mirror of
https://github.com/Jerryplusy/rc-plugin.git
synced 2025-10-14 08:09:19 +00:00
✨ feat: 适配 dy 短链接直播 && 增加直播切片自定义时长 [beta]
This commit is contained in:
parent
82b80c5a09
commit
6e1fada26a
@ -36,7 +36,7 @@ import {
|
||||
BILI_SUMMARY,
|
||||
DY_COMMENT,
|
||||
DY_INFO,
|
||||
DY_LIVE_INFO,
|
||||
DY_LIVE_INFO, DY_LIVE_INFO_2,
|
||||
DY_TOUTIAO_INFO,
|
||||
GENERAL_REQ_LINK,
|
||||
HIBI_API_SERVICE,
|
||||
@ -77,7 +77,7 @@ import {
|
||||
downloadImg,
|
||||
estimateReadingTime,
|
||||
formatBiliInfo,
|
||||
retryAxiosReq,
|
||||
retryAxiosReq, saveJsonToFile,
|
||||
secondsToTime,
|
||||
testProxy,
|
||||
truncateString,
|
||||
@ -99,6 +99,7 @@ import { getDS } from "../utils/mihoyo.js";
|
||||
import { OpenaiBuilder } from "../utils/openai-builder.js";
|
||||
import { redisExistKey, redisGetKey, redisSetKey } from "../utils/redis-util.js";
|
||||
import { saveTDL, startTDL } from "../utils/tdl-util.js";
|
||||
import { genVerifyFp } from "../utils/tiktok.js";
|
||||
import Translate from "../utils/trans-strategy.js";
|
||||
import { mid2id } from "../utils/weibo.js";
|
||||
import { ytDlpGetTilt, ytDlpHelper } from "../utils/yt-dlp-util.js";
|
||||
@ -232,6 +233,8 @@ export class tools extends plugin {
|
||||
this.myProxy = `http://${ this.proxyAddr }:${ this.proxyPort }`;
|
||||
// 加载识别前缀
|
||||
this.identifyPrefix = this.toolsConfig.identifyPrefix;
|
||||
// 加载直播录制时长
|
||||
this.streamDuration = this.toolsConfig.streamDuration;
|
||||
// 加载哔哩哔哩配置
|
||||
this.biliSessData = this.toolsConfig.biliSessData;
|
||||
// 加载哔哩哔哩的限制时长
|
||||
@ -317,14 +320,18 @@ export class tools extends plugin {
|
||||
}
|
||||
// 获取链接
|
||||
let douUrl = urlRex.exec(e.msg.trim())[0];
|
||||
let ttwid = '';
|
||||
if (douUrl.includes("v.douyin.com")) {
|
||||
douUrl = await this.douyinRequest(douUrl)
|
||||
const { location, ttwidValue } = await this.douyinRequest(douUrl);
|
||||
ttwid = ttwidValue;
|
||||
douUrl = location
|
||||
}
|
||||
// 获取 ID
|
||||
const douId = /note\/(\d+)/g.exec(douUrl)?.[1] ||
|
||||
/video\/(\d+)/g.exec(douUrl)?.[1] ||
|
||||
/live.douyin.com\/(\d+)/.exec(douUrl)?.[1] ||
|
||||
/live\/(\d+)/.exec(douUrl)?.[1];
|
||||
/live\/(\d+)/.exec(douUrl)?.[1] ||
|
||||
/webcast.amemv.com\/douyin\/webcast\/reflow\/(\d+)/.exec(douUrl)?.[1];
|
||||
// 当前版本需要填入cookie
|
||||
if (_.isEmpty(this.douyinCookie) || _.isEmpty(douId)) {
|
||||
e.reply(`检测到没有Cookie 或者 这是一个无效链接,无法解析抖音${ HELP_DOC }`);
|
||||
@ -340,7 +347,28 @@ export class tools extends plugin {
|
||||
Referer: "https://www.douyin.com/",
|
||||
cookie: this.douyinCookie,
|
||||
};
|
||||
const dyApi = douUrl.includes("live") ? DY_LIVE_INFO.replaceAll("{}", douId) : DY_INFO.replace("{}", douId);
|
||||
let dyApi;
|
||||
if (douUrl.includes("live.douyin.com")) {
|
||||
// 第一类直播类型
|
||||
dyApi = DY_LIVE_INFO.replaceAll("{}", douId)
|
||||
} else if (douUrl.includes("webcast.amemv.com")) {
|
||||
// 第二类直播类型,这里必须使用客户端的 fetch 请求
|
||||
dyApi = DY_LIVE_INFO_2.replace("{}", douId) + `&verifyFp=${ genVerifyFp() }` + `&msToken=${ ttwid }`;
|
||||
const webcastResp = await fetch(dyApi);
|
||||
const webcastData = await webcastResp.json();
|
||||
const item = webcastData.data.room;
|
||||
logger.info(item);
|
||||
const { title, cover, user_count, stream_url } = item;
|
||||
const dySendContent = `${ this.identifyPrefix }识别:抖音直播,${ title }`
|
||||
e.reply([segment.image(cover?.url_list?.[0]), dySendContent, `\n🏄♂️在线人数:${ user_count }人正在观看`]);
|
||||
// 下载10s的直播流
|
||||
await this.sendStreamSegment(e, stream_url?.flv_pull_url?.HD1 || stream_url?.flv_pull_url?.FULL_HD1 || stream_url?.flv_pull_url?.SD1 || stream_url?.flv_pull_url?.SD2);
|
||||
return;
|
||||
} else {
|
||||
// 普通类型
|
||||
dyApi = DY_INFO.replace("{}", douId);
|
||||
}
|
||||
logger.info(dyApi);
|
||||
// a-bogus参数
|
||||
const abParam = aBogus.generate_a_bogus(
|
||||
new URLSearchParams(new URL(dyApi).search).toString(),
|
||||
@ -355,7 +383,7 @@ export class tools extends plugin {
|
||||
});
|
||||
// 如果失败进行3次重试
|
||||
try {
|
||||
const data = await retryAxiosReq(dyResponse)
|
||||
const data = await retryAxiosReq(dyResponse);
|
||||
// saveJsonToFile(data);
|
||||
// 直播数据逻辑
|
||||
if (douUrl.includes("live")) {
|
||||
@ -364,7 +392,7 @@ export class tools extends plugin {
|
||||
const dySendContent = `${ this.identifyPrefix }识别:抖音直播,${ title }`
|
||||
e.reply([segment.image(cover?.url_list?.[0]), dySendContent, `\n🏄♂️在线人数:${ user_count_str }人正在观看`]);
|
||||
// 下载10s的直播流
|
||||
await this.sendStreamSegment(e, stream_url?.flv_pull_url?.HD1);
|
||||
await this.sendStreamSegment(e, stream_url?.flv_pull_url?.HD1 || stream_url?.flv_pull_url?.FULL_HD1 || stream_url?.flv_pull_url?.SD1 || stream_url?.flv_pull_url?.SD2);
|
||||
return;
|
||||
}
|
||||
const item = await data.aweme_detail;
|
||||
@ -458,7 +486,7 @@ export class tools extends plugin {
|
||||
* @param stream_url
|
||||
* @param second
|
||||
*/
|
||||
async sendStreamSegment(e, stream_url, second = 10) {
|
||||
async sendStreamSegment(e, stream_url, second = this.streamDuration) {
|
||||
const outputFilePath = `${ this.getCurDownloadPath(e) }/stream_10s.flv`;
|
||||
await checkAndRemoveFile(outputFilePath);
|
||||
const file = fs.createWriteStream(outputFilePath);
|
||||
@ -471,13 +499,13 @@ export class tools extends plugin {
|
||||
|
||||
// 设置 10 秒后停止下载
|
||||
setTimeout(() => {
|
||||
logger.info('[R插件][发送直播流] 直播下载10秒钟到,停止下载!');
|
||||
logger.info(`[R插件][发送直播流] 直播下载 ${this.streamDuration} 秒钟到,停止下载!`);
|
||||
response.data.destroy(); // 销毁流
|
||||
e.reply(segment.video(outputFilePath));
|
||||
file.close(); // 关闭文件流
|
||||
}, second * 1000); // 10秒 = 10000毫秒
|
||||
}).catch(error => {
|
||||
console.error('下载失败:', error.message);
|
||||
logger.error(`下载失败:${ error.message }`);
|
||||
fs.unlink(outputFilePath, () => {
|
||||
}); // 下载失败时删除文件
|
||||
});
|
||||
@ -2160,11 +2188,28 @@ export class tools extends plugin {
|
||||
timeout: 10000,
|
||||
};
|
||||
try {
|
||||
const resp = await axios.head(url, params);
|
||||
const resp = await axios.get(url, params);
|
||||
|
||||
const location = resp.request.res.responseUrl;
|
||||
|
||||
const setCookieHeaders = resp.headers['set-cookie']
|
||||
let ttwidValue;
|
||||
if (setCookieHeaders) {
|
||||
setCookieHeaders.forEach(cookie => {
|
||||
// 使用正则表达式提取 ttwid 的值
|
||||
const ttwidMatch = cookie.match(/ttwid=([^;]+)/);
|
||||
if (ttwidMatch) {
|
||||
ttwidValue = ttwidMatch[1];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (location != null) {
|
||||
return resolve(location);
|
||||
return resolve({
|
||||
location: location,
|
||||
ttwidValue: ttwidValue
|
||||
});
|
||||
} else {
|
||||
return reject("获取失败");
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ identifyPrefix: '' # 识别前缀,比如你识别哔哩哔哩,那么就有
|
||||
|
||||
deeplApiUrls: 'http://www.gptspt.cn/translate,http://gptspt.top/translate,http://8.134.135.4:1188/translate,http://120.76.141.173:1188/translate,http://bit.x7ys.com:1188/translate,http://deeplxapi.x7ys.com:1188/translate'
|
||||
|
||||
streamDuration: 10 # 视频最大时长(单位秒)
|
||||
|
||||
biliSessData: '' # 哔哩哔哩的SESSDATA
|
||||
biliIntroLenLimit: 50 # 哔哩哔哩简介长度限制,填 0 或者 -1 可以不做任何限制,显示完整简介
|
||||
biliDuration: 480 # 哔哩哔哩限制的最大视频时长(默认8分钟),单位:秒
|
||||
|
@ -1,11 +1,10 @@
|
||||
- {
|
||||
version: 1.9.0,
|
||||
version: 1.9.1,
|
||||
data:
|
||||
[
|
||||
新增<span class="cmd">rso搜索</span>功能,
|
||||
新增<span class="cmd">直播切片</span>功能,
|
||||
优化<span class="cmd">队列下载和GPT</span>功能,
|
||||
新增<span class="cmd">哔哩哔哩下载分辨率设置</span>功能,
|
||||
新增<span class="cmd">自定义识别</span>功能,
|
||||
支持<span class="cmd">锅巴</span>插件,方便查看和修改配置,
|
||||
输入<span class="cmd">#R帮助</span>获取插件帮助,
|
||||
输入<span class="cmd">#R更新</span>更新插件,
|
||||
|
@ -127,6 +127,12 @@ export const DY_TOUTIAO_INFO = "https://aweme.snssdk.com/aweme/v1/play/?video_id
|
||||
*/
|
||||
export const DY_LIVE_INFO = "https://live.douyin.com/webcast/room/web/enter/?device_platform=webapp&aid=6383&channel=channel_pc_web&pc_client_type=1&version_code=190500&version_name=19.5.0&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=Win32&browser_name=Firefox&browser_version=124.0&browser_online=true&engine_name=Gecko&engine_version=122.0.0.0&os_name=Windows&os_version=10&cpu_core_num=12&device_memory=8&platform=PC&web_rid={}&room_id_str={}";
|
||||
|
||||
/**
|
||||
* DY 直播信息 二类型
|
||||
* @type {string}
|
||||
*/
|
||||
export const DY_LIVE_INFO_2 = "https://webcast.amemv.com/webcast/room/reflow/info/?type_id=0&live_id=1&sec_user_id=&version_code=99.99.99&app_id=1128&room_id={}";
|
||||
|
||||
/**
|
||||
* X API
|
||||
* @type {string}
|
||||
|
@ -69,6 +69,17 @@ export function supportGuoba() {
|
||||
placeholder: "请输入DeeplX API地址集合",
|
||||
},
|
||||
},
|
||||
{
|
||||
field: "tools.streamDuration",
|
||||
label: "解析直播时长",
|
||||
bottomHelpMessage:
|
||||
"解析直播(目前涉及哔哩哔哩、抖音)时长,单位:秒(默认:10秒),建议时间为10~60,不然也没人看",
|
||||
component: "InputNumber",
|
||||
required: false,
|
||||
componentProps: {
|
||||
placeholder: "请输入最大解析直播时长",
|
||||
},
|
||||
},
|
||||
{
|
||||
field: "tools.defaultPath",
|
||||
label: "视频暂存位置",
|
||||
|
36
utils/tiktok.js
Normal file
36
utils/tiktok.js
Normal file
@ -0,0 +1,36 @@
|
||||
export function genVerifyFp() {
|
||||
const baseStr = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
const t = baseStr.length;
|
||||
let milliseconds = Date.now(); // 获取当前的时间戳(毫秒)
|
||||
let base36 = "";
|
||||
|
||||
// 将时间戳转换为base36
|
||||
while (milliseconds > 0) {
|
||||
let remainder = milliseconds % 36;
|
||||
if (remainder < 10) {
|
||||
base36 = remainder.toString() + base36;
|
||||
} else {
|
||||
base36 = String.fromCharCode('a'.charCodeAt(0) + remainder - 10) + base36;
|
||||
}
|
||||
milliseconds = Math.floor(milliseconds / 36);
|
||||
}
|
||||
|
||||
const r = base36;
|
||||
let o = new Array(36).fill("");
|
||||
o[8] = o[13] = o[18] = o[23] = "_";
|
||||
o[14] = "4";
|
||||
|
||||
// 生成随机字符
|
||||
for (let i = 0; i < 36; i++) {
|
||||
if (!o[i]) {
|
||||
let n = Math.floor(Math.random() * t);
|
||||
if (i === 19) {
|
||||
n = (3 & n) | 8;
|
||||
}
|
||||
o[i] = baseStr[n];
|
||||
}
|
||||
}
|
||||
|
||||
return "verify_" + r + "_" + o.join("");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user