调整创建直播流方法名称,新增查询直播流信息方法

This commit is contained in:
lxy 2025-07-14 16:45:22 +08:00
parent a71d5d339f
commit 304c2f6ac2
8 changed files with 612 additions and 370 deletions

View File

@ -1,4 +1,4 @@
import { QiniuZone } from '../../types/Qiniu';
import { QiniuLiveStreamInfo, QiniuZone } from '../../types/Qiniu';
export declare class QiniuCloudInstance {
private accessKey;
private secretKey;
@ -17,40 +17,6 @@ export declare class QiniuCloudInstance {
uploadHost: string;
bucket: string;
};
/**
* token
* @param method
* @param path
* @param host
* @param rawQuery
* @param contentType
* @param bodyStr
* @returns
*/
getLiveToken(method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, host: string, rawQuery?: string, contentType?: string, bodyStr?: string): string;
/**
*
* @param hub
* @param streamTitle
* @param host
* @param publishDomain
* @param playDomainType
* @param playDomain
* @param expireAt
* @param publishSecurity
* @param publishKey
* @param playKey
* @returns
*/
getLiveStream(hub: string, streamTitle: string, host: string, publishDomain: string, playDomainType: 'rtmp' | 'hls' | 'flv', playDomain: string, expireAt: number, publishSecurity: 'none' | 'static' | 'expiry' | 'expiry_sk', publishKey: string, playKey: string): Promise<{
streamTitle: string;
hub: string;
rtmpPushUrl: string;
playUrl: string;
pcPushUrl: string;
streamKey: string;
expireAt: number;
}>;
/**
* https://developer.qiniu.com/kodo/1308/stat
* GET方法nodejs-sdk里看是POST方法
@ -95,6 +61,40 @@ export declare class QiniuCloudInstance {
}>;
moveKodoFile(srcBucket: string, zone: QiniuZone, srcKey: string, destBucket: string, destKey: string, force?: boolean, mockData?: any): Promise<void>;
copyKodoFile(srcBucket: string, zone: QiniuZone, srcKey: string, destBucket: string, destKey: string, force?: boolean, mockData?: any): Promise<void>;
/**
* token
* @param method
* @param path
* @param host
* @param rawQuery
* @param contentType
* @param bodyStr
* @returns
*/
getLiveToken(method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, host: string, rawQuery?: string, contentType?: string, bodyStr?: string): string;
/**
*
* @param hub
* @param streamTitle
* @param host
* @param publishDomain
* @param playDomainType
* @param playDomain
* @param expireAt
* @param publishSecurity
* @param publishKey
* @param playKey
* @returns
*/
createLiveStream(hub: string, streamTitle: string, host: string, publishDomain: string, playDomainType: 'rtmp' | 'hls' | 'flv', playDomain: string, expireAt: number, publishSecurity: 'none' | 'static' | 'expiry' | 'expiry_sk', publishKey: string, playKey: string): Promise<{
streamTitle: string;
hub: string;
rtmpPushUrl: string;
playUrl: string;
pcPushUrl: string;
streamKey: string;
expireAt: number;
}>;
/**
*
* @param hub
@ -136,10 +136,21 @@ export declare class QiniuCloudInstance {
* @param prefix
* @param limit
* @param marker
* @returns
* @returns
*/
getLiveStreamList(hub: string, host: string, liveOnly?: boolean, prefix?: string, limit?: number, //取值范围0~5000
marker?: string): Promise<any>;
marker?: string): Promise<{
streamTitles: string[];
marker: string;
}>;
/**
*
* @param hub
* @param streamTitle
* @param host
* @returns
*/
getLiveStreamInfo(hub: string, streamTitle: string, host: string): Promise<QiniuLiveStreamInfo>;
/**
* 访
* @param path

View File

@ -135,90 +135,6 @@ export class QiniuCloudInstance {
throw err;
}
}
/**
* 计算直播需要的token
* @param method
* @param path
* @param host
* @param rawQuery
* @param contentType
* @param bodyStr
* @returns
*/
getLiveToken(method, path, host, rawQuery, contentType, bodyStr) {
// 1. 添加 Path
let data = `${method} ${path}`;
if (rawQuery) {
data += `?${rawQuery}`;
}
data += `\nHost: ${host}`;
if (contentType) {
data += `\nContent-Type: ${contentType}`;
}
data += '\n\n';
if (bodyStr &&
contentType &&
contentType !== 'application/octet-stream') {
data += bodyStr;
}
const sign = this.hmacSha1(data, this.secretKey);
const encodedSign = this.base64ToUrlSafe(sign);
const toke = 'Qiniu ' + this.accessKey + ':' + encodedSign;
return toke;
}
/**
* 创建直播流
* @param hub
* @param streamTitle
* @param host
* @param publishDomain
* @param playDomainType
* @param playDomain
* @param expireAt
* @param publishSecurity
* @param publishKey
* @param playKey
* @returns
*/
async getLiveStream(hub, streamTitle, host, publishDomain, playDomainType, playDomain, expireAt, publishSecurity, publishKey, playKey) {
// 七牛创建直播流接口路径
const path = `/v2/hubs/${hub}/streams`;
// 如果用户没给streamTitle那么随机生成一个
let key = streamTitle;
if (!key) {
key = `class${new Date().getTime()}`;
}
const bodyStr = JSON.stringify({
key,
});
const contentType = 'application/json';
const token = this.getLiveToken('POST', path, host, undefined, contentType, bodyStr);
const url = `https://pili.qiniuapi.com/v2/hubs/${hub}/streams`;
let response;
try {
response = await global.fetch(url, {
method: 'POST',
headers: {
Authorization: token,
'Content-Type': contentType,
},
body: bodyStr,
// mode: 'no-cors',
});
}
catch (err) {
throw new OakNetworkException();
}
if (response.status !== 200) {
const json = await response.json();
const { error } = json;
throw new OakExternalException('qiniu', response.status.toString(), error, {
status: response.status,
});
}
const obj = this.getStreamObj(hub, streamTitle, expireAt, publishDomain, playDomainType, playDomain, publishSecurity, publishKey, playKey);
return obj;
}
/**
* https://developer.qiniu.com/kodo/1308/stat
* 文档里写的是GET方法从nodejs-sdk里看是POST方法
@ -298,6 +214,97 @@ export class QiniuCloudInstance {
'Content-Type': 'application/x-www-form-urlencoded',
}, undefined, 'POST', undefined, mockData);
}
/**
* 计算直播需要的token
* @param method
* @param path
* @param host
* @param rawQuery
* @param contentType
* @param bodyStr
* @returns
*/
getLiveToken(method, path, host, rawQuery, contentType, bodyStr) {
// 1. 添加 Path
let data = `${method} ${path}`;
if (rawQuery) {
data += `?${rawQuery}`;
}
data += `\nHost: ${host}`;
if (contentType) {
data += `\nContent-Type: ${contentType}`;
}
data += '\n\n';
if (bodyStr &&
contentType &&
contentType !== 'application/octet-stream') {
data += bodyStr;
}
const sign = this.hmacSha1(data, this.secretKey);
const encodedSign = this.base64ToUrlSafe(sign);
const toke = 'Qiniu ' + this.accessKey + ':' + encodedSign;
return toke;
}
/**
* 创建直播流
* @param hub
* @param streamTitle
* @param host
* @param publishDomain
* @param playDomainType
* @param playDomain
* @param expireAt
* @param publishSecurity
* @param publishKey
* @param playKey
* @returns
*/
async createLiveStream(hub, streamTitle, host, publishDomain, playDomainType, playDomain, expireAt, publishSecurity, publishKey, playKey) {
// 七牛创建直播流接口路径
const path = `/v2/hubs/${hub}/streams`;
// 如果用户没给streamTitle那么随机生成一个
let key = streamTitle;
if (!key) {
key = `class${new Date().getTime()}`;
}
const bodyStr = JSON.stringify({
key,
});
const contentType = 'application/json';
const token = this.getLiveToken('POST', path, host, undefined, contentType, bodyStr);
const url = `https://pili.qiniuapi.com/v2/hubs/${hub}/streams`;
let response;
try {
response = await global.fetch(url, {
method: 'POST',
headers: {
Authorization: token,
'Content-Type': contentType,
},
body: bodyStr,
// mode: 'no-cors',
});
}
catch (err) {
throw new OakNetworkException();
}
if (response.status !== 200) {
if (response.status === 614) {
throw new OakExternalException('qiniu', response.status.toString(), '直播流名已存在', {
status: response.status,
});
}
else {
const json = await response.json();
const { error } = json;
throw new OakExternalException('qiniu', response.status.toString(), error, {
status: response.status,
});
}
}
const obj = this.getStreamObj(hub, streamTitle, expireAt, publishDomain, playDomainType, playDomain, publishSecurity, publishKey, playKey);
return obj;
}
/**
* 计算直播流地址相关信息
* @param hub
@ -440,7 +447,7 @@ export class QiniuCloudInstance {
* @param prefix
* @param limit
* @param marker
* @returns 直播流名称
* @returns
*/
async getLiveStreamList(hub, host, liveOnly, prefix, limit, //取值范围0~5000
marker) {
@ -473,8 +480,59 @@ export class QiniuCloudInstance {
catch (err) {
throw new OakNetworkException();
}
const json = await response.json();
return json.items.map((ele) => ele.key);
if (response.status === 200) {
const json = await response.json();
const streamTitles = json.items?.map((ele) => ele.key);
return {
streamTitles,
marker: json.marker,
};
}
else {
const json = await response.json();
const { error } = json;
throw new OakExternalException('qiniu', response.status.toString(), error, {
status: response.status,
});
}
}
/**
* 查询直播流信息
* @param hub
* @param streamTitle
* @param host
* @returns
*/
async getLiveStreamInfo(hub, streamTitle, host) {
const encodedStreamTitle = this.urlSafeBase64Encode(streamTitle);
const path = `/v2/hubs/${hub}/streams/${encodedStreamTitle}`;
const contentType = 'application/x-www-form-urlencoded';
const token = this.getLiveToken('GET', path, host, undefined, contentType);
const url = `https://pili.qiniuapi.com${path}`;
let response;
try {
response = await global.fetch(url, {
method: 'GET',
headers: {
Authorization: token,
'Content-Type': contentType,
},
});
}
catch (err) {
throw new OakNetworkException();
}
if (response.status === 200) {
const json = await response.json();
return json;
}
else {
const json = await response.json();
const { error } = json;
throw new OakExternalException('qiniu', response.status.toString(), error, {
status: response.status,
});
}
}
/**
* 管理端访问七牛云服务器

11
es/types/Qiniu.d.ts vendored
View File

@ -1 +1,12 @@
export type QiniuZone = 'z0' | 'cn-east-2' | 'z1' | 'z2' | 'na0' | 'as0';
export type QiniuLiveStreamInfo = {
createdAt: number;
updatedAt: number;
expireAt: number;
disabledTill: number;
converts: string[];
watermark: boolean;
publishSecurity: string;
publishKey: string;
nropEnable: boolean;
};

View File

@ -1,4 +1,4 @@
import { QiniuZone } from '../../types/Qiniu';
import { QiniuLiveStreamInfo, QiniuZone } from '../../types/Qiniu';
export declare class QiniuCloudInstance {
private accessKey;
private secretKey;
@ -17,40 +17,6 @@ export declare class QiniuCloudInstance {
uploadHost: string;
bucket: string;
};
/**
* token
* @param method
* @param path
* @param host
* @param rawQuery
* @param contentType
* @param bodyStr
* @returns
*/
getLiveToken(method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, host: string, rawQuery?: string, contentType?: string, bodyStr?: string): string;
/**
*
* @param hub
* @param streamTitle
* @param host
* @param publishDomain
* @param playDomainType
* @param playDomain
* @param expireAt
* @param publishSecurity
* @param publishKey
* @param playKey
* @returns
*/
getLiveStream(hub: string, streamTitle: string, host: string, publishDomain: string, playDomainType: 'rtmp' | 'hls' | 'flv', playDomain: string, expireAt: number, publishSecurity: 'none' | 'static' | 'expiry' | 'expiry_sk', publishKey: string, playKey: string): Promise<{
streamTitle: string;
hub: string;
rtmpPushUrl: string;
playUrl: string;
pcPushUrl: string;
streamKey: string;
expireAt: number;
}>;
/**
* https://developer.qiniu.com/kodo/1308/stat
* GET方法nodejs-sdk里看是POST方法
@ -95,6 +61,40 @@ export declare class QiniuCloudInstance {
}>;
moveKodoFile(srcBucket: string, zone: QiniuZone, srcKey: string, destBucket: string, destKey: string, force?: boolean, mockData?: any): Promise<void>;
copyKodoFile(srcBucket: string, zone: QiniuZone, srcKey: string, destBucket: string, destKey: string, force?: boolean, mockData?: any): Promise<void>;
/**
* token
* @param method
* @param path
* @param host
* @param rawQuery
* @param contentType
* @param bodyStr
* @returns
*/
getLiveToken(method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, host: string, rawQuery?: string, contentType?: string, bodyStr?: string): string;
/**
*
* @param hub
* @param streamTitle
* @param host
* @param publishDomain
* @param playDomainType
* @param playDomain
* @param expireAt
* @param publishSecurity
* @param publishKey
* @param playKey
* @returns
*/
createLiveStream(hub: string, streamTitle: string, host: string, publishDomain: string, playDomainType: 'rtmp' | 'hls' | 'flv', playDomain: string, expireAt: number, publishSecurity: 'none' | 'static' | 'expiry' | 'expiry_sk', publishKey: string, playKey: string): Promise<{
streamTitle: string;
hub: string;
rtmpPushUrl: string;
playUrl: string;
pcPushUrl: string;
streamKey: string;
expireAt: number;
}>;
/**
*
* @param hub
@ -136,10 +136,21 @@ export declare class QiniuCloudInstance {
* @param prefix
* @param limit
* @param marker
* @returns
* @returns
*/
getLiveStreamList(hub: string, host: string, liveOnly?: boolean, prefix?: string, limit?: number, //取值范围0~5000
marker?: string): Promise<any>;
marker?: string): Promise<{
streamTitles: string[];
marker: string;
}>;
/**
*
* @param hub
* @param streamTitle
* @param host
* @returns
*/
getLiveStreamInfo(hub: string, streamTitle: string, host: string): Promise<QiniuLiveStreamInfo>;
/**
* 访
* @param path

View File

@ -139,90 +139,6 @@ class QiniuCloudInstance {
throw err;
}
}
/**
* 计算直播需要的token
* @param method
* @param path
* @param host
* @param rawQuery
* @param contentType
* @param bodyStr
* @returns
*/
getLiveToken(method, path, host, rawQuery, contentType, bodyStr) {
// 1. 添加 Path
let data = `${method} ${path}`;
if (rawQuery) {
data += `?${rawQuery}`;
}
data += `\nHost: ${host}`;
if (contentType) {
data += `\nContent-Type: ${contentType}`;
}
data += '\n\n';
if (bodyStr &&
contentType &&
contentType !== 'application/octet-stream') {
data += bodyStr;
}
const sign = this.hmacSha1(data, this.secretKey);
const encodedSign = this.base64ToUrlSafe(sign);
const toke = 'Qiniu ' + this.accessKey + ':' + encodedSign;
return toke;
}
/**
* 创建直播流
* @param hub
* @param streamTitle
* @param host
* @param publishDomain
* @param playDomainType
* @param playDomain
* @param expireAt
* @param publishSecurity
* @param publishKey
* @param playKey
* @returns
*/
async getLiveStream(hub, streamTitle, host, publishDomain, playDomainType, playDomain, expireAt, publishSecurity, publishKey, playKey) {
// 七牛创建直播流接口路径
const path = `/v2/hubs/${hub}/streams`;
// 如果用户没给streamTitle那么随机生成一个
let key = streamTitle;
if (!key) {
key = `class${new Date().getTime()}`;
}
const bodyStr = JSON.stringify({
key,
});
const contentType = 'application/json';
const token = this.getLiveToken('POST', path, host, undefined, contentType, bodyStr);
const url = `https://pili.qiniuapi.com/v2/hubs/${hub}/streams`;
let response;
try {
response = await global.fetch(url, {
method: 'POST',
headers: {
Authorization: token,
'Content-Type': contentType,
},
body: bodyStr,
// mode: 'no-cors',
});
}
catch (err) {
throw new Exception_1.OakNetworkException();
}
if (response.status !== 200) {
const json = await response.json();
const { error } = json;
throw new Exception_1.OakExternalException('qiniu', response.status.toString(), error, {
status: response.status,
});
}
const obj = this.getStreamObj(hub, streamTitle, expireAt, publishDomain, playDomainType, playDomain, publishSecurity, publishKey, playKey);
return obj;
}
/**
* https://developer.qiniu.com/kodo/1308/stat
* 文档里写的是GET方法从nodejs-sdk里看是POST方法
@ -302,6 +218,97 @@ class QiniuCloudInstance {
'Content-Type': 'application/x-www-form-urlencoded',
}, undefined, 'POST', undefined, mockData);
}
/**
* 计算直播需要的token
* @param method
* @param path
* @param host
* @param rawQuery
* @param contentType
* @param bodyStr
* @returns
*/
getLiveToken(method, path, host, rawQuery, contentType, bodyStr) {
// 1. 添加 Path
let data = `${method} ${path}`;
if (rawQuery) {
data += `?${rawQuery}`;
}
data += `\nHost: ${host}`;
if (contentType) {
data += `\nContent-Type: ${contentType}`;
}
data += '\n\n';
if (bodyStr &&
contentType &&
contentType !== 'application/octet-stream') {
data += bodyStr;
}
const sign = this.hmacSha1(data, this.secretKey);
const encodedSign = this.base64ToUrlSafe(sign);
const toke = 'Qiniu ' + this.accessKey + ':' + encodedSign;
return toke;
}
/**
* 创建直播流
* @param hub
* @param streamTitle
* @param host
* @param publishDomain
* @param playDomainType
* @param playDomain
* @param expireAt
* @param publishSecurity
* @param publishKey
* @param playKey
* @returns
*/
async createLiveStream(hub, streamTitle, host, publishDomain, playDomainType, playDomain, expireAt, publishSecurity, publishKey, playKey) {
// 七牛创建直播流接口路径
const path = `/v2/hubs/${hub}/streams`;
// 如果用户没给streamTitle那么随机生成一个
let key = streamTitle;
if (!key) {
key = `class${new Date().getTime()}`;
}
const bodyStr = JSON.stringify({
key,
});
const contentType = 'application/json';
const token = this.getLiveToken('POST', path, host, undefined, contentType, bodyStr);
const url = `https://pili.qiniuapi.com/v2/hubs/${hub}/streams`;
let response;
try {
response = await global.fetch(url, {
method: 'POST',
headers: {
Authorization: token,
'Content-Type': contentType,
},
body: bodyStr,
// mode: 'no-cors',
});
}
catch (err) {
throw new Exception_1.OakNetworkException();
}
if (response.status !== 200) {
if (response.status === 614) {
throw new Exception_1.OakExternalException('qiniu', response.status.toString(), '直播流名已存在', {
status: response.status,
});
}
else {
const json = await response.json();
const { error } = json;
throw new Exception_1.OakExternalException('qiniu', response.status.toString(), error, {
status: response.status,
});
}
}
const obj = this.getStreamObj(hub, streamTitle, expireAt, publishDomain, playDomainType, playDomain, publishSecurity, publishKey, playKey);
return obj;
}
/**
* 计算直播流地址相关信息
* @param hub
@ -444,7 +451,7 @@ class QiniuCloudInstance {
* @param prefix
* @param limit
* @param marker
* @returns 直播流名称
* @returns
*/
async getLiveStreamList(hub, host, liveOnly, prefix, limit, //取值范围0~5000
marker) {
@ -477,8 +484,59 @@ class QiniuCloudInstance {
catch (err) {
throw new Exception_1.OakNetworkException();
}
const json = await response.json();
return json.items.map((ele) => ele.key);
if (response.status === 200) {
const json = await response.json();
const streamTitles = json.items?.map((ele) => ele.key);
return {
streamTitles,
marker: json.marker,
};
}
else {
const json = await response.json();
const { error } = json;
throw new Exception_1.OakExternalException('qiniu', response.status.toString(), error, {
status: response.status,
});
}
}
/**
* 查询直播流信息
* @param hub
* @param streamTitle
* @param host
* @returns
*/
async getLiveStreamInfo(hub, streamTitle, host) {
const encodedStreamTitle = this.urlSafeBase64Encode(streamTitle);
const path = `/v2/hubs/${hub}/streams/${encodedStreamTitle}`;
const contentType = 'application/x-www-form-urlencoded';
const token = this.getLiveToken('GET', path, host, undefined, contentType);
const url = `https://pili.qiniuapi.com${path}`;
let response;
try {
response = await global.fetch(url, {
method: 'GET',
headers: {
Authorization: token,
'Content-Type': contentType,
},
});
}
catch (err) {
throw new Exception_1.OakNetworkException();
}
if (response.status === 200) {
const json = await response.json();
return json;
}
else {
const json = await response.json();
const { error } = json;
throw new Exception_1.OakExternalException('qiniu', response.status.toString(), error, {
status: response.status,
});
}
}
/**
* 管理端访问七牛云服务器

11
lib/types/Qiniu.d.ts vendored
View File

@ -1 +1,12 @@
export type QiniuZone = 'z0' | 'cn-east-2' | 'z1' | 'z2' | 'na0' | 'as0';
export type QiniuLiveStreamInfo = {
createdAt: number;
updatedAt: number;
expireAt: number;
disabledTill: number;
converts: string[];
watermark: boolean;
publishSecurity: string;
publishKey: string;
nropEnable: boolean;
};

View File

@ -8,7 +8,7 @@ import {
OakNetworkException,
} from 'oak-domain/lib/types/Exception';
import { url as URL, urlObject as UrlObject } from 'oak-domain/lib/utils/url';
import { QiniuZone } from '../../types/Qiniu';
import { QiniuLiveStreamInfo, QiniuZone } from '../../types/Qiniu';
/**
* qiniu endpoint list
@ -148,123 +148,6 @@ export class QiniuCloudInstance {
}
}
/**
* token
* @param method
* @param path
* @param host
* @param rawQuery
* @param contentType
* @param bodyStr
* @returns
*/
getLiveToken(
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
path: string,
host: string,
rawQuery?: string,
contentType?: string,
bodyStr?: string
) {
// 1. 添加 Path
let data = `${method} ${path}`;
if (rawQuery) {
data += `?${rawQuery}`;
}
data += `\nHost: ${host}`;
if (contentType) {
data += `\nContent-Type: ${contentType}`;
}
data += '\n\n';
if (
bodyStr &&
contentType &&
contentType !== 'application/octet-stream'
) {
data += bodyStr;
}
const sign = this.hmacSha1(data, this.secretKey);
const encodedSign = this.base64ToUrlSafe(sign);
const toke = 'Qiniu ' + this.accessKey + ':' + encodedSign;
return toke;
}
/**
*
* @param hub
* @param streamTitle
* @param host
* @param publishDomain
* @param playDomainType
* @param playDomain
* @param expireAt
* @param publishSecurity
* @param publishKey
* @param playKey
* @returns
*/
async getLiveStream(
hub: string,
streamTitle: string,
host: string,
publishDomain: string,
playDomainType: 'rtmp' | 'hls' | 'flv',
playDomain: string,
expireAt: number,
publishSecurity: 'none' | 'static' | 'expiry' | 'expiry_sk',
publishKey: string,
playKey: string,
) {
// 七牛创建直播流接口路径
const path = `/v2/hubs/${hub}/streams`;
// 如果用户没给streamTitle那么随机生成一个
let key: string = streamTitle;
if (!key) {
key = `class${new Date().getTime()}`;
}
const bodyStr = JSON.stringify({
key,
});
const contentType = 'application/json';
const token = this.getLiveToken('POST', path, host, undefined, contentType, bodyStr);
const url = `https://pili.qiniuapi.com/v2/hubs/${hub}/streams`;
let response: Response;
try {
response = await global.fetch(url, {
method: 'POST',
headers: {
Authorization: token,
'Content-Type': contentType,
},
body: bodyStr,
// mode: 'no-cors',
});
}
catch (err) {
throw new OakNetworkException();
}
if (response.status !== 200) {
const json = await response.json();
const { error } = json;
throw new OakExternalException('qiniu', response.status.toString(), error, {
status: response.status,
});
}
const obj = this.getStreamObj(
hub,
streamTitle,
expireAt,
publishDomain,
playDomainType,
playDomain,
publishSecurity,
publishKey,
playKey,
);
return obj;
}
/**
* https://developer.qiniu.com/kodo/1308/stat
* GET方法nodejs-sdk里看是POST方法
@ -451,6 +334,129 @@ export class QiniuCloudInstance {
);
}
/**
* token
* @param method
* @param path
* @param host
* @param rawQuery
* @param contentType
* @param bodyStr
* @returns
*/
getLiveToken(
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
path: string,
host: string,
rawQuery?: string,
contentType?: string,
bodyStr?: string
) {
// 1. 添加 Path
let data = `${method} ${path}`;
if (rawQuery) {
data += `?${rawQuery}`;
}
data += `\nHost: ${host}`;
if (contentType) {
data += `\nContent-Type: ${contentType}`;
}
data += '\n\n';
if (
bodyStr &&
contentType &&
contentType !== 'application/octet-stream'
) {
data += bodyStr;
}
const sign = this.hmacSha1(data, this.secretKey);
const encodedSign = this.base64ToUrlSafe(sign);
const toke = 'Qiniu ' + this.accessKey + ':' + encodedSign;
return toke;
}
/**
*
* @param hub
* @param streamTitle
* @param host
* @param publishDomain
* @param playDomainType
* @param playDomain
* @param expireAt
* @param publishSecurity
* @param publishKey
* @param playKey
* @returns
*/
async createLiveStream(
hub: string,
streamTitle: string,
host: string,
publishDomain: string,
playDomainType: 'rtmp' | 'hls' | 'flv',
playDomain: string,
expireAt: number,
publishSecurity: 'none' | 'static' | 'expiry' | 'expiry_sk',
publishKey: string,
playKey: string,
) {
// 七牛创建直播流接口路径
const path = `/v2/hubs/${hub}/streams`;
// 如果用户没给streamTitle那么随机生成一个
let key: string = streamTitle;
if (!key) {
key = `class${new Date().getTime()}`;
}
const bodyStr = JSON.stringify({
key,
});
const contentType = 'application/json';
const token = this.getLiveToken('POST', path, host, undefined, contentType, bodyStr);
const url = `https://pili.qiniuapi.com/v2/hubs/${hub}/streams`;
let response: Response;
try {
response = await global.fetch(url, {
method: 'POST',
headers: {
Authorization: token,
'Content-Type': contentType,
},
body: bodyStr,
// mode: 'no-cors',
});
}
catch (err) {
throw new OakNetworkException();
}
if (response.status !== 200) {
if (response.status === 614) {
throw new OakExternalException('qiniu', response.status.toString(), '直播流名已存在', {
status: response.status,
});
} else {
const json = await response.json();
const { error } = json;
throw new OakExternalException('qiniu', response.status.toString(), error, {
status: response.status,
});
}
}
const obj = this.getStreamObj(
hub,
streamTitle,
expireAt,
publishDomain,
playDomainType,
playDomain,
publishSecurity,
publishKey,
playKey,
);
return obj;
}
/**
*
* @param hub
@ -632,7 +638,7 @@ export class QiniuCloudInstance {
* @param prefix
* @param limit
* @param marker
* @returns
* @returns
*/
async getLiveStreamList(
hub: string,
@ -676,8 +682,72 @@ export class QiniuCloudInstance {
} catch (err) {
throw new OakNetworkException();
}
const json = await response.json();
return json.items.map((ele: any) => ele.key);
if (response.status === 200) {
const json = await response.json();
const streamTitles = json.items?.map((ele: { key: string }) => ele.key);
return {
streamTitles,
marker: json.marker,
} as {
streamTitles: string[];
marker: string;
};
} else {
const json = await response.json();
const { error } = json;
throw new OakExternalException('qiniu', response.status.toString(), error, {
status: response.status,
});
}
}
/**
*
* @param hub
* @param streamTitle
* @param host
* @returns
*/
async getLiveStreamInfo(
hub: string,
streamTitle: string,
host: string,
) {
const encodedStreamTitle = this.urlSafeBase64Encode(streamTitle);
const path = `/v2/hubs/${hub}/streams/${encodedStreamTitle}`;
const contentType = 'application/x-www-form-urlencoded';
const token = this.getLiveToken(
'GET',
path,
host,
undefined,
contentType,
);
const url = `https://pili.qiniuapi.com${path}`;
let response: Response;
try {
response = await global.fetch(url, {
method: 'GET',
headers: {
Authorization: token,
'Content-Type': contentType,
},
});
} catch (err) {
throw new OakNetworkException();
}
if (response.status === 200) {
const json = await response.json();
return json as QiniuLiveStreamInfo;
} else {
const json = await response.json();
const { error } = json;
throw new OakExternalException('qiniu', response.status.toString(), error, {
status: response.status,
});
}
}
/**

View File

@ -1 +1,13 @@
export type QiniuZone = 'z0' | 'cn-east-2' | 'z1' | 'z2' | 'na0' | 'as0';
export type QiniuZone = 'z0' | 'cn-east-2' | 'z1' | 'z2' | 'na0' | 'as0';
export type QiniuLiveStreamInfo = {
createdAt: number;
updatedAt: number;
expireAt: number; //过期时间一个流持续N天设置的直播空间的存储过期时间不推流回被自动清除
disabledTill: number; //-1表示永久禁播
converts: string[]; //转码配置
watermark: boolean; //是否开启水印
publishSecurity: string; //推流鉴权类型
publishKey: string; //推流密钥
nropEnable: boolean; //是否开启鉴黄
}