封装openApi invoke-aliyun-api
import cloud from '@lafjs/cloud'
import * as querystring from 'querystring'
import * as crypto from 'crypto'
import * as assert from 'assert'
exports.main = async function (ctx: FunctionContext) {
assert.ok(ctx.body, 'empty body got')
const ApiEntryPoint = ctx.body.ApiEntryPoint
const AccessKeySecret = ctx.body.AccessKeySecret
const _params = Object.assign({
Format: 'json',
SignatureMethod: 'HMAC-SHA1',
SignatureNonce: crypto.randomUUID(),
SignatureVersion: '1.0',
Version: '2017-03-21',
Timestamp: (new Date()).toISOString()
}, ctx.body)
delete _params['ApiEntryPoint']
delete _params['AccessKeySecret']
console.log(_params)
const params = sortObjectKeys(_params)
params['Signature'] = specialEncode(sign(params, AccessKeySecret))
const query = querystring.stringify(params)
const url = `${ApiEntryPoint}?${query}`
console.log('=>', url)
try {
const r = await cloud.fetch(url)
return r.data
} catch (err) {
console.log(err.response.data)
throw err
}
}
function sign(raw_params: any, accessKeySecret: string) {
const params = encode(raw_params)
let strToSign = '';
for (let i in params) {
strToSign += i + '=' + params[i] + '&';
}
strToSign = strToSign.substr(0, strToSign.length - 1);
strToSign = "GET&" + encodeURIComponent('/') + '&' + encodeURIComponent(strToSign);
const ret = crypto.createHmac('sha1', accessKeySecret + '&')
.update(strToSign)
.digest('base64')
return ret
}
function sortObjectKeys(obj) {
const tmp = {};
Object.keys(obj).sort().forEach(k => tmp[k] = obj[k])
return tmp;
}
function encode(params) {
const obj = {}
for (let i in params) {
const str = encodeURIComponent(params[i])
obj[i] = specialEncode(str)
}
return obj
}
function specialEncode(encoded) {
if (encoded.indexOf('+')) {
encoded.replace("+", "%20");
} else if (encoded.indexOf('*')) {
encoded.replace("*", "%2A");
} else if (encoded.indexOf('%7E')) {
encoded.replace("%7E", "~");
}
return encoded
}
创建上传视频地址 create-video-upload-url
import cloud from '@lafjs/cloud'
const config = cloud.shared.get('aliyun.vod.config')
const accessKeyId = config.accessKeyId
const accessKeySecret = config.accessKeySecret
const api_entrypoint = config.api_entrypoint ?? 'https://vod.cn-shanghai.aliyuncs.com'
exports.main = async function (ctx: FunctionContext) {
const { filename, title} = ctx.body
const params = {
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
ApiEntryPoint: api_entrypoint,
Action: 'CreateUploadVideo',
Version: '2017-03-21',
FileName: filename,
Title: title
}
const data = await cloud.invoke('invoke-aliyun-api', { body: params })
console.log(data)
return {
error_code: '0',
error_message: 'success',
data: data
}
}
视频上传、转码回调 vod_callback
import cloud from '@lafjs/cloud'
const DB = cloud.database()
function CollNotEmpty(arg: any) {
return arg && Array.isArray(arg) && arg.length > 0
}
function getDuration(streamInfos: Record<string, any>[]){
console.log(`流信息 => `, streamInfos)
if (CollNotEmpty(streamInfos)) {
const {Duration} = streamInfos[0]
return Duration
}
return 0
}
function mustOk(
response: Record<string, any>,
callback?: (response: Record<string, any>) => any,
) {
if (response.ok) {
try {
if (callback) {
return callback(response);
}
return
} catch (e) {
console.error('错误: ', e);
throw e;
}
}
console.log('响应错误: ', response.code, response.error);
throw new Error('查询错误');
}
const TABLE_NAME = 'material'
exports.main = async function (ctx: any) {
const {body: {VideoId, StreamInfos, EventType}, query} = ctx
console.log(`回调处理, 类型: ${EventType} VideoId: ${VideoId}`)
if (EventType !== 'TranscodeComplete') {
return 'ok'
}
const response = await DB.collection(TABLE_NAME)
.where({"url": VideoId,})
.get()
const resData = mustOk(response, res => res.data)
console.log('查询结果: ', resData )
if (CollNotEmpty(resData)) {
const updateResponse = await DB.collection(TABLE_NAME)
.where({"url": VideoId,})
.update({
"video": {
"videoId": VideoId,
"duration": getDuration(StreamInfos),
},
"updateTime": Date.now(),
})
mustOk(updateResponse, res => {
console.log('更新成功, 补全duration', res)
})
} else {
const insertResponse = await DB.collection(TABLE_NAME)
.add({
"url": VideoId,
"video": {
"videoId": VideoId,
"duration": getDuration(StreamInfos),
},
"type": "2",
"delFlag": "0",
"createTime": Date.now(),
"updateTime": Date.now(),
});
mustOk(insertResponse, res => {
console.log(`添加临时数据成功`, res)
})
}
return 'ok'
}
素材信息表 material
{
"video": {
"mediaType": "video",
"outputType": "oss",
"status": "Uploading",
"title": "九龄.mp4",
"videoId": "54740f5035e94fefbda63172e3b515a2",
"format": "mp4",
"jobId": "54740f5035e94fefbda63172e3b515a202",
"playUrl": "https://outin-304e6bbe1f6b11ec936300163e1a625e.oss-cn-shanghai.aliyuncs.com/sv/96337a6-17c386e000e/96337a6-17c386e000e.mp4?Expires=1633037922&OSSAccessKeyId=LTAIVVfYx6D0HeL2&Signature=6ch5VFxTjSAJZKVKLAJR8OYUXog%3D",
"preprocessStatus": "UnPreprocess",
"file": {
"uid": "rc-upload-1633034250274-2"
},
"duration": 2333
},
"groupId": "6154a4eaf56ae0b2db2992ae",
"name": "琉璃",
"sort": 1,
"url": "54740f5035e94fefbda63172e3b515a2",
"ext": "九龄.mp4",
"createTime": 1633034340974,
"updateTime": 1633034340974,
"delFlag": "1",
"type": "2",
"updated_at": 1633681294142
}