🎈 perf: V1.3.2 优化油管解析性能

1. 优化了寻找最佳解析分辨率的算法
2. 优化“魔法值”,增加后期可维护性
3. 说明 X 的不可维护性
This commit is contained in:
zhiyu 2024-02-06 16:34:12 +08:00
parent 9769dce7a4
commit 4046905c83
8 changed files with 135 additions and 92 deletions

View File

@ -113,6 +113,9 @@ chmod a+rx ~/.local/bin/yt-dlp
<img src="./img/douyin_cookie.webp" alt="小程序解析" width="50%" height="50%" />
### ✖️ 小蓝鸟问题
**2024-2-5**修复小蓝鸟的时候看到free计划已经[没有给查看Tweet的api](https://developer.twitter.com/en/portal/products/basic),原先[使用的库也出现了403报错](https://github.com/PLhery/node-twitter-api-v2)开通会员要100美元不值得。目前暂停更新后续有方案和精力再更新
## 🤺 R插件交流群
扫码不行就575663150
@ -161,7 +164,9 @@ chmod a+rx ~/.local/bin/yt-dlp
* [x0rz4](https://gitee.com/x0rz4) 提供依赖掉包解决方案
感谢以下框架的开源:
YouTube解析参考了[yt-dlp:A youtube-dl fork with additional features and fixes](https://github.com/yt-dlp/yt-dlp)
YouTube解析参考了
- [yt-dlp:A youtube-dl fork with additional features and fixes](https://github.com/yt-dlp/yt-dlp)
## ☕ 请我喝一杯瑞幸咖啡
如果你觉得插件能帮助到你增进好友关系,那么你可以在有条件的情况下[请我喝一杯瑞幸咖啡](https://afdian.net/a/zhiyu1998),这是我开源这个插件的最大动力!

View File

@ -16,6 +16,7 @@ import {
DIVIDING_LINE,
XHS_NO_WATERMARK_HEADER,
REDIS_YUNZAI_ISOVERSEA,
TWITTER_BEARER_TOKEN,
} from "../constants/constant.js";
import { containsChinese, formatBiliInfo, getIdVideo, secondsToTime } from "../utils/common.js";
import config from "../model/index.js";
@ -27,8 +28,8 @@ import { av2BV } from "../utils/bilibili-bv-av-convert.js";
import querystring from "querystring";
import TokenBucket from "../utils/token-bucket.js";
import { getWbi } from "../utils/biliWbi.js";
import { BILI_SUMMARY } from "../constants/bili.js";
import { XHS_VIDEO } from "../constants/xhs.js";
import { BILI_SUMMARY, DY_INFO, TIKTOK_INFO, TWITTER_TWEET_INFO, XHS_REQ_LINK } from "../constants/tools.js";
import { XHS_VIDEO } from "../constants/tools.js";
import child_process from 'node:child_process'
import { getAudio, getVideo } from "../utils/y2b.js";
import { processTikTokUrl } from "../utils/tiktok.js";
@ -168,7 +169,7 @@ export class tools extends plugin {
Referer: "https://www.douyin.com/",
cookie: this.douyinCookie,
};
const dyApi = `https://www.douyin.com/aweme/v1/web/aweme/detail/?device_platform=webapp&aid=6383&channel=channel_pc_web&aweme_id=${ douId }&pc_client_type=1&version_code=190500&version_name=19.5.0&cookie_enabled=true&screen_width=1344&screen_height=756&browser_language=zh-CN&browser_platform=Win32&browser_name=Firefox&browser_version=118.0&browser_online=true&engine_name=Gecko&engine_version=109.0&os_name=Windows&os_version=10&cpu_core_num=16&device_memory=&platform=PC&webid=7284189800734082615&msToken=B1N9FM825TkvFbayDsDvZxM8r5suLrsfQbC93TciS0O9Iii8iJpAPd__FM2rpLUJi5xtMencSXLeNn8xmOS9q7bP0CUsrt9oVTL08YXLPRzZm0dHKLc9PGRlyEk=`;
const dyApi = DY_INFO.replace("{}", douId);
// xg参数
const xbParam = xBogus.sign(
new URLSearchParams(new URL(dyApi).search).toString(),
@ -236,7 +237,7 @@ export class tools extends plugin {
let tiktokVideoId = await getIdVideo(url);
tiktokVideoId = tiktokVideoId.replace(/\//g, "");
// API链接
const API_URL = `https://api16-normal-c-useast1a.tiktokv.com/aweme/v1/feed/?aweme_id=${ tiktokVideoId }`;
const API_URL = TIKTOK_INFO.replace("{}", tiktokVideoId);
await fetch(API_URL, {
headers: {
"User-Agent":
@ -491,7 +492,7 @@ export class tools extends plugin {
return true;
}
// 小蓝鸟解析
// 小蓝鸟解析:停止更新
// 例子https://twitter.com/chonkyanimalx/status/1595834168000204800
async twitter(e) {
// 配置参数及解析
@ -499,65 +500,70 @@ export class tools extends plugin {
const twitterUrl = reg.exec(e.msg);
const id = twitterUrl[1];
// 判断是否是海外服务器默认为false
const isProxy = !(await this.isOverseasServer());
const httpAgent = new HttpsProxyAgent(this.myProxy);
const twitterClient = new TwitterApi(Buffer.from(TWITTER_BEARER_TOKEN, "base64").toString(), !isProxy ?? { httpAgent });
const isOversea = !(await this.isOverseasServer());
// Tell typescript it's a readonly app
const readOnlyClient = twitterClient.readOnly;
readOnlyClient.v2
.singleTweet(id, {
"media.fields":
"duration_ms,height,media_key,preview_image_url,public_metrics,type,url,width,alt_text,variants",
expansions: ["entities.mentions.username", "attachments.media_keys"],
})
.then(async resp => {
e.reply(`识别:小蓝鸟学习版,${ resp.data.text }`);
const downloadPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`;
// 创建文件夹(如果没有过这个群)
if (!fs.existsSync(downloadPath)) {
mkdirsSync(downloadPath);
// 请求
const params = {
"ids": id,
"media.fields":
"duration_ms,height,media_key,preview_image_url,public_metrics,type,url,width,alt_text,variants",
"expansions": ["entities.mentions.username", "attachments.media_keys"],
}
await fetch(TWITTER_TWEET_INFO.replace("{}", id), {
headers: {
"User-Agent": "v2TweetLookupJS",
"authorization": `Bearer ${Buffer.from(TWITTER_BEARER_TOKEN, "base64").toString()}`
},
...params,
agent: !isOversea ? '' : new HttpProxyAgent(this.myProxy),
}).then(async resp => {
logger.info(resp)
e.reply(`识别:小蓝鸟学习版,${ resp.data.text }`);
const downloadPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`;
// 创建文件夹(如果没有过这个群)
if (!fs.existsSync(downloadPath)) {
mkdirsSync(downloadPath);
}
// 逐个遍历判断
let task = [];
for (let item of resp.includes.media) {
if (item.type === "photo") {
// 图片
task.push(this.downloadImg(item.url, downloadPath, "", true));
} else if (item.type === "video") {
// 视频
await this.downloadVideo(resp.includes.media[0].variants[0].url, true).then(
_ => {
e.reply(segment.video(`${ downloadPath }/temp.mp4`));
},
);
}
// 逐个遍历判断
let task = [];
for (let item of resp.includes.media) {
if (item.type === "photo") {
// 图片
task.push(this.downloadImg(item.url, downloadPath, "", true));
} else if (item.type === "video") {
// 视频
await this.downloadVideo(resp.includes.media[0].variants[0].url, true).then(
_ => {
e.reply(segment.video(`${ downloadPath }/temp.mp4`));
},
);
}
}
// 如果没有图片直接返回走
if (task.length === 0) {
return true;
}
// 下面是有图片的情况
let images = [];
let path = [];
// 获取所有图片的promise
await Promise.all(task).then(resp => {
// console.log(resp)
resp.forEach(item => {
path.push(item);
images.push({
message: segment.image(fs.readFileSync(item)),
nickname: this.e.sender.card || this.e.user_id,
user_id: this.e.user_id,
});
}
// 如果没有图片直接返回走
if (task.length === 0) {
return true;
}
// 下面是有图片的情况
let images = [];
let path = [];
// 获取所有图片的promise
await Promise.all(task).then(resp => {
// console.log(resp)
resp.forEach(item => {
path.push(item);
images.push({
message: segment.image(fs.readFileSync(item)),
nickname: this.e.sender.card || this.e.user_id,
user_id: this.e.user_id,
});
});
await e.reply(await Bot.makeForwardMsg(images));
// 清理文件
path.forEach(item => {
fs.unlinkSync(item);
});
});
await e.reply(await Bot.makeForwardMsg(images));
// 清理文件
path.forEach(item => {
fs.unlinkSync(item);
});
});
return true;
}
@ -615,7 +621,7 @@ export class tools extends plugin {
}
const downloadPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`;
// 获取信息
fetch(`https://www.xiaohongshu.com/explore/${ id }`, {
fetch(`${XHS_REQ_LINK}${ id }`, {
headers: XHS_NO_WATERMARK_HEADER,
}).then(async resp => {
const xhsHtml = await resp.text();
@ -951,8 +957,8 @@ export class tools extends plugin {
// bestVideo = Array.from(videos).sort((a, b) => a.rate - b.rate)[videos.length - 1];
// 较为有性能的分辨率
bestVideo = Array.from(videos).filter(item => item.scale.includes("720") || item.scale.includes("360"))[0];
bestAudio = Array.from(audios).filter(item => item.format === 'm4a')[0];
bestVideo = Array.from(videos).find(item => item.scale.includes("720") || item.scale.includes("360"));
bestAudio = Array.from(audios).find(item => item.format === 'm4a');
// logger.mark({
// bestVideo,
// bestAudio
@ -969,7 +975,7 @@ export class tools extends plugin {
let cmd = //`cd '${__dirname}' && (cd tmp > /dev/null || (mkdir tmp && cd tmp)) &&` +
`yt-dlp ${ this.y2bCk !== undefined ? `--cookies ${ this.y2bCk }` : '' } ${url} -f ${ format.replace('x', '+') } ` +
`-o '${ fullpath }/${ v }.%(ext)s' ${ isProxy ? `--proxy ${ this.proxyAddr }:${ this.proxyPort }` : '' } -k --write-info-json`;
logger.info(cmd)
logger.mark(cmd)
try {
await child_process.execSync(cmd);
e.reply(segment.video(`${ fullpath }/${ v }.mp4`))
@ -1147,6 +1153,11 @@ export class tools extends plugin {
}
}
/**
* 设置海外模式
* @param e
* @returns {Promise<boolean>}
*/
async setOversea(e) {
// 查看当前设置
let os;

View File

@ -1,20 +0,0 @@
/**
* AI总结API
* https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/misc/sign/wbi.md
* @type {string}
*/
export const BILI_SUMMARY = "https://api.bilibili.com/x/web-interface/view/conclusion/get"
/**
* 视频基本信息API
* https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/video/info.md
* @type {string}
*/
export const BILI_VIDEO_INFO = "http://api.bilibili.com/x/web-interface/view"
/**
* 登录基本信息
* https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/login/login_info.md#%E5%AF%BC%E8%88%AA%E6%A0%8F%E7%94%A8%E6%88%B7%E4%BF%A1%E6%81%AF
* @type {string}
*/
export const BILI_NAV = "https://api.bilibili.com/x/web-interface/nav"

View File

@ -70,3 +70,5 @@ export const DIVIDING_LINE = "\n------------------{}------------------"
* @type {string}
*/
export const REDIS_YUNZAI_ISOVERSEA = "Yz:rconsole:tools:oversea";
export const TWITTER_BEARER_TOKEN = ""

50
constants/tools.js Normal file
View File

@ -0,0 +1,50 @@
/**
* AI总结API
* https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/misc/sign/wbi.md
* @type {string}
*/
export const BILI_SUMMARY = "https://api.bilibili.com/x/web-interface/view/conclusion/get"
/**
* 视频基本信息API
* https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/video/info.md
* @type {string}
*/
export const BILI_VIDEO_INFO = "http://api.bilibili.com/x/web-interface/view"
/**
* 登录基本信息
* https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/login/login_info.md#%E5%AF%BC%E8%88%AA%E6%A0%8F%E7%94%A8%E6%88%B7%E4%BF%A1%E6%81%AF
* @type {string}
*/
export const BILI_NAV = "https://api.bilibili.com/x/web-interface/nav"
/**
* 视频请求链接CDN
* @type {string}
*/
export const XHS_VIDEO = "http://sns-video-bd.xhscdn.com/"
/**
* dy API
* @type {string}
*/
export const DY_INFO = "https://www.douyin.com/aweme/v1/web/aweme/detail/?device_platform=webapp&aid=6383&channel=channel_pc_web&aweme_id={}&pc_client_type=1&version_code=190500&version_name=19.5.0&cookie_enabled=true&screen_width=1344&screen_height=756&browser_language=zh-CN&browser_platform=Win32&browser_name=Firefox&browser_version=118.0&browser_online=true&engine_name=Gecko&engine_version=109.0&os_name=Windows&os_version=10&cpu_core_num=16&device_memory=&platform=PC&webid=7284189800734082615&msToken=B1N9FM825TkvFbayDsDvZxM8r5suLrsfQbC93TciS0O9Iii8iJpAPd__FM2rpLUJi5xtMencSXLeNn8xmOS9q7bP0CUsrt9oVTL08YXLPRzZm0dHKLc9PGRlyEk="
/**
* Tiktok API
* @type {string}
*/
export const TIKTOK_INFO = "https://api16-normal-c-useast1a.tiktokv.com/aweme/v1/feed/?aweme_id={}"
/**
* X API
* @type {string}
*/
export const TWITTER_TWEET_INFO = "https://api.twitter.com/2/tweets?ids={}"
/**
* XHS 的请求链接
* @type {string}
*/
export const XHS_REQ_LINK = "https://www.xiaohongshu.com/explore/"

View File

@ -1,5 +0,0 @@
/**
* 视频请求链接CDN
* @type {string}
*/
export const XHS_VIDEO = "http://sns-video-bd.xhscdn.com/"

View File

@ -1,6 +1,6 @@
import fetch from "node-fetch";
import axios from "axios";
import { BILI_VIDEO_INFO } from "../constants/bili.js";
import { BILI_VIDEO_INFO } from "../constants/tools.js";
async function getVideoInfo(url) {
// const baseVideoInfo = "http://api.bilibili.com/x/web-interface/view";

View File

@ -1,5 +1,5 @@
import md5 from 'md5'
import { BILI_NAV } from "../constants/bili.js";
import { BILI_NAV } from "../constants/tools.js";
const mixinKeyEncTab = [
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,