info
This commit is contained in:
+89
@@ -0,0 +1,89 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const safeRequire = require('./safe-require')
|
||||
const createConfig = safeRequire('uni-config-center')
|
||||
const shareConfig = createConfig({
|
||||
pluginId: 'uni-media-library'
|
||||
})
|
||||
const config = shareConfig.config()
|
||||
|
||||
const internalImageLibrary = [
|
||||
{
|
||||
provider: "unsplash",
|
||||
name: "Unsplash",
|
||||
website: 'https://unsplash.com',
|
||||
requiredFields: ["appId", "accessKey", 'secretKey'],
|
||||
}, {
|
||||
provider: "giphy",
|
||||
name: "Giphy",
|
||||
website: 'https://giphy.com',
|
||||
requiredFields: ["apiKey"],
|
||||
}, {
|
||||
provider: "pexels",
|
||||
name: "Pexels",
|
||||
website: 'https://www.pexels.com',
|
||||
requiredFields: ["apiKey"],
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
function getProviders () {
|
||||
const imageLibraryProviders = []
|
||||
const internalLibraryProviders = internalImageLibrary.map(item => item.provider)
|
||||
const imageLibraryProvidersConfig = config.imageLibraryProviders || {}
|
||||
|
||||
for (const provider of internalLibraryProviders) {
|
||||
const library = internalImageLibrary.find(item => item.provider === provider)
|
||||
const libraryConfig = imageLibraryProvidersConfig[provider]
|
||||
|
||||
if (!libraryConfig) continue
|
||||
|
||||
if (
|
||||
provider.requiredFields &&
|
||||
provider.requiredFields.some(field => !libraryConfig[field])
|
||||
) {
|
||||
console.warn(`The provider "${provider}" requires the following fields: ${provider.requiredFields.join(', ')}`)
|
||||
continue
|
||||
}
|
||||
|
||||
imageLibraryProviders.push({
|
||||
provider: library.provider,
|
||||
name: library.name,
|
||||
website: library.website,
|
||||
internal: true,
|
||||
entryFilePath: path.resolve(__dirname, '../internal-image-library', provider, 'index.js'),
|
||||
options: libraryConfig
|
||||
})
|
||||
}
|
||||
|
||||
if (imageLibraryProvidersConfig.others && imageLibraryProvidersConfig.others.length) {
|
||||
for (const library of imageLibraryProvidersConfig.others) {
|
||||
if (internalLibraryProviders.includes(library.provider)) {
|
||||
console.warn(`The provider "${library.provider}" is an internal provider, please do not use it in "imageLibraryProvidersConfig.others"`)
|
||||
continue
|
||||
}
|
||||
|
||||
const entryFilePath = shareConfig.resolve(`image-library/${library.provider}/index.js`)
|
||||
if (!fs.existsSync(entryFilePath)) {
|
||||
console.warn('The provider entry file does not exist: ' + entryFilePath)
|
||||
continue
|
||||
}
|
||||
|
||||
imageLibraryProviders.push({
|
||||
provider: library.provider,
|
||||
name: library.name,
|
||||
website: library.website,
|
||||
internal: false,
|
||||
entryFilePath: entryFilePath,
|
||||
options: library.options
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return imageLibraryProviders
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
...config,
|
||||
imageLibraryProviders: getProviders()
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
module.exports = function safeRequire(module) {
|
||||
try {
|
||||
return require(module)
|
||||
} catch (e) {
|
||||
if (e.code === 'MODULE_NOT_FOUND') {
|
||||
throw new Error(`${module} 公共模块不存在,请在 uni-media-library-co 云对象目录右键“管理公共模块或扩展库依赖”添加 ${module} 模块`)
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
async function deleteMedia (params) {
|
||||
const {mediaIds = [], deleteOriginalFile = true} = params
|
||||
const db = uniCloud.database()
|
||||
|
||||
if (mediaIds.length <= 0) {
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
||||
|
||||
const mediaList = await db.collection('uni-media-library').where({
|
||||
_id: db.command.in(mediaIds)
|
||||
}).get()
|
||||
|
||||
if (!mediaList.data || mediaList.data.length <= 0) {
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
||||
|
||||
const mediaFileIds = mediaList.data.filter(item => item.src).map(item => item.src)
|
||||
const coverFileIds = mediaList.data.filter(item => item.type === 'video' && item.cover).map(item => item.cover)
|
||||
|
||||
try {
|
||||
await Promise.all([
|
||||
// 删除云数据库中的记录
|
||||
db.collection('uni-media-library').where({
|
||||
_id: db.command.in(mediaIds)
|
||||
}).remove(),
|
||||
// 删除云存储中的文件
|
||||
deleteOriginalFile && mediaFileIds.length && uniCloud.deleteFile({
|
||||
fileList: mediaFileIds
|
||||
}),
|
||||
// 删除云存储中的文件
|
||||
deleteOriginalFile && coverFileIds.length && uniCloud.deleteFile({
|
||||
fileList: coverFileIds
|
||||
})
|
||||
])
|
||||
} catch (e) {
|
||||
console.log('删除云存储图片失败', e)
|
||||
}
|
||||
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = deleteMedia
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
const config = require('../../common/config')
|
||||
|
||||
async function getProviders() {
|
||||
return {
|
||||
errCode: 0,
|
||||
data: config.imageLibraryProviders.map(item => ({
|
||||
provider: item.provider,
|
||||
name: item.name,
|
||||
website: item.website,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = getProviders
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
const fs = require('fs')
|
||||
// const stream = require("stream")
|
||||
const config = require('../../common/config')
|
||||
|
||||
module.exports = async function (params) {
|
||||
const {url = '', id, provider = ''} = params
|
||||
const cloudInfo = uniCloud.getCloudInfos()[0]
|
||||
const isAliyun = cloudInfo.provider === 'aliyun'
|
||||
const imageLibraryProviders = config.imageLibraryProviders || []
|
||||
const providerConfig = imageLibraryProviders.find(item => item.provider === provider)
|
||||
|
||||
let imageDetail = {
|
||||
fileType: 'jpeg'
|
||||
}
|
||||
|
||||
if (id && providerConfig) {
|
||||
const entry = require(providerConfig.entryFilePath)
|
||||
try {
|
||||
const detail = await entry.detail({
|
||||
id
|
||||
}, providerConfig.options)
|
||||
imageDetail = Object.assign(imageDetail, detail)
|
||||
} catch (e) {
|
||||
return {
|
||||
errCode: 500,
|
||||
errMsg: e.message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const response = await uniCloud.httpclient.request(url, {
|
||||
streaming: !isAliyun,
|
||||
timeout: 600000
|
||||
})
|
||||
|
||||
if (response.status !== 200) {
|
||||
return {
|
||||
errCode: response.status,
|
||||
errMsg: '上传失败'
|
||||
}
|
||||
}
|
||||
|
||||
// 未获取到文件大小时,尝试从响应头中获取
|
||||
if (!imageDetail.size && response.headers['content-length']) {
|
||||
imageDetail.size = Number(response.headers['content-length'])
|
||||
}
|
||||
|
||||
const res = await uniCloud.uploadFile({
|
||||
cloudPath: `uni-media-library/${Date.now()}.${imageDetail.fileType}`,
|
||||
fileContent: isAliyun ? response.data: response.res
|
||||
})
|
||||
|
||||
return {
|
||||
errCode: 0,
|
||||
data: {
|
||||
fileID: res.fileID,
|
||||
detail: imageDetail
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
const config = require('../../common/config')
|
||||
|
||||
module.exports = async function (params) {
|
||||
const {keyword = '', page = 1, pageSize = 20, provider = ''} = params
|
||||
const imageLibraryProviders = config.imageLibraryProviders || []
|
||||
const providerConfig = imageLibraryProviders.find(item => item.provider === provider)
|
||||
|
||||
if (!providerConfig) {
|
||||
return {
|
||||
errCode: 400,
|
||||
errMsg: `Provider ${provider} is not found`
|
||||
}
|
||||
}
|
||||
|
||||
const entry = require(providerConfig.entryFilePath)
|
||||
|
||||
try {
|
||||
const res = await entry.search({
|
||||
keyword,
|
||||
page,
|
||||
pageSize
|
||||
}, providerConfig.options)
|
||||
return {
|
||||
errCode: 0,
|
||||
data: res
|
||||
}
|
||||
} catch (e) {
|
||||
return {
|
||||
errCode: 500,
|
||||
errMsg: e.message
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
report: require('./report'),
|
||||
deleteMedia: require('./delete-media'),
|
||||
getImageLibraryProviders: require('./image-library/get-providers'),
|
||||
searchImageLibrary: require('./image-library/search'),
|
||||
uploadImage: require('./image-library/internal-uploader'),
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
const db = uniCloud.database()
|
||||
|
||||
async function report (params) {
|
||||
const {
|
||||
src,
|
||||
cover,
|
||||
type,
|
||||
originalName,
|
||||
fileType,
|
||||
size,
|
||||
resolution = {},
|
||||
duration,
|
||||
uploadUser,
|
||||
description,
|
||||
alt
|
||||
} = params
|
||||
|
||||
await db.collection('uni-media-library').add({
|
||||
src,
|
||||
cover,
|
||||
type,
|
||||
originalName,
|
||||
fileType,
|
||||
size,
|
||||
resolution,
|
||||
duration,
|
||||
uploadUser,
|
||||
description,
|
||||
alt,
|
||||
createDate: Date.now()
|
||||
})
|
||||
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = report
|
||||
+1
@@ -0,0 +1 @@
|
||||
module.exports = require('./functions')
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
const API_URL = 'https://api.giphy.com/v1'
|
||||
|
||||
exports.search = async function (params = {}, config = {}){
|
||||
const {keyword, page = 1, pageSize} = params
|
||||
const {apiKey} = config
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error('Giphy provider is not enabled')
|
||||
}
|
||||
|
||||
if (pageSize > 50) {
|
||||
throw new Error('pageSize should not be greater than 50')
|
||||
}
|
||||
|
||||
const url = `${API_URL}/gifs/search?api_key=${apiKey}`
|
||||
const res = await uniCloud.request({
|
||||
url,
|
||||
data: {
|
||||
q: keyword,
|
||||
offset: (page - 1) * pageSize,
|
||||
limit: pageSize
|
||||
}
|
||||
})
|
||||
|
||||
const {statusCode, data} = res
|
||||
|
||||
if (statusCode !== 200) {
|
||||
console.error(statusCode, res.data)
|
||||
throw new Error(`statusCode: ${statusCode}`)
|
||||
}
|
||||
|
||||
if (data.meta && data.meta.status !== 200) {
|
||||
console.error(data.meta.status, data.meta.msg)
|
||||
throw new Error(`status: ${data.meta.status}, errMsg: ${data.meta.msg}`)
|
||||
}
|
||||
|
||||
if (!data.data) return []
|
||||
|
||||
return data.data.map(item => {
|
||||
return {
|
||||
id: item.id,
|
||||
url: item.images.original.webp,
|
||||
thumbUrl: item.images.preview_gif.url,
|
||||
width: Number(item.images.original.width),
|
||||
height: Number(item.images.original.height),
|
||||
size: Number(item.images.original.webp_size),
|
||||
description: item.title,
|
||||
alt: item.alt_text,
|
||||
originalName: item.slug || item.id || "'",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
exports.detail = async function (params = {}, config = {}) {
|
||||
const {id} = params
|
||||
const {apiKey} = config
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error('Giphy provider is not enabled')
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
throw new Error('Giphy id is required')
|
||||
}
|
||||
|
||||
const url = `${API_URL}/gifs/${id}?api_key=${apiKey}`
|
||||
const res = await uniCloud.request({
|
||||
url
|
||||
})
|
||||
|
||||
const {statusCode, data} = res
|
||||
|
||||
if (statusCode !== 200) {
|
||||
console.error(statusCode, data)
|
||||
throw new Error(`statusCode: ${statusCode}`)
|
||||
}
|
||||
|
||||
if (data.meta && data.meta.status !== 200) {
|
||||
console.error(data.meta.status, data.meta.msg)
|
||||
throw new Error(`status: ${data.meta.status}, errMsg: ${data.meta.msg}`)
|
||||
}
|
||||
|
||||
const result = data.data
|
||||
|
||||
return {
|
||||
id: result.id,
|
||||
url: result.images.original.webp,
|
||||
thumbUrl: result.images.preview_gif.url,
|
||||
width: Number(result.images.original.width),
|
||||
height: Number(result.images.original.height),
|
||||
size: Number(result.images.original.webp_size),
|
||||
description: result.title,
|
||||
alt: result.alt_text,
|
||||
originalName: result.slug || result.id || "",
|
||||
fileType: 'webp'
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
const API_URL = 'https://api.pexels.com/v1'
|
||||
|
||||
exports.search = async function (params = {}, config = {}){
|
||||
const {keyword, page, pageSize} = params
|
||||
const {apiKey} = config
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error('Pexels provider is not enabled')
|
||||
}
|
||||
|
||||
const url = `${API_URL}/search`
|
||||
const res = await uniCloud.request({
|
||||
url,
|
||||
data: {
|
||||
query: keyword,
|
||||
page,
|
||||
per_page: pageSize
|
||||
},
|
||||
header: {
|
||||
Authorization: `${apiKey}`
|
||||
}
|
||||
})
|
||||
|
||||
if (res.statusCode !== 200) {
|
||||
console.error(res.statusCode, res.data)
|
||||
throw new Error(`statusCode: ${res.statusCode}`)
|
||||
}
|
||||
|
||||
return res.data.photos.map(item => {
|
||||
return {
|
||||
id: item.id,
|
||||
url: item.src.original,
|
||||
thumbUrl: item.src.tiny,
|
||||
width: item.width,
|
||||
height: item.height,
|
||||
description: item.description,
|
||||
alt: item.alt,
|
||||
originalName: item.slug || item.id || "'",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
exports.detail = async function (params = {}, config = {}) {
|
||||
const {id} = params
|
||||
const {apiKey} = config
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error('Pexels provider is not enabled')
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
throw new Error('Pexels id is required')
|
||||
}
|
||||
|
||||
const url = `${API_URL}/photos/${id}`
|
||||
const res = await uniCloud.request({
|
||||
url,
|
||||
header: {
|
||||
Authorization: `${apiKey}`
|
||||
}
|
||||
})
|
||||
|
||||
if (res.statusCode !== 200) {
|
||||
console.error(res.statusCode, res.data)
|
||||
throw new Error(`statusCode: ${res.statusCode}`)
|
||||
}
|
||||
|
||||
const {data} = res
|
||||
|
||||
const filename = data.src.original.split('/').pop()
|
||||
const [name, ext = 'jpeg'] = filename.split('.')
|
||||
|
||||
return {
|
||||
id: data.id,
|
||||
url: data.src.original,
|
||||
thumbUrl: data.src.tiny,
|
||||
width: data.width,
|
||||
height: data.height,
|
||||
description: data.description,
|
||||
alt: data.alt,
|
||||
originalName: filename || "",
|
||||
fileType: ext
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
const API_URL = 'https://api.unsplash.com'
|
||||
|
||||
exports.search = async function (params = {}, config = {}){
|
||||
const {keyword, page, pageSize} = params
|
||||
const {appId, accessKey, secretKey} = config
|
||||
|
||||
if (!appId || !accessKey || !secretKey) {
|
||||
throw new Error('Unsplash provider is not enabled')
|
||||
}
|
||||
|
||||
const url = `${API_URL}/search/photos`
|
||||
const res = await uniCloud.request({
|
||||
url,
|
||||
data: {
|
||||
query: keyword,
|
||||
page,
|
||||
per_page: pageSize
|
||||
},
|
||||
header: {
|
||||
Authorization: `Client-ID ${accessKey}`
|
||||
}
|
||||
})
|
||||
|
||||
if (res.statusCode !== 200) {
|
||||
console.error(res.statusCode, res.data)
|
||||
throw new Error(`statusCode: ${res.statusCode}`)
|
||||
}
|
||||
|
||||
return res.data.results.map(item => {
|
||||
return {
|
||||
id: item.id,
|
||||
url: item.urls.raw,
|
||||
thumbUrl: item.urls.thumb,
|
||||
width: item.width,
|
||||
height: item.height,
|
||||
description: item.description,
|
||||
alt: item.alt_description,
|
||||
originalName: item.slug || item.id || "'",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
exports.detail = async function (params = {}, config = {}) {
|
||||
const {id} = params
|
||||
const {appId, accessKey, secretKey} = config
|
||||
|
||||
if (!appId || !accessKey || !secretKey) {
|
||||
throw new Error('Unsplash provider is not enabled')
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
throw new Error('Unsplash id is required')
|
||||
}
|
||||
|
||||
const url = `${API_URL}/photos/${id}`
|
||||
const res = await uniCloud.request({
|
||||
url,
|
||||
header: {
|
||||
Authorization: `Client-ID ${accessKey}`
|
||||
}
|
||||
})
|
||||
|
||||
if (res.statusCode !== 200) {
|
||||
console.error(res.statusCode, res.data)
|
||||
throw new Error(`statusCode: ${res.statusCode}`)
|
||||
}
|
||||
|
||||
const {data} = res
|
||||
|
||||
|
||||
return {
|
||||
id: data.id,
|
||||
url: data.urls.raw,
|
||||
thumbUrl: data.urls.thumb,
|
||||
width: data.width,
|
||||
height: data.height,
|
||||
description: data.description,
|
||||
alt: data.alt_description,
|
||||
originalName: data.slug || data.id || "",
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "uni-media-library-co",
|
||||
"dependencies": {
|
||||
"uni-config-center": "file:..\/..\/..\/..\/uni-config-center\/uniCloud\/cloudfunctions\/common\/uni-config-center"
|
||||
},
|
||||
"extensions": {
|
||||
"uni-cloud-jql": {}
|
||||
},
|
||||
"origin-plugin-dev-name": "uni-media-library",
|
||||
"origin-plugin-version": "1.1.1",
|
||||
"plugin-dev-name": "uni-media-library",
|
||||
"plugin-version": "1.1.1"
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
const createConfig = safeRequire('uni-config-center')
|
||||
const config = createConfig({
|
||||
pluginId: 'uni-media-library'
|
||||
}).config()
|
||||
|
||||
const coverCropRule = {
|
||||
aliyun: {
|
||||
listCover: 'x-oss-process=image/auto-orient,1/resize,m_fill,w_150,h_150/quality,q_80',
|
||||
detailCover: 'x-oss-process=image/auto-orient,1/resize,m_fill,w_300,h_180/quality,q_80'
|
||||
},
|
||||
tencent: {
|
||||
listCover: 'imageMogr2/thumbnail/!150x150r/quality/80',
|
||||
detailCover: 'imageMogr2/thumbnail/!300x180r/quality/80',
|
||||
}
|
||||
}
|
||||
|
||||
function safeRequire(module) {
|
||||
try {
|
||||
return require(module)
|
||||
} catch (e) {
|
||||
if (e.code === 'MODULE_NOT_FOUND') {
|
||||
throw new Error(`${module} 公共模块不存在,请在 uniCloud/database 目录右击"配置schema扩展公共模块"添加 ${module} 模块`)
|
||||
}
|
||||
}
|
||||
}
|
||||
function getImageCropRule (url) {
|
||||
if (/^cloud:\/\/env-/.test(url)) {
|
||||
return coverCropRule.aliyun
|
||||
}
|
||||
|
||||
if (/^cloud:\/\//.test(url)) {
|
||||
return coverCropRule.tencent
|
||||
}
|
||||
|
||||
return coverCropRule.aliyun
|
||||
}
|
||||
|
||||
function getThumbRules (assetsUrl) {
|
||||
const cropMediaAssetsConfig = config.cropMediaAssets || false
|
||||
|
||||
if (!cropMediaAssetsConfig) return {}
|
||||
|
||||
return getImageCropRule(assetsUrl)
|
||||
}
|
||||
function cropImage (result) {
|
||||
if (result && result.data && result.data.length > 0) {
|
||||
result.data.forEach(item => {
|
||||
item.thumbRules = {}
|
||||
|
||||
if (item.type === 'video') {
|
||||
item.thumbRules = getThumbRules(item.cover)
|
||||
} else {
|
||||
item.thumbRules = getThumbRules(item.src)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
trigger: {
|
||||
afterRead: ({result}) => {
|
||||
// 处理缩略图
|
||||
try {
|
||||
cropImage(result)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
throw new Error("媒体资源应用缩略图规则失败,查看云函数日志获取详细错误")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"bsonType": "object",
|
||||
"required": [],
|
||||
"permission": {
|
||||
"read": true,
|
||||
"create": true,
|
||||
"update": true,
|
||||
"delete": true
|
||||
},
|
||||
"properties": {
|
||||
"_id": {
|
||||
"description": "ID,系统自动生成"
|
||||
},
|
||||
"src": {
|
||||
"bsonType": "string",
|
||||
"description": "媒体资源地址"
|
||||
},
|
||||
"cover": {
|
||||
"bsonType": "string",
|
||||
"description": "媒体资源封面地址;仅视频使用"
|
||||
},
|
||||
"type": {
|
||||
"bsonType": "string",
|
||||
"description": "媒体资源类型",
|
||||
"enum": ["image", "video"]
|
||||
},
|
||||
"description": {
|
||||
"bsonType": "string",
|
||||
"description": "媒体资源描述"
|
||||
},
|
||||
"alt": {
|
||||
"bsonType": "string",
|
||||
"description": "媒体资源alt替代文字"
|
||||
},
|
||||
"originalName": {
|
||||
"bsonType": "string",
|
||||
"description": "媒体资源原始文件名"
|
||||
},
|
||||
"fileType": {
|
||||
"bsonType": "string",
|
||||
"description": "媒体资源文件类型"
|
||||
},
|
||||
"size": {
|
||||
"bsonType": "number",
|
||||
"description": "媒体资源大小"
|
||||
},
|
||||
"resolution": {
|
||||
"bsonType": "object",
|
||||
"description": "媒体资源分辨率"
|
||||
},
|
||||
"duration": {
|
||||
"bsonType": "number",
|
||||
"description": "媒体资源时长"
|
||||
},
|
||||
"uploadUser": {
|
||||
"bsonType": "string",
|
||||
"description": "媒体资源上传用户",
|
||||
"foreignKey": "uni-id-users._id"
|
||||
},
|
||||
"createDate": {
|
||||
"bsonType": "timestamp",
|
||||
"description": "媒体资源创建时间"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user