From 0bbaa4680425644670628c16ed4cd93c656deda4 Mon Sep 17 00:00:00 2001 From: zhiyu1998 <542716863@qq.com> Date: Mon, 21 Oct 2024 19:46:51 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat=EF=BC=9A=E9=80=82=E9=85=8D?= =?UTF-8?q?=E6=B2=B9=E7=AE=A1=E9=9F=B3=E9=A2=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 适配油管音频 2. 提取部分内联函数 --- apps/tools.js | 49 +++++++++++++++++--------------------------- utils/youtube.js | 40 ++++++++++++++++++++++++++++++++++++ utils/yt-dlp-util.js | 14 ++++++++----- 3 files changed, 68 insertions(+), 35 deletions(-) create mode 100644 utils/youtube.js diff --git a/apps/tools.js b/apps/tools.js index 3e4960c..52ab6fe 100644 --- a/apps/tools.js +++ b/apps/tools.js @@ -104,6 +104,7 @@ 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 { convertToSeconds, removeParams, ytbFormatTime } from "../utils/youtube.js"; import { ytDlpGetTilt, ytDlpHelper, ytDlpGetThumbnail, ytDlpGetDuration } from "../utils/yt-dlp-util.js"; import { textArrayToMakeForward } from "../utils/yunzai-util.js"; @@ -1925,19 +1926,7 @@ export class tools extends plugin { // 油管解析 async sy2b(e) { - function formatTime(seconds) { - // 计算小时、分钟和秒 - const hours = Math.floor(seconds / 3600); - const minutes = Math.floor((seconds % 3600) / 60); - const secs = seconds % 60; - // 将小时、分钟和秒格式化为两位数 - const formattedHours = String(hours).padStart(2, '0'); - const formattedMinutes = String(minutes).padStart(2, '0'); - const formattedSeconds = String(secs).padStart(2, '0'); - // 构造时间范围字符串 - return `00:00:00-${formattedHours}:${formattedMinutes}:${formattedSeconds}`; - } - const timeRange = await formatTime(this.youtubeClipTime) + const timeRange = ytbFormatTime(this.youtubeClipTime) const isOversea = await this.isOverseasServer(); if (!isOversea && !(await testProxy(this.proxyAddr, this.proxyPort))) { e.reply("检测到没有梯子,无法解析油管"); @@ -1947,11 +1936,6 @@ export class tools extends plugin { const urlRex = /(?:https?:\/\/)?(www\.|music\.)?youtube\.com\/[A-Za-z\d._?%&+\-=\/#]*/g; const url2Rex = /(?:https?:\/\/)?youtu\.be\/[A-Za-z\d._?%&+\-=\/#]*/g; - //移除链接中的不需要的参数 - function removeParams(url) { - return url.replace(/&list=[^&]*/g, '').replace(/&start_radio=[^&]*/g, '').replace(/&index=[^&]*/g, ''); - } - // 检测操作系统平台 const isWindows = process.platform === 'win32'; @@ -1962,23 +1946,28 @@ export class tools extends plugin { if (this.youtubeGraphicsOptions != 0) { graphics = `[height<=${ this.youtubeGraphicsOptions }]` } - // 适配 YouTube Music - if (url.includes("music")) { - // https://music.youtube.com/watch?v=F4sRtMoIgUs&si=7ZYrHjlI3fHAha0F - url = url.replace("music", "www"); - } + const path = this.getCurDownloadPath(e); await checkAndRemoveFile(path + "/temp.mp4") await checkAndRemoveFile(path + "/thumbnail.png") await ytDlpGetThumbnail(path, url, isOversea, this.myProxy) - const title = await ytDlpGetTilt(url, isOversea, this.myProxy).toString().replace(/\n/g, ''); - // logger.info('标题------',title) - function convertToSeconds(timeStr) { - const [minutes, seconds] = timeStr.split(':').map(Number); // 拆分并转换为数字 - if (!seconds) return timeStr; - return minutes * 60 + seconds; // 分钟转化为秒并加上秒数 + const title = ytDlpGetTilt(url, isOversea, this.myProxy).toString().replace(/\n/g, ''); + + // 音频逻辑 + if (url.includes("music")) { + e.reply([ + segment.image(`${path}/thumbnail.png`), + `${this.identifyPrefix}识别:油管音乐,视频时长超限 \n视频标题:${title}` + ]); + await ytDlpHelper(path, url, isOversea, this.myProxy, this.videoDownloadConcurrency, true, graphics, timeRange); + e.reply(segment.record(`${ path }/temp.mp3`)); + this.uploadGroupFile(e, `${ path }/temp.mp3`); + // 发送完就截断 + return; } - const Duration = convertToSeconds(await ytDlpGetDuration(url, isOversea, this.myProxy).toString().replace(/\n/g, '')) + + // 下面为视频逻辑 + const Duration = convertToSeconds(await ytDlpGetDuration(url, isOversea, this.myProxy).toString().replace(/\n/g, '')); // logger.info('时长------',Duration) if (Duration > this.youtubeDuration) { e.reply([ diff --git a/utils/youtube.js b/utils/youtube.js new file mode 100644 index 0000000..700e5c0 --- /dev/null +++ b/utils/youtube.js @@ -0,0 +1,40 @@ +/** + * 用于YouTube的格式化 + * @param seconds + * @returns {string} + */ +export function ytbFormatTime(seconds) { + // 计算小时、分钟和秒 + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + const secs = seconds % 60; + // 将小时、分钟和秒格式化为两位数 + const formattedHours = String(hours).padStart(2, '0'); + const formattedMinutes = String(minutes).padStart(2, '0'); + const formattedSeconds = String(secs).padStart(2, '0'); + // 构造时间范围字符串 + return `00:00:00-${formattedHours}:${formattedMinutes}:${formattedSeconds}`; +} + +/** + * 移除链接中的不需要的参数 + * @param url + * @returns {*} + */ +export function removeParams(url) { + return url + .replace(/&list=[^&]*/g, '') + .replace(/&start_radio=[^&]*/g, '') + .replace(/&index=[^&]*/g, '') + .replace(/&si=[^&]*/g, ''); +} + +export function convertToSeconds(timeStr) { + const [minutes, seconds] = timeStr.split(':').map(Number); // 拆分并转换为数字 + if (!seconds) return timeStr; + return minutes * 60 + seconds; // 分钟转化为秒并加上秒数 +} + +export async function autoSelectMusicOrVideoSend() { + +} diff --git a/utils/yt-dlp-util.js b/utils/yt-dlp-util.js index 1068ea1..791cbe1 100644 --- a/utils/yt-dlp-util.js +++ b/utils/yt-dlp-util.js @@ -58,13 +58,17 @@ export function ytDlpGetThumbnail(path, url, isOversea, proxy) { */ export async function ytDlpHelper(path, url, isOversea, proxy, maxThreads, merge = false, graphics, timeRange) { return new Promise((resolve, reject) => { - const mergeOption = merge ? '--merge-output-format "mp4"' : ''; + let command = ""; + if (url.includes("music")) { + // e.g yt-dlp -x --audio-format mp3 https://youtu.be/5wEtefq9VzM -o test.mp3 + command = `yt-dlp -x --audio-format mp3 ${constructProxyParam(isOversea, proxy)} -P ${path} -o "temp.mp3" ${url}`; + } else { + const fParam = url.includes("youtu") ? `--download-sections "*${timeRange}" -f "bv${graphics}[ext=mp4]+ba[ext=m4a]" ` : ""; - const fParam = url.includes("youtu") ? `--download-sections "*${timeRange}" -f "bv${graphics}[ext=mp4]+ba[ext=m4a]" ` : ""; + command = `yt-dlp -N ${maxThreads} ${fParam} --concurrent-fragments ${maxThreads} ${constructProxyParam(isOversea, proxy)} -P ${path} -o "temp.%(ext)s" ${url}`; + } - const command = `yt-dlp -N ${maxThreads} ${fParam} --concurrent-fragments ${maxThreads} ${constructProxyParam(isOversea, proxy)} -P ${path} -o "temp.%(ext)s" ${url}`; - - logger.info(`[R插件][yt-dlp审计] ${command}`) + logger.info(`[R插件][yt-dlp审计] ${command}`); exec(command, (error, stdout) => { if (error) {