This commit is contained in:
c
2025-03-12 20:11:03 +08:00
commit e65b262527
1179 changed files with 148205 additions and 0 deletions
@@ -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()
}
@@ -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} 模块`)
}
}
}
@@ -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
@@ -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
@@ -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
}
}
}
@@ -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
}
}
}
@@ -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'),
}
@@ -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
@@ -0,0 +1 @@
module.exports = require('./functions')
@@ -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'
}
}
@@ -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
}
}
@@ -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 || "",
}
}
@@ -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": "媒体资源创建时间"
}
}
}