fsd-vod 0.11.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +44 -2
- package/lib/index.js +64 -31
- package/package.json +5 -5
package/index.d.ts
CHANGED
|
@@ -2,6 +2,14 @@ import { Adapter } from 'fsd';
|
|
|
2
2
|
|
|
3
3
|
export interface VODAdapterOptions {
|
|
4
4
|
urlPrefix?: string;
|
|
5
|
+
/**
|
|
6
|
+
* 是否公开读,默认为false
|
|
7
|
+
*/
|
|
8
|
+
publicRead?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* 非公开读时,生成URL时的鉴权秘钥
|
|
11
|
+
*/
|
|
12
|
+
privateKey?: string;
|
|
5
13
|
accessKeyId: string;
|
|
6
14
|
accessKeySecret: string;
|
|
7
15
|
region?: string;
|
|
@@ -120,13 +128,47 @@ export interface UploadTokenWithAutoRefresh {
|
|
|
120
128
|
}
|
|
121
129
|
|
|
122
130
|
export default class VODAdpter extends Adapter<VODAdapterOptions> {
|
|
123
|
-
|
|
131
|
+
/**
|
|
132
|
+
* 创建上传凭证
|
|
133
|
+
* @param {string} videoId 视频ID
|
|
134
|
+
* @param {any} [meta] 文件元信息
|
|
135
|
+
* @param {number} [durationSeconds] 上传凭证有效期,单位秒, 默认 3600
|
|
136
|
+
*/
|
|
137
|
+
createUploadToken: (
|
|
138
|
+
videoId: string,
|
|
139
|
+
meta?: any,
|
|
140
|
+
durationSeconds?: number
|
|
141
|
+
) => Promise<UploadToken>;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* 创建带自动刷新的上传凭证
|
|
145
|
+
* @param {string} videoId 视频ID
|
|
146
|
+
* @param {any} [meta] 文件元信息
|
|
147
|
+
* @param {number} [durationSeconds] 上传凭证有效期,单位秒, 默认 3600
|
|
148
|
+
*/
|
|
124
149
|
createUploadTokenWithAutoRefresh: (
|
|
125
150
|
videoId: string,
|
|
126
|
-
meta?: any
|
|
151
|
+
meta?: any,
|
|
152
|
+
durationSeconds?: number
|
|
127
153
|
) => Promise<UploadTokenWithAutoRefresh>;
|
|
128
154
|
|
|
155
|
+
/**
|
|
156
|
+
* 获取视频信息
|
|
157
|
+
* @param {string} videoId 视频ID
|
|
158
|
+
*/
|
|
129
159
|
getVideoInfo(videoId: string): Promise<null | VideoInfo>;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 获取视频播放信息
|
|
163
|
+
* @param {string} videoId 视频ID
|
|
164
|
+
* @param {any} [options] 参数选项
|
|
165
|
+
*/
|
|
130
166
|
getMezzanineInfo(videoId: string, options?: any): Promise<null | MezzanineInfo>;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* 获取视频播放信息
|
|
170
|
+
* @param {string} videoId 视频ID
|
|
171
|
+
* @param {any} [options] 参数选项
|
|
172
|
+
*/
|
|
131
173
|
getPlayInfo(videoId: string, options?: any): Promise<null | PlayInfoResult>;
|
|
132
174
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
3
|
+
const crypto = require("crypto");
|
|
4
|
+
const stream_1 = require("stream");
|
|
5
|
+
const lru_cache_1 = require("lru-cache");
|
|
4
6
|
const Debugger = require("debug");
|
|
5
7
|
const RPC = require("@alicloud/pop-core");
|
|
6
|
-
const stream_1 = require("stream");
|
|
7
8
|
const akita_1 = require("akita");
|
|
8
9
|
const simple_oss_client_1 = require("fsd-oss/simple-oss-client");
|
|
9
10
|
const debug = Debugger('fsd-vod');
|
|
10
11
|
const client = akita_1.default.resolve('fsd-vod');
|
|
11
12
|
const CALLBACK_BODY = 'bucket=${bucket}&path=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}&format=${imageInfo.format}';
|
|
12
|
-
function
|
|
13
|
+
function parseToken(result) {
|
|
13
14
|
let UploadAddress = JSON.parse(Buffer.from(result.UploadAddress, 'base64').toString());
|
|
14
15
|
let UploadAuth = JSON.parse(Buffer.from(result.UploadAuth, 'base64').toString());
|
|
15
16
|
return {
|
|
@@ -24,6 +25,18 @@ function resultToCache(result) {
|
|
|
24
25
|
expiration: UploadAuth.Expiration * 950
|
|
25
26
|
};
|
|
26
27
|
}
|
|
28
|
+
function parseVideoId(id) {
|
|
29
|
+
if (id[0] === '/')
|
|
30
|
+
id = id.substring(1);
|
|
31
|
+
let path = '';
|
|
32
|
+
if (id.includes('#')) {
|
|
33
|
+
[id, path] = id.split('#');
|
|
34
|
+
}
|
|
35
|
+
return { id, path };
|
|
36
|
+
}
|
|
37
|
+
function md5(str) {
|
|
38
|
+
return crypto.createHash('md5').update(str).digest('hex');
|
|
39
|
+
}
|
|
27
40
|
class VODAdapter {
|
|
28
41
|
constructor(options) {
|
|
29
42
|
this.instanceOfFSDAdapter = true;
|
|
@@ -33,14 +46,16 @@ class VODAdapter {
|
|
|
33
46
|
throw new Error('option accessKeyId is required for fsd-vod');
|
|
34
47
|
if (!options.accessKeySecret)
|
|
35
48
|
throw new Error('option accessKeySecret is required for fsd-vod');
|
|
49
|
+
if (!options.publicRead && !options.privateKey)
|
|
50
|
+
throw new Error('option privateKey is required when publicRead is false');
|
|
36
51
|
this._options = options;
|
|
37
|
-
this._authCache = new LRUCache({
|
|
52
|
+
this._authCache = new lru_cache_1.LRUCache({
|
|
38
53
|
max: 1000,
|
|
39
|
-
|
|
54
|
+
ttl: 1800000
|
|
40
55
|
});
|
|
41
|
-
this._videoCache = new LRUCache({
|
|
56
|
+
this._videoCache = new lru_cache_1.LRUCache({
|
|
42
57
|
max: 1000,
|
|
43
|
-
|
|
58
|
+
ttl: 60000
|
|
44
59
|
});
|
|
45
60
|
this._rpc = new RPC({
|
|
46
61
|
accessKeyId: options.accessKeyId,
|
|
@@ -73,24 +88,23 @@ class VODAdapter {
|
|
|
73
88
|
let result = await this._rpc.request('CreateUploadVideo', params, { method: 'POST' });
|
|
74
89
|
if (result.Message)
|
|
75
90
|
throw new Error(result.Message);
|
|
76
|
-
let token =
|
|
77
|
-
this._authCache.set(result.VideoId, token, token.expiration);
|
|
78
|
-
return result.VideoId
|
|
91
|
+
let token = parseToken(result);
|
|
92
|
+
this._authCache.set(result.VideoId, token, { ttl: token.expiration });
|
|
93
|
+
return `/${result.VideoId}#${token.path}`;
|
|
79
94
|
};
|
|
80
|
-
this.createUploadToken = async (videoId, meta) => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
let token = this._authCache.get(videoId);
|
|
95
|
+
this.createUploadToken = async (videoId, meta, durationSeconds) => {
|
|
96
|
+
let vid = parseVideoId(videoId);
|
|
97
|
+
let token = this._authCache.get(vid.id);
|
|
84
98
|
debug('getAuth', videoId, token);
|
|
85
99
|
if (!token) {
|
|
86
100
|
let params = {
|
|
87
|
-
VideoId:
|
|
101
|
+
VideoId: vid.id
|
|
88
102
|
};
|
|
89
103
|
let result = await this._rpc.request('RefreshUploadVideo', params, { method: 'POST' });
|
|
90
104
|
if (result.Message)
|
|
91
105
|
throw new Error(result.Message);
|
|
92
|
-
token =
|
|
93
|
-
this._authCache.set(
|
|
106
|
+
token = parseToken(result);
|
|
107
|
+
this._authCache.set(vid.id, token, { ttl: token.expiration });
|
|
94
108
|
}
|
|
95
109
|
if (options.callbackUrl && meta) {
|
|
96
110
|
token.callback = {
|
|
@@ -118,18 +132,17 @@ class VODAdapter {
|
|
|
118
132
|
};
|
|
119
133
|
}
|
|
120
134
|
async getVideoInfo(videoId) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
let cache = this._videoCache.get(videoId);
|
|
135
|
+
let vid = parseVideoId(videoId);
|
|
136
|
+
let cache = this._videoCache.get(vid.id);
|
|
124
137
|
if (cache)
|
|
125
138
|
return cache;
|
|
126
139
|
let params = {
|
|
127
|
-
VideoId:
|
|
140
|
+
VideoId: vid.id
|
|
128
141
|
};
|
|
129
142
|
try {
|
|
130
143
|
let result = await this._rpc.request('GetVideoInfo', params, { method: 'POST' });
|
|
131
144
|
if (result.Video) {
|
|
132
|
-
this._videoCache.set(
|
|
145
|
+
this._videoCache.set(vid.id, result.Video);
|
|
133
146
|
return result.Video;
|
|
134
147
|
}
|
|
135
148
|
}
|
|
@@ -137,10 +150,9 @@ class VODAdapter {
|
|
|
137
150
|
return null;
|
|
138
151
|
}
|
|
139
152
|
async getMezzanineInfo(videoId, options) {
|
|
140
|
-
|
|
141
|
-
videoId = videoId.substring(1);
|
|
153
|
+
let vid = parseVideoId(videoId);
|
|
142
154
|
let params = Object.assign({
|
|
143
|
-
VideoId:
|
|
155
|
+
VideoId: vid.id,
|
|
144
156
|
OutputType: 'cdn'
|
|
145
157
|
}, options || {});
|
|
146
158
|
try {
|
|
@@ -153,10 +165,9 @@ class VODAdapter {
|
|
|
153
165
|
return null;
|
|
154
166
|
}
|
|
155
167
|
async getPlayInfo(videoId, options) {
|
|
156
|
-
|
|
157
|
-
videoId = videoId.substring(1);
|
|
168
|
+
let vid = parseVideoId(videoId);
|
|
158
169
|
let params = Object.assign({
|
|
159
|
-
VideoId:
|
|
170
|
+
VideoId: vid.id
|
|
160
171
|
}, options || {});
|
|
161
172
|
return await this._rpc.request('GetPlayInfo', params, { method: 'POST' });
|
|
162
173
|
}
|
|
@@ -172,6 +183,7 @@ class VODAdapter {
|
|
|
172
183
|
async createReadStream(videoId, options) {
|
|
173
184
|
debug('createReadStream %s options: %o', videoId, options);
|
|
174
185
|
let url = await this.createUrl(videoId);
|
|
186
|
+
console.log('url', url);
|
|
175
187
|
let headers = {};
|
|
176
188
|
if (options) {
|
|
177
189
|
let start = options.start || 0;
|
|
@@ -239,6 +251,26 @@ class VODAdapter {
|
|
|
239
251
|
}
|
|
240
252
|
async createUrl(videoId, options) {
|
|
241
253
|
debug('createUrl %s', videoId);
|
|
254
|
+
options = options || {};
|
|
255
|
+
let vid = parseVideoId(videoId);
|
|
256
|
+
let path = options.path || vid.path;
|
|
257
|
+
if (path && this._options.publicRead) {
|
|
258
|
+
if (/^https?\:\/\//.test(path))
|
|
259
|
+
return path;
|
|
260
|
+
return `${this._options.urlPrefix || ''}${path}`;
|
|
261
|
+
}
|
|
262
|
+
if (path) {
|
|
263
|
+
let urlPrefix = this._options.urlPrefix || '';
|
|
264
|
+
if (/^https?\:\/\//.test(path)) {
|
|
265
|
+
let url = new URL(path);
|
|
266
|
+
path = url.pathname;
|
|
267
|
+
urlPrefix = url.origin;
|
|
268
|
+
}
|
|
269
|
+
let timestamp = parseInt((Date.now() / 1000));
|
|
270
|
+
let string = `${path}-${timestamp}-0-0-${this._options.privateKey}`;
|
|
271
|
+
let hash = md5(string);
|
|
272
|
+
return `${urlPrefix}${path}?auth_key=${timestamp}-0-0-${hash}`;
|
|
273
|
+
}
|
|
242
274
|
let info = await this.getMezzanineInfo(videoId, options);
|
|
243
275
|
if (info)
|
|
244
276
|
return info.FileURL;
|
|
@@ -246,14 +278,15 @@ class VODAdapter {
|
|
|
246
278
|
}
|
|
247
279
|
async unlink(videoId) {
|
|
248
280
|
debug('unlink %s', videoId);
|
|
249
|
-
|
|
250
|
-
videoId = videoId.substring(1);
|
|
281
|
+
let vid = parseVideoId(videoId);
|
|
251
282
|
let params = {
|
|
252
|
-
VideoIds:
|
|
283
|
+
VideoIds: vid.id
|
|
253
284
|
};
|
|
254
285
|
let result = await this._rpc.request('DeleteVideo', params, { method: 'POST' });
|
|
255
286
|
if (result.Message)
|
|
256
287
|
throw new Error(result.Message);
|
|
288
|
+
this._videoCache.delete(vid.id);
|
|
289
|
+
this._authCache.delete(vid.id);
|
|
257
290
|
}
|
|
258
291
|
async exists(videoId) {
|
|
259
292
|
return !!(await this.getVideoInfo(videoId));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fsd-vod",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Aliyun OSS adapter for fsd",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
"author": "Liang <liang@miaomo.cc> (https://github.com/liangxingchen)",
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@alicloud/pop-core": "^1.7.
|
|
15
|
+
"@alicloud/pop-core": "^1.7.13",
|
|
16
16
|
"akita": "^1.0.4",
|
|
17
17
|
"debug": "^4.3.4",
|
|
18
|
-
"fsd-oss": "^0.
|
|
19
|
-
"lru-cache": "^
|
|
18
|
+
"fsd-oss": "^0.13.0",
|
|
19
|
+
"lru-cache": "^9.1.1"
|
|
20
20
|
},
|
|
21
|
-
"gitHead": "
|
|
21
|
+
"gitHead": "1548128573c0fd22977706a6704029ec3ca3bab6"
|
|
22
22
|
}
|