From a65e4290343be72834d94d484af7362f00e4fde7 Mon Sep 17 00:00:00 2001 From: Develon2015 <302615249@qq.com> Date: Mon, 5 Oct 2020 21:10:27 +0800 Subject: [PATCH 01/61] Update --- .gitignore | 2 ++ config.json | 5 ++--- cookies.txt | 12 ++++++++++++ index.js | 39 +++++++++++++++++++++++---------------- 4 files changed, 39 insertions(+), 19 deletions(-) create mode 100644 .gitignore create mode 100644 cookies.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6cb772b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +tmp diff --git a/config.json b/config.json index 99c21ca..6784681 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,6 @@ { - "address": "127.0.0.1", - "port": 28888, - "disk": "/dev/sda2", + "address": "0.0.0.0", + "port": 80, "cookie": "cookies.txt", "blacklist": "blacklist.txt", "mode": "演示模式" diff --git a/cookies.txt b/cookies.txt new file mode 100644 index 0000000..b9b6654 --- /dev/null +++ b/cookies.txt @@ -0,0 +1,12 @@ +# Netscape HTTP Cookie File +# This file is generated by youtube-dl. Do not edit. + +.youtube.com TRUE / TRUE 2146723198 CONSENT YES+JP.zh-CN+20161009-18-0 +.youtube.com TRUE / FALSE 1601903974 GPS 1 +.youtube.com TRUE / FALSE 1607086761 PREF f1=50000000&f6=8&hl=en +.youtube.com TRUE / TRUE 1617428183 VISITOR_INFO1_LIVE O3iKRKMJC5k +.youtube.com TRUE / TRUE 0 YSC IufRwdakY8s +.youtube.com TRUE / TRUE 1664974174 __Secure-3PAPISID ZISjGgE8830AXgFi/AIxubKg_gvkT_hcQg +.youtube.com TRUE / TRUE 1664974174 __Secure-3PSID 2AfUWLyxBONI8BjFvhuAig89T0Dhx0COSUkbHxkJJdfMFE5Dr4-z7hPHOVkqYWxgyT5geg. +.youtube.com TRUE / FALSE 0 s_gl 1d69aac621b2f9c0a25dade722d6e24bcwIAAABVUw== +.youtube.com TRUE / FALSE 0 wide 1 diff --git a/index.js b/index.js index 2d05f0a..9e6b363 100644 --- a/index.js +++ b/index.js @@ -76,22 +76,8 @@ function main() { if (queue[JSON.stringify(req.query)] === undefined) { // 检查磁盘空间 - try { - let df = child_process.execSync(`df -h '${config.disk}'`).toString(); - df.split('\n').forEach(it => { - console.log({'空间': it}); - // /dev/sda2 39G 19G 19G 51% / - let mr = it.match(/.*\s(\d+)%/); - if (!!mr && Number.parseInt(mr[1]) > 90) { - let cmd = `rm -r '${__dirname}/tmp'`; - console.log({'清理空间': cmd}); - child_process.execSync(cmd); - queue = [];; - } - }); - } catch(error) { - // - } + checkDisk(); + queue[JSON.stringify(req.query)] = { "success": true, @@ -140,6 +126,7 @@ function task() { let rs = []; try { + checkDisk(); if (true) rs = child_process.execSync(`youtube-dl ${config.cookie !== undefined ? `--cookies ${config.cookie}` : ''} -F '${msg.url}' 2> /dev/null`).toString().split('\n'); // 测试用数据 @@ -274,6 +261,26 @@ format code extension resolution note }); } +// 检测磁盘空间 +function checkDisk() { + try { + let df = child_process.execSync(`df -h .`).toString(); + df.split('\n').forEach(it => { + console.log({'空间': it}); + // /dev/sda2 39G 19G 19G 51% / + let mr = it.match(/.*\s(\d+)%/); + if (!!mr && Number.parseInt(mr[1]) > 90) { + let cmd = `rm -r '${__dirname}/tmp'`; + console.log({'清理空间': cmd}); + child_process.execSync(cmd); + queue = [];; + } + }); + } catch(error) { + // + } +} + if (worker_threads.isMainThread) main(); else From 99df1055af1a0f0fdbd62c2edef115a89cb7e0f8 Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Tue, 6 Oct 2020 04:05:23 +0800 Subject: [PATCH 02/61] README.md --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index f92da69..1891e13 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,36 @@ 通过本项目,您可以搭建一个网页,快速下载您中意的Youtube视频。 在线地址:[https://y2b.123345.xyz](https://y2b.123345.xyz) + + +## 更新记录 + +
+展开 + +### 很久之前 + +1: 使用Kotlin实现了master分支 + +### 过了一段时间 + +1:使用Node.js重构 + +2:自动清理空间 + +3:支持视频标题作为文件名 + +4: 添加黑名单, 以及Cookies, 避免Youtube 429响应 + +### 后来 + +1: 字幕(待实现) + +
+ + + + ## 安装 ### 1.安装Node.js From 3cedfed04bd05892f6255ebb8a8a717f061b788d Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Tue, 6 Oct 2020 04:07:19 +0800 Subject: [PATCH 03/61] README.md --- README.md | 53 +++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 1891e13..c510990 100644 --- a/README.md +++ b/README.md @@ -7,32 +7,6 @@ -## 更新记录 - -
-展开 - -### 很久之前 - -1: 使用Kotlin实现了master分支 - -### 过了一段时间 - -1:使用Node.js重构 - -2:自动清理空间 - -3:支持视频标题作为文件名 - -4: 添加黑名单, 以及Cookies, 避免Youtube 429响应 - -### 后来 - -1: 字幕(待实现) - -
- - ## 安装 @@ -74,3 +48,30 @@ npm start ``` + + + +## 更新记录 + +
+展开 + +##### 很久之前 + +1. 使用Kotlin实现了master分支 + +##### 过了一段时间 + +1. 使用Node.js重构 + +2. 自动清理空间 + +3. 支持视频标题作为文件名 + +4. 添加黑名单, 以及Cookies, 避免Youtube 429响应 + +##### 后来 + +1. 字幕(待实现) + +
From 74ba6b1ac0dcf8c71632aa3e9f294c923e2b2c90 Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Tue, 6 Oct 2020 04:34:46 +0800 Subject: [PATCH 04/61] checkDisk() --- index.js | 55 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/index.js b/index.js index 9e6b363..0ffb5c0 100644 --- a/index.js +++ b/index.js @@ -4,7 +4,7 @@ const worker_threads = require('worker_threads'); const fs = require('fs'); const getRemoteIP = require('./get-remote-ip.js'); -const config = require('./config.json'); +const config = require('./config.json'); // 加载配置文件 function main() { let app = new express(); @@ -53,6 +53,7 @@ function main() { }); return; } + checkDisk(); // 解析视频前先检查磁盘空间 let thread = new worker_threads.Worker(__filename); thread.once('message', msg => { @@ -75,9 +76,7 @@ function main() { return res.send({ "error": "演示模式,关闭转码功能
本项目已使用Node.js重写
请克隆本项目后自行部署", "success": false }); if (queue[JSON.stringify(req.query)] === undefined) { - // 检查磁盘空间 - checkDisk(); - + checkDisk(); // 下载视频前先检查磁盘空间 queue[JSON.stringify(req.query)] = { "success": true, @@ -107,7 +106,29 @@ function main() { app.listen(config.port, config.address, () => { console.log('服务已启动'); }); -} + + /** + * 检测磁盘空间, 必要时清理空间并清空队列queue + */ + function checkDisk() { + try { + let df = child_process.execSync(`df -h .`).toString(); + df.split('\n').forEach(it => { + console.log({ '空间': it }); + // /dev/sda2 39G 19G 19G 51% / + let mr = it.match(/.*\s(\d+)%/); + if (!!mr && Number.parseInt(mr[1]) > 90) { + let cmd = `rm -r '${__dirname}/tmp'`; + console.log({ '清理空间': cmd }); + child_process.execSync(cmd); + queue = []; + } + }); + } catch (error) { + // + } + } // checkDisk() +} // main() function getAudio(id, format, rate, info, size) { return { id, format, rate, info, size }; @@ -117,6 +138,9 @@ function getVideo(id, format, scale, frame, rate, info, size) { return { id, format, scale, frame, rate, info, size }; } +/** + * Worker线程入口 + */ function task() { worker_threads.parentPort.once('message', msg => { switch (msg.op) { @@ -126,7 +150,6 @@ function task() { let rs = []; try { - checkDisk(); if (true) rs = child_process.execSync(`youtube-dl ${config.cookie !== undefined ? `--cookies ${config.cookie}` : ''} -F '${msg.url}' 2> /dev/null`).toString().split('\n'); // 测试用数据 @@ -261,26 +284,6 @@ format code extension resolution note }); } -// 检测磁盘空间 -function checkDisk() { - try { - let df = child_process.execSync(`df -h .`).toString(); - df.split('\n').forEach(it => { - console.log({'空间': it}); - // /dev/sda2 39G 19G 19G 51% / - let mr = it.match(/.*\s(\d+)%/); - if (!!mr && Number.parseInt(mr[1]) > 90) { - let cmd = `rm -r '${__dirname}/tmp'`; - console.log({'清理空间': cmd}); - child_process.execSync(cmd); - queue = [];; - } - }); - } catch(error) { - // - } -} - if (worker_threads.isMainThread) main(); else From 5d0b1278fce1bab5fcea84b0e34a3c04feda76a8 Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Tue, 6 Oct 2020 07:55:51 +0800 Subject: [PATCH 05/61] catchSubtitle --- index.js | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 0ffb5c0..b5a6ecc 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,9 @@ const getRemoteIP = require('./get-remote-ip.js'); const config = require('./config.json'); // 加载配置文件 +/*====================================================================================== +main 主线程 +========================================================================================*/ function main() { let app = new express(); app.use((req, res, next) => { @@ -130,6 +133,11 @@ function main() { } // checkDisk() } // main() + + +/*====================================================================================== +Worker +========================================================================================*/ function getAudio(id, format, rate, info, size) { return { id, format, rate, info, size }; } @@ -138,6 +146,74 @@ function getVideo(id, format, scale, frame, rate, info, size) { return { id, format, scale, frame, rate, info, size }; } +/** + * 在以下形式的字符串中捕获字幕: + * Language formats <= 返回0, 继续 + * gu vtt, ttml, srv3, srv2, srv1 + * zh-Hans vtt, ttml, srv3, srv2, srv1 + * 其它形式一律视为终结符, 返回-1, 终结 + * @param {String} line + */ +function catchSubtitle(line) { + let mr = line.match(/([a-z]{2}(?:-[a-zA-Z]+)?).*/); + if (mr) return mr[1]; + if (mr.match(/.*Language formats.*/)) return 0; + return -1; +} + +/** + * 同步解析字幕 + * @param {{ op: 'parse', url: String, videoID: String }} msg + */ +function parseSubtitle(msg) { + let cmd = `youtube-dl --list-subs "${msg.url}"`; + console.log(`解析字幕, 命令: ${cmd}`); + try { + let rs = child_process.execSync( + `youtube-dl --list-subs ${config.cookie !== undefined ? `--cookies "${config.cookie}"` : ''} '${msg.url}' 2> /dev/null` + ).toString() + .split(/(\r\n|\n)/); + + /** 是否没有自动字幕 */ + let noAutoSub = true; + let officialSub = []; + + for (let i = 0; i < rs.length; i ++ ) { + console.log('=> ', rs[i]); + // 排除一下连自动字幕都没有的, 那一定是没有任何字幕可用 + if (rs[i].match(/.*Available automatic captions for .*?:/)) { // ?表示非贪婪, 遇到冒号即停止 + noAutoSub = false; // 排除即可, 全都是把整个字幕列表输出一遍, 这部分不需要捕获 + continue; + } + // 解析官方字幕 + if (rs[i].match(/.*Available subtitles for .*?:/)) { + FOR_J: // 打标签, 因为需要从switch中断 + for (let j = i + 1; j < rs.length; j ++ ) { + // + sub = catchSubtitle(rs[j]); + switch (sub) { + case -1: { // 终结 + break FOR_J; + } + case 0: { // 继续 + continue; + } + default: { // 捕获 + officialSub.push(sub); + break; + } + } + } // for j + } // if + } // for i + console.log('捕获到官方字幕:'); + console.log(officialSub); + } catch (error) { + console.error(error); + } + return {}; +} + /** * Worker线程入口 */ @@ -211,6 +287,8 @@ format code extension resolution note videos.sort((a, b) => a.rate - b.rate); bestAudio = audios[audios.length - 1]; bestVideo = videos[videos.length - 1]; + + let subs = parseSubtitle(msg); // 解析字幕 worker_threads.parentPort.postMessage({ "success": true, @@ -220,7 +298,7 @@ format code extension resolution note "audio": bestAudio, "video": bestVideo, }, - "available": { audios, videos } + "available": { audios, videos, subs } } }); @@ -284,7 +362,11 @@ format code extension resolution note }); } +/*====================================================================================== +index.js 兵分两路 +========================================================================================*/ if (worker_threads.isMainThread) main(); else task(); +/*======================================================================================*/ \ No newline at end of file From 41505a945f283765026a99103c0af0bbf334b833 Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Tue, 6 Oct 2020 08:21:44 +0800 Subject: [PATCH 06/61] catchSubtitle bug fixed --- index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index b5a6ecc..2eef095 100644 --- a/index.js +++ b/index.js @@ -157,7 +157,7 @@ function getVideo(id, format, scale, frame, rate, info, size) { function catchSubtitle(line) { let mr = line.match(/([a-z]{2}(?:-[a-zA-Z]+)?).*/); if (mr) return mr[1]; - if (mr.match(/.*Language formats.*/)) return 0; + if (line.match(/.*Language formats.*/)) return 0; return -1; } @@ -179,6 +179,7 @@ function parseSubtitle(msg) { let officialSub = []; for (let i = 0; i < rs.length; i ++ ) { + if (rs[i].trim() == '') continue; // 空行直接忽略 console.log('=> ', rs[i]); // 排除一下连自动字幕都没有的, 那一定是没有任何字幕可用 if (rs[i].match(/.*Available automatic captions for .*?:/)) { // ?表示非贪婪, 遇到冒号即停止 @@ -209,7 +210,7 @@ function parseSubtitle(msg) { console.log('捕获到官方字幕:'); console.log(officialSub); } catch (error) { - console.error(error); + console.log(error); // npm 命令无法捕获error错误流 } return {}; } From 805e65688416e30b63377b6196199901adff08a1 Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Tue, 6 Oct 2020 19:03:23 +0800 Subject: [PATCH 07/61] subtest --- index.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 2eef095..3e3f550 100644 --- a/index.js +++ b/index.js @@ -179,7 +179,7 @@ function parseSubtitle(msg) { let officialSub = []; for (let i = 0; i < rs.length; i ++ ) { - if (rs[i].trim() == '') continue; // 空行直接忽略 + if (rs[i].trim() === '' || rs[i].trim() === '\n') continue; // 空行直接忽略 console.log('=> ', rs[i]); // 排除一下连自动字幕都没有的, 那一定是没有任何字幕可用 if (rs[i].match(/.*Available automatic captions for .*?:/)) { // ?表示非贪婪, 遇到冒号即停止 @@ -190,7 +190,7 @@ function parseSubtitle(msg) { if (rs[i].match(/.*Available subtitles for .*?:/)) { FOR_J: // 打标签, 因为需要从switch中断 for (let j = i + 1; j < rs.length; j ++ ) { - // + if (rs[j].trim() === '' || rs[j].trim() === '\n') continue; // 空行直接忽略 sub = catchSubtitle(rs[j]); switch (sub) { case -1: { // 终结 @@ -208,7 +208,17 @@ function parseSubtitle(msg) { } // if } // for i console.log('捕获到官方字幕:'); - console.log(officialSub); + console.log(JSON.stringify(officialSub, null, 2)); + + if (officialSub.length < 1) { // 没有官方字幕 + if (noAutoSub) { // 没有任何字幕 + console.log('没有任何字幕'); + } else { // 没有官方字幕但是有自动生成字幕 + console.log('有自动生成字幕'); + } + } else { // 有官方字幕, 同时可以自动翻译为任何字幕 + console.log('有官方字幕'); + } } catch (error) { console.log(error); // npm 命令无法捕获error错误流 } From fea9032fb8ecd8f28c3767d167cf99e4d636270d Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Tue, 6 Oct 2020 19:15:31 +0800 Subject: [PATCH 08/61] =?UTF-8?q?'=E8=AF=AF=E5=88=A4Language=20formats?= =?UTF-8?q?=E8=A1=8C'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 3e3f550..14b2e8d 100644 --- a/index.js +++ b/index.js @@ -155,9 +155,9 @@ function getVideo(id, format, scale, frame, rate, info, size) { * @param {String} line */ function catchSubtitle(line) { - let mr = line.match(/([a-z]{2}(?:-[a-zA-Z]+)?).*/); + if (line.match(/^Language formats.*/)) return 0; + let mr = line.match(/^([a-z]{2}(?:-[a-zA-Z]+)?).*/); if (mr) return mr[1]; - if (line.match(/.*Language formats.*/)) return 0; return -1; } From 653833b820d9134cde0d764ee51405412902734b Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Wed, 7 Oct 2020 03:56:20 +0800 Subject: [PATCH 09/61] stash --- index.js | 12 ++-- webapps/index.html | 172 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 175 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index 14b2e8d..0ae4f67 100644 --- a/index.js +++ b/index.js @@ -180,7 +180,7 @@ function parseSubtitle(msg) { for (let i = 0; i < rs.length; i ++ ) { if (rs[i].trim() === '' || rs[i].trim() === '\n') continue; // 空行直接忽略 - console.log('=> ', rs[i]); + // console.log('=> ', rs[i]); // 排除一下连自动字幕都没有的, 那一定是没有任何字幕可用 if (rs[i].match(/.*Available automatic captions for .*?:/)) { // ?表示非贪婪, 遇到冒号即停止 noAutoSub = false; // 排除即可, 全都是把整个字幕列表输出一遍, 这部分不需要捕获 @@ -207,22 +207,24 @@ function parseSubtitle(msg) { } // for j } // if } // for i - console.log('捕获到官方字幕:'); - console.log(JSON.stringify(officialSub, null, 2)); if (officialSub.length < 1) { // 没有官方字幕 if (noAutoSub) { // 没有任何字幕 console.log('没有任何字幕'); - } else { // 没有官方字幕但是有自动生成字幕 + return []; + } else { // 没有官方字幕但是有自动生成字幕, 可以自动翻译为任何字幕 console.log('有自动生成字幕'); + return ['auto']; } } else { // 有官方字幕, 同时可以自动翻译为任何字幕 console.log('有官方字幕'); + console.log(JSON.stringify(officialSub, null, 0)); + return officialSub; } } catch (error) { console.log(error); // npm 命令无法捕获error错误流 } - return {}; + return []; } /** diff --git a/webapps/index.html b/webapps/index.html index a97c08a..84c533e 100755 --- a/webapps/index.html +++ b/webapps/index.html @@ -44,12 +44,43 @@ flex-direction: column; align-items: center; } + + .available { + color: mediumseagreen; + margin: 20px 0; + font-size: 120%; + } + + .btn-google-sub { + display: inline-block; + cursor: pointer; + user-select: none; + padding: 10px 20px; + background: mediumorchid; + } + + .btn-google-sub:active { + color: white; + background: black; + } + + + + + + + + + + + + +
+
Youtube在线解析 -- BiliBili模式
+
+ + + +
+
+ +
+
+ +
+
+ + + +
+

《更新日志》

+

1:支持下载外挂字幕文件

+

2: 请按Ctrl+Shift+R强制刷新缓存

+

✩   您的Star和Fork是对开发者最大的支持!

+
+ +
+

服务器正在处理...

+
+ + + diff --git a/webapps/index.html b/webapps/index.html index 42261a4..87e18e7 100755 --- a/webapps/index.html +++ b/webapps/index.html @@ -275,6 +275,13 @@ parse = fun => { $("#divResult").fadeOut() var url = $('input#url')[0].value + + if (url.match(/https?:\/\/(www\.)?bilibili\.com\/video\/([\w\d]){11,14}$/)) { // 匹配B站视频 + // window.document.location.href = `./bilibili.html?url=${encodeURIComponent(url)}`; + window.document.location.href = `./bilibili.html?url=${url}`; + return; + } + var id = Develon.notifyID // 获取即将弹出的通知框ID var parseRequest = $.ajax({ url: "/y2b/parse?" + encodeURIComponent(url.replace('youtube', 'y2b').replace('youtu', 'y2')), @@ -442,7 +449,7 @@
-
Youtube在线解析
+
Youtube在线解析
@@ -452,7 +459,7 @@
- +
From 551e0c48dd3bde70ebf024ae130370fd7874d926 Mon Sep 17 00:00:00 2001 From: develon2015 Date: Mon, 12 Oct 2020 14:25:21 +0800 Subject: [PATCH 30/61] BiliBili --- .gitignore | 1 + README.md | 2 -- index.js | 46 +++++++++++++++++++++++++++++++++++++++++++ webapps/bilibili.html | 16 +++++++++------ webapps/index.html | 8 ++++---- 5 files changed, 61 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 6cb772b..73ca78c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules tmp +bilibili diff --git a/README.md b/README.md index 97d7059..ceda9f4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # Youtube-dl-REST -## 概要 - 通过本项目,您可以搭建一个网页,快速下载您中意的Youtube视频。 在线地址:[https://y2b.123345.xyz](https://y2b.123345.xyz) diff --git a/index.js b/index.js index 71eabe3..615b291 100644 --- a/index.js +++ b/index.js @@ -68,6 +68,29 @@ function main() { thread.postMessage({ op: 'parse', url, videoID: mr[1] }); }); + // 解析B站视频 + app.get('/bili/parse', (req, res) => { + let url = req._parsedUrl.query; + url = decodeURIComponent(url); // URI解码 + console.log({ op: '解析(B站):', url }); + + if (!url.match(/^https?:\/\/(www\.|m\.)?bilibili\.com\/video\/[\w\d]{11,14}$/)) { // 检查URL合法性 + console.log(`不合法的B站视频地址: ${url}`); + res.send({ + "error": 'B站视频URL示例:

https://www.bilibili.com/
video/BV1xxxxxxxxx', + "success": false, + }); + } + checkDisk(); // 解析视频前先检查磁盘空间 + + let thread = new worker_threads.Worker(__filename); + thread.once('message', msg => { + // console.log(JSON.stringify(msg, null, 1)); + res.send(msg); + }); + thread.postMessage({ op: 'bili/parse', url, }); + }); + let queue = []; app.get('/y2b/download', (req, res) => { let { v, format, recode, subs } = req.query; @@ -309,6 +332,29 @@ function task() { }); break; } // case subtitle end + + case 'bili-parse': { + try { + let id = msg.url.match(/.*video\/([\w\d]+)$/)[1]; + let fullpath = `${__dirname}/bilibili/${id}`; + // let cmd_write_info = `youtube-dl -o '${fullpath}/%(id)s/flv.%(ext)s' '${msg.url}' --skip-download --write-info`; + let cmd_write_info = `youtube-dl -o '${fullpath}/flv.%(ext)s' '${msg.url}' --skip-download --write-info`; + let file_info = `${fullpath}/flv.info.json`; + child_process.execSync(cmd_write_info); + let info = JSON.parse(fs.readFileSync(file_info).toString()); + let { uploader, title, thumbnail, filesize, duration } = info; + worker_threads.parentPort.postMessage({ + success: true, + ...{ uploader, title, thumbnail, filesize, duration }, + }); + } catch (error) { + worker_threads.parentPort.postMessage({ + success: false, + error: '解析失败!', + }); + } + } // case bili-parse end + case 'parse': { let audios = [], videos = []; let bestAudio = {}, bestVideo = {}; diff --git a/webapps/bilibili.html b/webapps/bilibili.html index ba9894c..1797e1e 100755 --- a/webapps/bilibili.html +++ b/webapps/bilibili.html @@ -82,7 +82,7 @@ $(() => { let query = new URL(document.location.href).searchParams.get('url'); url.value = query; - document.querySelector('form').submit(); + query && document.querySelector('form').submit(); }) @@ -276,15 +276,19 @@ $("#divResult").fadeOut() var url = $('input#url')[0].value - // if (!url.match(/https?:\/\/(www\.)?bilibili\.com\/video\/BV1[\w\d]{8,10}/)) { // 匹配B站视频 - if (!url.match(/https?:\/\/(www\.)?bilibili\.com\/video\/[\w\d]{11,14}/)) { // 匹配B站视频 - Develon.notify('B站视频URL示例:

https://www.bilibili.com/
video/BV1iKxxxh7pH'); + if (url.match(/.*?youtu.*/)) { // 匹配油管视频 + window.document.location.href = `./?url=${url}`; + return; + } + // if (!url.match(/^https?:\/\/(www\.|m\.)?bilibili\.com\/video\/BV1[\w\d]{8,10}$/)) { // 匹配B站视频 + if (!url.match(/^https?:\/\/(www\.|m\.)?bilibili\.com\/video\/[\w\d]{11,14}$/)) { // 匹配B站视频 + Develon.notify('B站视频URL示例:

https://www.bilibili.com/
video/BV1xxxxxxxxx'); return; } var id = Develon.notifyID // 获取即将弹出的通知框ID var parseRequest = $.ajax({ - url: "/y2b/parse?" + encodeURIComponent(url.replace('youtube', 'y2b').replace('youtu', 'y2')), + url: "/bili/parse?" + encodeURIComponent(url), success: fun => { if (fun.success === false) { Develon.notify(fun.error) @@ -449,7 +453,7 @@
-
Youtube在线解析 -- BiliBili模式
+
Youtube在线解析
diff --git a/webapps/index.html b/webapps/index.html index 87e18e7..9e5390e 100755 --- a/webapps/index.html +++ b/webapps/index.html @@ -80,9 +80,9 @@ test = false; window.sub_type = 'native'; // 字幕类型 $(() => { - if (!!!test) return; - url.value = 'https://www.youtube.com/watch?v=XXX'; - document.querySelector('form').submit(); + let query = new URL(document.location.href).searchParams.get('url'); + url.value = query; + query && document.querySelector('form').submit(); }) @@ -276,7 +276,7 @@ $("#divResult").fadeOut() var url = $('input#url')[0].value - if (url.match(/https?:\/\/(www\.)?bilibili\.com\/video\/([\w\d]){11,14}$/)) { // 匹配B站视频 + if (url.match(/^https?:\/\/(www\.|m\.)?bilibili\.com\/video\/([\w\d]){11,14}$/)) { // 匹配B站视频 // window.document.location.href = `./bilibili.html?url=${encodeURIComponent(url)}`; window.document.location.href = `./bilibili.html?url=${url}`; return; From 2ab986185916d9aeadcec66d42363f5a34b617af Mon Sep 17 00:00:00 2001 From: develon2015 Date: Mon, 12 Oct 2020 17:57:29 +0800 Subject: [PATCH 31/61] bilibili --- index.js | 102 ++++++++++- webapps/bilibili.html | 383 +++++------------------------------------- webapps/index.html | 9 +- 3 files changed, 148 insertions(+), 346 deletions(-) diff --git a/index.js b/index.js index 615b291..9ff6b04 100644 --- a/index.js +++ b/index.js @@ -32,7 +32,16 @@ function main() { if (!isBlackIP) next(); }); app.use('/', express.static(`${__dirname}/webapps`)); - app.use('/file', (req, res, next) => { + // app.use('/bili_file', (req, res, next) => { + // console.log(`下载${req.url}`); + // let info = fs.readFileSync(`${__dirname}/tmp/${req.url.replace(/\.\w+$/, '.info.json')}`).toString(); + // info = JSON.parse(info); + // console.log({'标题': info.title}); // or 'fulltitle' + // let ext = req.url.match(/.*(\.\w+)$/)[1]; + // res.set({'Content-Disposition': `attachment; filename="${encodeURI(info.title + ext)}"; filename*=UTF-8''${encodeURI(info.title + ext)}`}); + // next(); + // }); + app.use('/file', (req, res, next) => { console.log(`下载${req.url}`); let info = fs.readFileSync(`${__dirname}/tmp/${req.url.replace(/\.\w+$/, '.info.json')}`).toString(); info = JSON.parse(info); @@ -92,6 +101,43 @@ function main() { }); let queue = []; + app.get('/bili/download', (req, res) => { + let { url } = req.query; + url = decodeURIComponent(url); + + if (!url.match(/^https?:\/\/(www\.|m\.)?bilibili\.com\/video\/[\w\d]{11,14}$/)) { // 检查URL合法性 + console.log(`不合法的B站视频地址: ${url}`); + res.send({ + "error": 'B站视频URL示例:

https://www.bilibili.com/
video/BV1xxxxxxxxx', + "success": false, + }); + } + if (queue[JSON.stringify(req.query)] === undefined) { + checkDisk(); // 下载视频前先检查磁盘空间 + + queue[JSON.stringify(req.query)] = { + "success": true, + "result": { + "downloading": true, + "downloadSucceed": false, + "dest": "正在下载中", + "metadata": "" + } + }; + + let thread = new worker_threads.Worker(__filename); + thread.once('message', msg => { + // 下载成功或失败,更新queue + console.log('下载成功或失败,更新queue'); + console.log(JSON.stringify(msg, null, 1)); + queue[JSON.stringify(req.query)] = msg; + }); + thread.postMessage({ op: 'bili/download', url }); + } // if end + // 发送轮询结果 + res.send(queue[JSON.stringify(req.query)]); + }); // /bili/download end + app.get('/y2b/download', (req, res) => { let { v, format, recode, subs } = req.query; if (!!!v.match(/^[\w-]{11}$/)) @@ -333,19 +379,20 @@ function task() { break; } // case subtitle end - case 'bili-parse': { + case 'bili/parse': { // 解析, 生成bilibili/{id}/flv.info.json try { let id = msg.url.match(/.*video\/([\w\d]+)$/)[1]; let fullpath = `${__dirname}/bilibili/${id}`; // let cmd_write_info = `youtube-dl -o '${fullpath}/%(id)s/flv.%(ext)s' '${msg.url}' --skip-download --write-info`; let cmd_write_info = `youtube-dl -o '${fullpath}/flv.%(ext)s' '${msg.url}' --skip-download --write-info`; let file_info = `${fullpath}/flv.info.json`; + console.log('解析B站视频, 命令:', cmd_write_info); child_process.execSync(cmd_write_info); let info = JSON.parse(fs.readFileSync(file_info).toString()); - let { uploader, title, thumbnail, filesize, duration } = info; + let { webpage_url: url, uploader, title, thumbnail, filesize, duration } = info; worker_threads.parentPort.postMessage({ success: true, - ...{ uploader, title, thumbnail, filesize, duration }, + ...{ url, uploader, title, thumbnail, filesize, duration }, }); } catch (error) { worker_threads.parentPort.postMessage({ @@ -353,7 +400,8 @@ function task() { error: '解析失败!', }); } - } // case bili-parse end + break; + } // case bili/parse end case 'parse': { let audios = [], videos = []; @@ -440,6 +488,50 @@ format code extension resolution note break; } + case 'bili/download': { + try { + let { url } = msg; + let id = msg.url.match(/.*video\/([\w\d]+)$/)[1]; + let fullpath = `${__dirname}/bilibili/${id}`; + let cmd_download = `youtube-dl -o '${fullpath}/${id}.%(ext)s' '${url}'`; + console.log('下载B站视频, 命令:', cmd_download); + child_process.execSync(cmd_download); + let dest = 'Unknown dest'; + worker_threads.parentPort.postMessage({ + "success": true, + "result": { + "v": videoID, + "downloading": false, + "downloadSucceed": true, + "dest": `bili_file/bilibili/${id}/${id}.flv`, + "metadata": '', + }, + }); + } catch (error) { + let cause = 'Unknown cause'; + console.log({error}); + error.toString().split('\n').forEach(it => { + console.log(it); + let mr = it.match(/^.*(ERROR.*)$/); + if (!!mr) { + cause = mr[1]; + } + }); + worker_threads.parentPort.postMessage({ + "success": true, + "result": { + "v": "demoVideoID", + "downloading": false, + "downloadSucceed": false, + "dest": "下载失败", + "metadata": cause + } + }); + } // end of try + + break; + } + case 'download': { let { videoID, format, recode, subs } = msg; // subs字幕内封暂未实现 const path = `${videoID}/${format}`; diff --git a/webapps/bilibili.html b/webapps/bilibili.html index 1797e1e..7a52206 100755 --- a/webapps/bilibili.html +++ b/webapps/bilibili.html @@ -19,14 +19,16 @@ } table th { - background-color: #ccc; + background-color: #eee; + color: mediumseagreen; width: 200px; padding: 0; margin: 0; } table td { - background-color: aquamarine; + background-color: mediumseagreen; + color: white; padding: 0; margin: 0; } @@ -51,7 +53,7 @@ font-size: 120%; } - .btn-google-sub { + .button { display: inline-block; cursor: pointer; user-select: none; @@ -59,14 +61,10 @@ background: mediumorchid; } - .btn-google-sub:active { + .button:active { color: white; background: black; } - - #wait_subtitle { - display: none; - } @@ -77,199 +75,40 @@ @@ -119,7 +119,7 @@ var url = $('input#url')[0].value if (url.match(/.*?youtu.*/)) { // 匹配油管视频 - window.document.location.href = `./?url=${url}`; + window.document.location.href = `./?url=${encodeURIComponent(url.replace('youtube', 'y2b').replace('youtu', 'y2'))}`; return; } // if (!url.match(/^https?:\/\/(www\.|m\.)?bilibili\.com\/video\/BV1[\w\d]{8,10}$/)) { // 匹配B站视频 diff --git a/webapps/index.html b/webapps/index.html index 7acd955..ab83232 100755 --- a/webapps/index.html +++ b/webapps/index.html @@ -82,6 +82,7 @@ window.sub_type = 'native'; // 字幕类型 $(() => { let query = new URL(document.location.href).searchParams.get('url'); + query = decodeURIComponent(url.replace('y2b', 'youtube').replace('y2', 'youtu')); // 还原y2b视频地址 url.value = query; query && document.querySelector('form').submit(); }) From ca487af156134ba5c7f394b593598b1f4412fc05 Mon Sep 17 00:00:00 2001 From: develon2015 Date: Tue, 13 Oct 2020 10:02:52 +0800 Subject: [PATCH 37/61] parsedTitle.flv --- webapps/bilibili.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapps/bilibili.html b/webapps/bilibili.html index affc17e..1e23d9b 100755 --- a/webapps/bilibili.html +++ b/webapps/bilibili.html @@ -111,7 +111,7 @@ }); // 存储标题 - window.parsedTitle = r.title; + window.parsedTitle = `${r.title}.flv`; } parse = fun => { From a875eecb7788b8cb6291c415f1f538bd66e38bc7 Mon Sep 17 00:00:00 2001 From: develon2015 Date: Tue, 13 Oct 2020 10:04:43 +0800 Subject: [PATCH 38/61] =?UTF-8?q?=E8=BF=98=E5=8E=9Fy2b=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webapps/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapps/index.html b/webapps/index.html index ab83232..bb7e856 100755 --- a/webapps/index.html +++ b/webapps/index.html @@ -82,7 +82,7 @@ window.sub_type = 'native'; // 字幕类型 $(() => { let query = new URL(document.location.href).searchParams.get('url'); - query = decodeURIComponent(url.replace('y2b', 'youtube').replace('y2', 'youtu')); // 还原y2b视频地址 + query = decodeURIComponent(query.replace('y2b', 'youtube').replace('y2', 'youtu')); // 还原y2b视频地址 url.value = query; query && document.querySelector('form').submit(); }) From f7dd3cb29072375d5ccc343b5ed0e8cb6c19fff8 Mon Sep 17 00:00:00 2001 From: develon2015 Date: Tue, 13 Oct 2020 10:09:51 +0800 Subject: [PATCH 39/61] README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ceda9f4..a7348a7 100644 --- a/README.md +++ b/README.md @@ -71,5 +71,6 @@ npm start ##### 后来 1. 添加外挂字幕下载功能 +2. 支持解析BiliBili From 2ad40a0656f8ca1f5fae3ce325806c26035b96ba Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Tue, 13 Oct 2020 21:18:09 +0800 Subject: [PATCH 40/61] up --- webapps/bilibili.html | 2 +- webapps/index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webapps/bilibili.html b/webapps/bilibili.html index 1e23d9b..e6c52da 100755 --- a/webapps/bilibili.html +++ b/webapps/bilibili.html @@ -106,7 +106,7 @@ //$("#divResult").css("display", "block") $("#divResult").fadeIn(); - $("span#recode").bind("click", fun => { + $("span#recode").off('click').bind("click", fun => { postDownload(`/bili/download?url=${ encodeURIComponent(r.url) }`); }); diff --git a/webapps/index.html b/webapps/index.html index bb7e856..b3ff03d 100755 --- a/webapps/index.html +++ b/webapps/index.html @@ -269,7 +269,7 @@ //$("#divResult").css("display", "block") $("#divResult").fadeIn() - $("span#recode").bind("click", fun => { + $("span#recode").off('click').bind("click", fun => { download(null, `/y2b/download?v=${ res.v }`) // got v, select a, v format & recode ($("table input:checked")) }) } From 4e605658eba1d7042cd227eb7bb0448d7c204bfa Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Tue, 13 Oct 2020 21:35:47 +0800 Subject: [PATCH 41/61] blacked --- webapps/bilibili.html | 2 +- webapps/index.html | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/webapps/bilibili.html b/webapps/bilibili.html index e6c52da..1340859 100755 --- a/webapps/bilibili.html +++ b/webapps/bilibili.html @@ -217,7 +217,7 @@
-
Youtube在线解析
+
Youtube&BiliBili 在线解析
diff --git a/webapps/index.html b/webapps/index.html index b3ff03d..9882c4d 100755 --- a/webapps/index.html +++ b/webapps/index.html @@ -275,6 +275,9 @@ } parse = fun => { + if (window.blacked === 1) { + Develon.notify('由于服务器请求次数过多
服务器IP已被Youtube拉黑

请等待解封
你还可以自行部署或使用B站'); + } $("#divResult").fadeOut() var url = $('input#url')[0].value @@ -451,7 +454,7 @@
-
Youtube在线解析
+
Youtube&BiliBili 在线解析
@@ -540,6 +543,10 @@

服务器正在处理...

+ + From f01d52b14230224c84cdf1eb73f79a4f56f50a69 Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Tue, 13 Oct 2020 21:37:50 +0800 Subject: [PATCH 42/61] up --- webapps/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapps/index.html b/webapps/index.html index 9882c4d..72d56cb 100755 --- a/webapps/index.html +++ b/webapps/index.html @@ -78,7 +78,7 @@ From 76d0ebe896fb01cb464a7d04e4164c29402b2772 Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Tue, 13 Oct 2020 21:42:30 +0800 Subject: [PATCH 43/61] up --- index.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/index.js b/index.js index 9e64032..f7b03e2 100644 --- a/index.js +++ b/index.js @@ -12,6 +12,16 @@ main 主线程 ========================================================================================*/ function main() { let app = new express(); + app.use('/y2b', (req, res, next) => { + if (false) { + res.send({ + success: false, + error: `由于服务器请求次数过多
服务器IP已被Youtube拉黑

请等待解封
你还可以自行部署或使用B站`, + }); + } else { + next(); + } + }); app.use((req, res, next) => { console.log(`${getRemoteIP(req)}\t=> ${req.url}`); let isBlackIP = false; From dc2d10099f9328c807125e7c2cc9f2acbe80d54d Mon Sep 17 00:00:00 2001 From: Develon2015 <302615249@qq.com> Date: Wed, 14 Oct 2020 10:13:03 +0800 Subject: [PATCH 44/61] get IP --- get-remote-ip.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/get-remote-ip.js b/get-remote-ip.js index 0d4b791..3546d40 100755 --- a/get-remote-ip.js +++ b/get-remote-ip.js @@ -1,5 +1,5 @@ function getRemoteIP(request) { - return request.header('cf-connecting-ip') || '未知IP'; + return request.header('cf-connecting-ip') || request.ip || '未知IP'; } module.exports = getRemoteIP; From 3a37cb1b280f1d4b75e1830c64b15b1e3d352d5a Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Sat, 17 Oct 2020 18:13:01 +0800 Subject: [PATCH 45/61] Content-Disposition --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index f7b03e2..3ba8389 100644 --- a/index.js +++ b/index.js @@ -57,7 +57,7 @@ function main() { info = JSON.parse(info); console.log({'标题': info.title}); // or 'fulltitle' let ext = req.url.match(/.*(\.\w+)$/)[1]; - res.set({'Content-Disposition': `attachment; filename="${encodeURI(info.title + ext)}"; filename*=UTF-8''${encodeURI(info.title + ext)}`}); + res.set({'Content-Disposition': `attachment; filename="${encodeURIComponent(info.title + ext)}"; filename*=UTF-8''${encodeURI(info.title + ext)}`}); next(); }); app.use('/file', express.static(`${__dirname}/tmp`)); From 14f2e028b452d7b5fa64c9b8b3ed61f8c70e8088 Mon Sep 17 00:00:00 2001 From: develon_cyg Date: Sun, 18 Oct 2020 01:45:07 +0800 Subject: [PATCH 46/61] package.json --- package.json | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 0019e0d..cb08079 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,12 @@ { - "name": "Youtube-dl-REST-node", + "name": "youtube-dl-rest", "version": "1.0.0", "description": "Youtube-dl-REST By Node.js", - "main": "index.js", "scripts": { - "start": "/usr/bin/env node index.js" + "start:dev": "nodemon index.js", + "start": "node index.js" }, - "keywords": [], - "author": "develon", - "license": "ISC", + "license": "MIT", "dependencies": { "express": "^4.17.1" } From de38327fd0193a35b8aac59f8c66147bf0baa32e Mon Sep 17 00:00:00 2001 From: Develon <302615249@qq.com> Date: Tue, 3 Nov 2020 09:38:46 +0800 Subject: [PATCH 47/61] =?UTF-8?q?youtube-dl=E6=83=A8=E9=81=ADDMCA=E5=88=B6?= =?UTF-8?q?=E8=A3=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a7348a7..964e76a 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ sudo snap install node --classic --channel=14 node -v ``` -### 2.安装[youtube-dl](https://github.com/ytdl-org/youtube-dl)和[FFmpeg](https://github.com/FFmpeg/FFmpeg) +### 2.安装[youtube-dl](https://youtube-dl.org/)和[FFmpeg](https://github.com/FFmpeg/FFmpeg) 确保`youtube-dl`命令和`ffmpeg`命令可用: ``` From dfc902d2239d1d614910b734eb7ffab86cc33a55 Mon Sep 17 00:00:00 2001 From: Develon2015 <302615249@qq.com> Date: Tue, 1 Dec 2020 21:22:37 -0500 Subject: [PATCH 48/61] DISABLE --- index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 3ba8389..0a1ceb8 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,5 @@ +const DISABLE = 0 + const express = require('express'); const json = require('body-parser').json; const child_process = require('child_process'); @@ -13,7 +15,7 @@ main 主线程 function main() { let app = new express(); app.use('/y2b', (req, res, next) => { - if (false) { + if (DISABLE) { res.send({ success: false, error: `由于服务器请求次数过多
服务器IP已被Youtube拉黑

请等待解封
你还可以自行部署或使用B站`, @@ -607,4 +609,4 @@ if (worker_threads.isMainThread) main(); else task(); -/*======================================================================================*/ \ No newline at end of file +/*======================================================================================*/ From fa1b8c91926cdaeba549820fea49b63d85e0cb52 Mon Sep 17 00:00:00 2001 From: kasumi Date: Mon, 11 Jan 2021 22:09:35 +0800 Subject: [PATCH 49/61] rm bilibili --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 0a1ceb8..705bbeb 100644 --- a/index.js +++ b/index.js @@ -237,7 +237,7 @@ function main() { // /dev/sda2 39G 19G 19G 51% / let mr = it.match(/.*\s(\d+)%/); if (!!mr && Number.parseInt(mr[1]) > 90) { - let cmd = `rm -r '${__dirname}/tmp'`; + let cmd = `rm -r '${__dirname}/tmp' '${__dirname}/bilibili`; console.log({ '清理空间': cmd }); child_process.execSync(cmd); queue = []; From d2345b0fe166b9d0dccc52cb597acfe109df1cc4 Mon Sep 17 00:00:00 2001 From: Develon2015 <302615249@qq.com> Date: Mon, 8 Mar 2021 21:04:14 -0500 Subject: [PATCH 50/61] rm --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 705bbeb..17d0740 100644 --- a/index.js +++ b/index.js @@ -237,7 +237,7 @@ function main() { // /dev/sda2 39G 19G 19G 51% / let mr = it.match(/.*\s(\d+)%/); if (!!mr && Number.parseInt(mr[1]) > 90) { - let cmd = `rm -r '${__dirname}/tmp' '${__dirname}/bilibili`; + let cmd = `rm -r '${__dirname}/tmp' '${__dirname}/bilibili'`; console.log({ '清理空间': cmd }); child_process.execSync(cmd); queue = []; From 4a7e85a9c64719b78779d78681ae9974e6d0e66a Mon Sep 17 00:00:00 2001 From: qcloud Date: Thu, 28 Sep 2023 16:51:07 +0800 Subject: [PATCH 51/61] mv --- {webapps => static}/bilibili.html | 0 {webapps => static}/css/style.css | 0 {webapps => static}/favicon.ico | Bin {webapps => static}/index.html | 0 {webapps => static}/js/jquery.js | 0 {webapps => static}/js/libjrt.js | 0 {webapps => static}/js/loadbar.js | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename {webapps => static}/bilibili.html (100%) rename {webapps => static}/css/style.css (100%) rename {webapps => static}/favicon.ico (100%) rename {webapps => static}/index.html (100%) rename {webapps => static}/js/jquery.js (100%) rename {webapps => static}/js/libjrt.js (100%) rename {webapps => static}/js/loadbar.js (100%) diff --git a/webapps/bilibili.html b/static/bilibili.html similarity index 100% rename from webapps/bilibili.html rename to static/bilibili.html diff --git a/webapps/css/style.css b/static/css/style.css similarity index 100% rename from webapps/css/style.css rename to static/css/style.css diff --git a/webapps/favicon.ico b/static/favicon.ico similarity index 100% rename from webapps/favicon.ico rename to static/favicon.ico diff --git a/webapps/index.html b/static/index.html similarity index 100% rename from webapps/index.html rename to static/index.html diff --git a/webapps/js/jquery.js b/static/js/jquery.js similarity index 100% rename from webapps/js/jquery.js rename to static/js/jquery.js diff --git a/webapps/js/libjrt.js b/static/js/libjrt.js similarity index 100% rename from webapps/js/libjrt.js rename to static/js/libjrt.js diff --git a/webapps/js/loadbar.js b/static/js/loadbar.js similarity index 100% rename from webapps/js/loadbar.js rename to static/js/loadbar.js From fa53dc7c293ec6cf9206e7304df27f77c557c857 Mon Sep 17 00:00:00 2001 From: qcloud Date: Thu, 28 Sep 2023 16:53:29 +0800 Subject: [PATCH 52/61] yt-dlp --- config.json | 2 +- doc/subtitle.md | 122 ---------------------------------------------- index.js | 118 ++++++++++++++++++++------------------------ static/index.html | 70 ++++++++++++++++++-------- 4 files changed, 102 insertions(+), 210 deletions(-) delete mode 100755 doc/subtitle.md diff --git a/config.json b/config.json index 6784681..1d33fe5 100644 --- a/config.json +++ b/config.json @@ -3,5 +3,5 @@ "port": 80, "cookie": "cookies.txt", "blacklist": "blacklist.txt", - "mode": "演示模式" + "mode": "非演示模式(演示模式关闭转码功能)" } diff --git a/doc/subtitle.md b/doc/subtitle.md deleted file mode 100755 index 3dd70da..0000000 --- a/doc/subtitle.md +++ /dev/null @@ -1,122 +0,0 @@ -字幕下载. - -Subtitle Options: ---write-sub Write subtitle file ---write-auto-sub Write automatically generated subtitle file - (YouTube only) ---all-subs Download all the available subtitles of the - video--list-subs List all available subtitles for the video ---sub-format FORMAT Subtitle format, accepts formats - preference, for example: "srt" or "ass/srt/best" ---sub-lang LANGS Languages of the subtitles to download - (optional) separated by commas, use --list- - subs for available language tags - -其它选项: ---embed-subs Embed subtitles in the video (only for mp4, webm and mkv videos) ---embed-subs 在视频中嵌入字幕(仅适用于mp4,webm和mkv视频) ---convert-subs FORMAT Convert the subtitles to other format (currently supported: srt|ass|vtt|lrc) ---convert-subs FORMAT 将字幕转换为其他格式(当前支持:srt | ass | vtt | lrc) - -首先, 我们可以使用--list-subs参数获取并解析可用字幕列表. - - -1. 无任何字幕: - -# youtube-dl --list-subs https://www.youtube.com/watch?v=YL0a1sc1lmE -[youtube] YL0a1sc1lmE: Downloading webpage -WARNING: video doesn't have subtitles -[youtube] YL0a1sc1lmE: Looking for automatic captions -WARNING: Couldn't find automatic captions for YL0a1sc1lmE -YL0a1sc1lmE has no automatic captions -YL0a1sc1lmE has no subtitles - - -2. 系统可自动生成日语字幕: -需要使用--write-auto-sub选项, 即谷歌翻译 -# youtube-dl --list-subs https://www.youtube.com/watch?v=1plxH_2lZ8o -[youtube] 1plxH_2lZ8o: Downloading webpage -WARNING: video doesn't have subtitles -[youtube] 1plxH_2lZ8o: Looking for automatic captions -Available automatic captions for 1plxH_2lZ8o: -Language formats -gu vtt, ttml, srv3, srv2, srv1 -zh-Hans vtt, ttml, srv3, srv2, srv1 -zh-Hant vtt, ttml, srv3, srv2, srv1 -... -1plxH_2lZ8o has no subtitles - -小文件: -https://www.youtube.com/watch?v=-E5KUTt7mGE - - -3. 自带某些字幕, 同时可翻译其它语言(存在一个问题, 源和目标如何选择? 很遗憾, 无法选择源): - -# youtube-dl --list-subs https://www.youtube.com/watch?v=AVlaVkH9AQE -[youtube] AVlaVkH9AQE: Downloading webpage -[youtube] AVlaVkH9AQE: Looking for automatic captions -Available automatic captions for AVlaVkH9AQE: -Language formats -gu vtt, ttml, srv3, srv2, srv1 -zh-Hans vtt, ttml, srv3, srv2, srv1 -zh-Hant vtt, ttml, srv3, srv2, srv1 -... -Available subtitles for AVlaVkH9AQE: -Language formats -ja vtt, ttml, srv3, srv2, srv1 -root@ubuntu:~# youtube-dl --list-subs https://www.youtube.com/watch?v=YL0a1sc1lmE -[youtube] YL0a1sc1lmE: Downloading webpage -WARNING: video doesn't have subtitles -[youtube] YL0a1sc1lmE: Looking for automatic captions -WARNING: Couldn't find automatic captions for YL0a1sc1lmE -YL0a1sc1lmE has no automatic captions -YL0a1sc1lmE has no subtitles - -小文件: -https://www.youtube.com/watch?v=uDEk5wvTbZ8 -多字幕文件: -https://www.youtube.com/watch?v=MruC4eV4LGs - -https://www.youtube.com/watch?v=EiKK04Ht8QI - - -如何单独下载某些字幕文件? - -注意有--write-sub和--write-auto-sub两条通道, 不可交叉选择 -但是自动翻译是万能的, 因为可以二次翻译 - -# youtube-dl https://www.youtube.com/watch?v=uDEk5wvTbZ8 --write-auto-sub --skip-download --sub-lang ja,en -[youtube] uDEk5wvTbZ8: Downloading webpage -[youtube] uDEk5wvTbZ8: Looking for automatic captions -[info] Writing video subtitles to: 测试YouTube字幕-uDEk5wvTbZ8.en.vtt -[info] Writing video subtitles to: 测试YouTube字幕-uDEk5wvTbZ8.ja.vtt - */ - - - -// 嵌入视频的字幕, 在视频中嵌入字幕(仅适用于mp4,webm和mkv视频) - -youtube-dl https://www.youtube.com/watch?v=AVlaVkH9AQE --write-sub --embed-subs --convert-subs srt -[youtube] AVlaVkH9AQE: Downloading webpage -[info] Writing video subtitles to: 清水翔太『My Boo』のアンサーソング!!當山みれい『Dear My Boo』-AVlaVkH9AQE.ja.vtt -WARNING: Requested formats are incompatible for merge and will be merged into mkv. -[download] Destination: 清水翔太『My Boo』のアンサーソング!!當山みれい『Dear My Boo』-AVlaVkH9AQE.f137.mp4 -[download] 100% of 46.93MiB in 00:00 -[download] Destination: 清水翔太『My Boo』のアンサーソング!!當山みれい『Dear My Boo』-AVlaVkH9AQE.f251.webm -[download] 100% of 4.49MiB in 00:00 -[ffmpeg] Merging formats into "清水翔太『My Boo』のアンサーソング!!當山みれい『Dear My Boo』-AVlaVkH9AQE.mkv" -Deleting original file 清水翔太『My Boo』のアンサーソング!!當山みれい『Dear My Boo』-AVlaVkH9AQE.f137.mp4 (pass -k to keep) -Deleting original file 清水翔太『My Boo』のアンサーソング!!當山みれい『Dear My Boo』-AVlaVkH9AQE.f251.webm (pass -k to keep) -[ffmpeg] Converting subtitles -Deleting original file 清水翔太『My Boo』のアンサーソング!!當山みれい『Dear My Boo』-AVlaVkH9AQE.ja.vtt (pass -k to keep) -[ffmpeg] Embedding subtitles in '清水翔太『My Boo』のアンサーソング!!當山みれい『Dear My Boo』-AVlaVkH9AQE.mkv' -Deleting original file 清水翔太『My Boo』のアンサーソング!!當山みれい『Dear My Boo』-AVlaVkH9AQE.ja.srt (pass -k to keep) - -youtube-dl https://www.youtube.com/watch?v=uDEk5wvTbZ8 --write-auto-sub --embed-subs --covert-subs srt --sub-lang zh-Hant,en,ja - -// --skip-download skip音视频文件下载 - - -# 限制 - -1. 只能在Webm文件中嵌入WebVTT字幕 diff --git a/index.js b/index.js index 17d0740..09b296f 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,7 @@ const child_process = require('child_process'); const worker_threads = require('worker_threads'); const fs = require('fs'); const getRemoteIP = require('./get-remote-ip.js'); +const http = require('https'); const config = require('./config.json'); // 加载配置文件 @@ -43,7 +44,7 @@ function main() { } if (!isBlackIP) next(); }); - app.use('/', express.static(`${__dirname}/webapps`)); + app.use('/', express.static(`${__dirname}/static`)); // app.use('/bili_file', (req, res, next) => { // console.log(`下载${req.url}`); // let info = fs.readFileSync(`${__dirname}/tmp/${req.url.replace(/\.\w+$/, '.info.json')}`).toString(); @@ -222,6 +223,20 @@ function main() { thread.postMessage({ op: 'subtitle', id, locale, ext, type }); }); // /youtube/subtitle end + app.get('/pxy', (req, res) => { + let url = req.query.url; + if (!url.startsWith('https://i.ytimg.com/')) { + res.status(403).end(); + } + http.get(url, (response) => { + res.writeHead(response.statusCode, response.statusMessage, response.headers); + response.pipe(res); + }).on('error', (err) => { + console.log(err); + res.status(502).end(); + }); + }); + app.listen(config.port, config.address, () => { console.log('服务已启动'); }); @@ -255,23 +270,24 @@ function main() { Worker ========================================================================================*/ function getAudio(id, format, rate, info, size) { - return { id, format, rate, info, size }; + return { id, format, rate: rate == 0 ? '未知' : rate, info, size: size == 0 ? '未知' : size }; } function getVideo(id, format, scale, frame, rate, info, size) { - return { id, format, scale, frame, rate, info, size }; + return { id, format, scale, frame, rate: rate == 0 ? '未知' : rate, info, size: size == 0 ? '未知' : size }; } /** * 在以下形式的字符串中捕获字幕: - * Language formats <= 返回0, 继续 + * Language Name Formats <= 返回0, 继续 * gu vtt, ttml, srv3, srv2, srv1 * zh-Hans vtt, ttml, srv3, srv2, srv1 + * en English vtt, ttml, srv3, srv2, srv1, json3 * 其它形式一律视为终结符, 返回-1, 终结 * @param {String} line */ function catchSubtitle(line) { - if (line.match(/^Language formats.*/)) return 0; + if (line.match(/^Language .*/)) return 0; let mr = line.match(/^([a-z]{2}(?:-[a-zA-Z]+)?).*/); if (mr) return mr[1]; return -1; @@ -283,7 +299,7 @@ function catchSubtitle(line) { */ function parseSubtitle(msg) { try { - let cmd = `youtube-dl --list-subs ${config.cookie !== undefined ? `--cookies "${config.cookie}"` : ''} '${msg.url}' 2> /dev/null` + let cmd = `yt-dlp --list-subs ${config.cookie !== undefined ? `--cookies "${config.cookie}"` : ''} '${msg.url}' 2> /dev/null` console.log(`解析字幕, 命令: ${cmd}`); let rs = child_process.execSync(cmd).toString().split(/(\r\n|\n)/); @@ -353,9 +369,9 @@ function task() { let fullpath = `${__dirname}/tmp/${id}`; // 字幕工作路径 let cmd_download = ''; if (type === 'native') // 原生字幕 - cmd_download = `youtube-dl --sub-lang '${locale}' -o '${fullpath}/%(id)s.%(ext)s' --write-sub --skip-download --write-info-json 'https://youtu.be/${id}' ${config.cookie !== undefined ? `--cookies ${config.cookie}` : ''}`; + cmd_download = `yt-dlp --sub-lang '${locale}' -o '${fullpath}/%(id)s.%(ext)s' --write-sub --skip-download --write-info-json 'https://youtu.be/${id}' ${config.cookie !== undefined ? `--cookies ${config.cookie}` : ''}`; else if (type === 'auto') // 切换翻译通道 - cmd_download = `youtube-dl --sub-lang '${locale}' -o '${fullpath}/%(id)s.%(ext)s' --write-auto-sub --skip-download --write-info-json 'https://youtu.be/${id}' ${config.cookie !== undefined ? `--cookies ${config.cookie}` : ''}`; + cmd_download = `yt-dlp --sub-lang '${locale}' -o '${fullpath}/%(id)s.%(ext)s' --write-auto-sub --skip-download --write-info-json 'https://youtu.be/${id}' ${config.cookie !== undefined ? `--cookies ${config.cookie}` : ''}`; console.log(`下载字幕, 命令: ${cmd_download}`); try { child_process.execSync(cmd_download); // 执行下载 @@ -365,10 +381,12 @@ function task() { let file = `${before}.${locale}.vtt`; // 下载的字幕一定是vtt格式 console.log('下载的字幕:', file); let file_convert = `${before}.${locale}${ext}`; // 要转换的字幕文件 - console.log('转换为:', file_convert); - let cmd_ffmpeg = `ffmpeg -i '${file}' '${file_convert}' -y`; // -y 强制覆盖文件 - console.log(`转换字幕, 命令: ${cmd_ffmpeg}`); - child_process.execSync(cmd_ffmpeg); + if (file != file_convert) { + console.log('转换为:', file_convert); + let cmd_ffmpeg = `ffmpeg -i '${file}' '${file_convert}' -y`; // -y 强制覆盖文件 + console.log(`转换字幕, 命令: ${cmd_ffmpeg}`); + child_process.execSync(cmd_ffmpeg); + } // info文件路径 let file_info = `${before}.info.json`; console.log('info文件:', file_info); @@ -381,7 +399,7 @@ function task() { success: true, title, // 返回标题 filename: `${title}.${locale}${ext}`, // 建议文件名 - text, // 字幕文本 + text: Buffer.from(text).toString('base64'), // 字幕文本,Base64 }); } catch(error) { // 下载过程出错 console.log(error); @@ -396,8 +414,8 @@ function task() { try { let id = msg.url.match(/.*video\/([\w\d]+)$/)[1]; let fullpath = `${__dirname}/bilibili/${id}`; - // let cmd_write_info = `youtube-dl -o '${fullpath}/%(id)s/flv.%(ext)s' '${msg.url}' --skip-download --write-info`; - let cmd_write_info = `youtube-dl -o '${fullpath}/flv.%(ext)s' '${msg.url}' --skip-download --write-info`; + // let cmd_write_info = `yt-dlp -o '${fullpath}/%(id)s/flv.%(ext)s' '${msg.url}' --skip-download --write-info`; + let cmd_write_info = `yt-dlp -o '${fullpath}/flv.%(ext)s' '${msg.url}' --skip-download --write-info`; let file_info = `${fullpath}/flv.info.json`; console.log('解析B站视频, 命令:', cmd_write_info); child_process.execSync(cmd_write_info); @@ -420,25 +438,13 @@ function task() { let audios = [], videos = []; let bestAudio = {}, bestVideo = {}; - let rs = []; + let rs = { title: '', thumbnail: '', formats: [] }; try { - if (true) - rs = child_process.execSync(`youtube-dl ${config.cookie !== undefined ? `--cookies ${config.cookie}` : ''} -F '${msg.url}' 2> /dev/null`).toString().split('\n'); - // 测试用数据 - else - rs = `[youtube] sbz3fOe7rog: Downloading webpage -[youtube] sbz3fOe7rog: Downloading video info webpage -[info] Available formats for sbz3fOe7rog: -format code extension resolution note -249 webm audio only tiny 59k , opus @ 50k (48000Hz), 1.50KB -251 webm audio only tiny 150k , opus @160k (48000Hz), 3.85MiB -250 webm audio only tiny 78k , opus @ 70k (48000Hz), 2.00MiB -140 m4a audio only tiny 129k , m4a_dash container, mp4a.40.2@128k (44100Hz), 3.47MiB -278 webm 256x144 144p 95k , webm container, vp9, 15fps, video only, 2.36MiB -160 mp4 256x144 144p 111k , avc1.4d400c, 15fps, video only, 2.95MiB -133 mp4 426x240 240p 247k , avc1.4d4015, 15fps, video only, 6.58MiB -242 webm 426x240 240p 162k , vp9, 15fps, video only, 2.62MiB -18 mp4 512x288 240p 355k , avc1.42001E, mp4a.40.2@ 96k (44100Hz), 9.58MiB (best)`.split('\n'); + let cmd = `yt-dlp --print-json --skip-download ${config.cookie !== undefined ? `--cookies ${config.cookie}` : ''} '${msg.url}' 2> /dev/null` + console.log('解析视频, 命令:', cmd); + rs = child_process.execSync(cmd).toString(); + rs = JSON.parse(rs); + console.log('解析完成:', rs.title, msg.url); } catch(error) { console.log(error.toString()); worker_threads.parentPort.postMessage({ @@ -447,40 +453,18 @@ format code extension resolution note }); } - rs.forEach(it => { - console.log(it); - let videoRegex = /^(\d+)\s+(\w+)\s+(\d+x\d+)\s+(\d+)p\s+(\d+)k , (.*), video only, (.+)MiB$/; - let mr = it.match(videoRegex); - if (!!mr) { - let video = getVideo(mr[1], mr[2], mr[3], mr[4], mr[5], mr[6], mr[7]); - return videos.push(video); - } - - videoRegex = /^(\d+)\s+(\w+)\s+(\d+x\d+)\s+(\d+)p\s+(\d+)k , (.*), (.+)MiB.+best.+$/; - mr = it.match(videoRegex); - if (!!mr) { - let video = getVideo(mr[1], mr[2], mr[3], mr[4], mr[5], mr[6], mr[7]); - return videos.push(video); - } - - videoRegex = /^(\d+)\s+(\w+)\s+(\d+x\d+)\s+(?:[^,]+)\s+(\d+)k , (.*), video.*$/; - mr = it.match(videoRegex); - if (!!mr) { - let video = getVideo(mr[1], mr[2], mr[3], 0, mr[4], mr[5], '未知'); - return videos.push(video); - } - - let audioRegex = /^(\d+)\s+(\w+)\s+audio only.*\s+(\d+)k , (.*),\s+(?:(.+)MiB|.+)$/; - mr = it.match(audioRegex); - if (!!mr) { - let audio = getAudio(mr[1], mr[2], mr[3], mr[4], mr[5] || '未知'); - return audios.push(audio); + // break; + rs.formats.forEach(it => { + if (it.audio_ext != 'none') { + audios.push(getAudio(it.format_id, it.ext, (it.abr || 0).toFixed(0), it.format_note, ((it.filesize || 0) / 1024 / 1024).toFixed(2))) + } else if (it.video_ext != 'none') { + videos.push(getVideo(it.format_id, it.ext, it.resolution, it.height, (it.vbr || 0).toFixed(0), it.format_note || '', ((it.filesize || 0) / 1024 / 1024).toFixed(2))); } }); // sort - audios.sort((a, b) => a.rate - b.rate); - videos.sort((a, b) => a.rate - b.rate); + // audios.sort((a, b) => a.rate - b.rate); + // videos.sort((a, b) => a.rate - b.rate); bestAudio = audios[audios.length - 1]; bestVideo = videos[videos.length - 1]; @@ -490,6 +474,8 @@ format code extension resolution note "success": true, "result": { "v": msg.videoID, + "title": rs.title, + "thumbnail": rs.thumbnail, "best": { "audio": bestAudio, "video": bestVideo, @@ -506,7 +492,7 @@ format code extension resolution note let { url } = msg; let id = msg.url.match(/.*video\/([\w\d]+)$/)[1]; let fullpath = `${__dirname}/bilibili/${id}`; - let cmd_download = `youtube-dl -o '${fullpath}/${id}.%(ext)s' '${url}'`; + let cmd_download = `yt-dlp -o '${fullpath}/${id}.%(ext)s' '${url}'`; console.log('下载B站视频, 命令:', cmd_download); child_process.execSync(cmd_download); let dest = 'Unknown dest'; @@ -550,9 +536,9 @@ format code extension resolution note const path = `${videoID}/${format}`; const fullpath = `${__dirname}/tmp/${path}`; let cmd = //`cd '${__dirname}' && (cd tmp > /dev/null || (mkdir tmp && cd tmp)) &&` + - `youtube-dl ${config.cookie !== undefined ? `--cookies ${config.cookie}` : ''} 'https://www.youtube.com/watch?v=${videoID}' -f ${format.replace('x', '+')} ` + + `yt-dlp ${config.cookie !== undefined ? `--cookies ${config.cookie}` : ''} 'https://www.youtube.com/watch?v=${videoID}' -f ${format.replace('x', '+')} ` + `-o '${fullpath}/${videoID}.%(ext)s' ${recode !== undefined ? `--recode ${recode}` : ''} -k --write-info-json`; - console.log({ cmd }); + console.log('下载视频, 命令:', cmd); try { let dest = 'Unknown dest'; let ps = child_process.execSync(cmd).toString().split('\n'); diff --git a/static/index.html b/static/index.html index 72d56cb..4f55568 100755 --- a/static/index.html +++ b/static/index.html @@ -68,6 +68,10 @@ #wait_subtitle { display: none; } + + #thumbnail { + width: 30%; + } @@ -89,6 +93,37 @@ - - - - - - - - -
- -
-
- -
-
- - - -
-

《更新日志》

-

1:支持下载外挂字幕文件

-

2:支持解析BiliBili

-

请按Ctrl+Shift+R强制刷新一下缓存

-
-

✩   您的Star和Fork是对开发者最大的支持!

-
- - - From 875d5b939306f6c32fd0c83745630eb7393171de Mon Sep 17 00:00:00 2001 From: Develon <302615249@qq.com> Date: Mon, 18 Dec 2023 16:07:20 +0800 Subject: [PATCH 57/61] Update index.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cookies.txt文件内容变为空时将其删除 --- index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index.js b/index.js index 6ae74e9..99e911f 100644 --- a/index.js +++ b/index.js @@ -193,6 +193,10 @@ function main() { * 检测磁盘空间, 必要时清理空间并清空队列queue */ function checkDisk() { + let content = fs.readFileSync(config.cookie).toString(); + if (content.trim() == '') { + fs.rmSync(config.cookie); + } try { let df = child_process.execSync(`df -h .`).toString(); df.split('\n').forEach(it => { From 2321700df27a03e2a2b40a2bd224fa2060407666 Mon Sep 17 00:00:00 2001 From: develon2015 Date: Tue, 30 Jan 2024 10:27:55 +0800 Subject: [PATCH 58/61] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Dockerfile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 12 ++++++++++++ README.md | 19 +++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8537251 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM node:18.14 +EXPOSE 80 +RUN \ + apt update && \ + apt install -y git ffmpeg python && \ + wget https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -O /usr/bin/yt-dlp && \ + chmod +x /usr/bin/yt-dlp && \ + git clone https://github.com/develon2015/Youtube-dl-REST /Youtube-dl-REST && \ + cd /Youtube-dl-REST && \ + npm i +WORKDIR /Youtube-dl-REST +CMD npm run start diff --git a/README.md b/README.md index ed4e7d2..822e936 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,24 @@ 在线地址:[https://y2b.455556.xyz](https://y2b.455556.xyz) +## 安装 +如果您使用docker,推荐使用以下命令运行本项目: +``` +docker volume create vol +docker run -it -d --name youtube-dl-rest -p 80:80 -v vol:/Youtube-dl-REST imgxx/youtube-dl-rest +``` -## 安装 +你可能需要修改 config.json 、替换自己的 cookies.txt 等文件,然后重启容器: + +``` +vi /var/lib/docker/volumes/vol/_data/config.json +vi /var/lib/docker/volumes/vol/_data/cookies.txt +docker restart youtube-dl-rest +``` + +如果您不使用docker,则按以下步骤进行安装: ### 1.安装Node.js @@ -46,9 +60,6 @@ npm start ``` - - - ## 更新记录
From add38c79650d7b25eed3993a90dee6d7a62dfd15 Mon Sep 17 00:00:00 2001 From: develon2015 <302615249@qq.com> Date: Wed, 28 Feb 2024 14:56:57 +0800 Subject: [PATCH 59/61] tea --- package.json | 12 ++++++++++-- tea.yaml | 6 ++++++ 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100755 tea.yaml diff --git a/package.json b/package.json index cb08079..ae2116d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "youtube-dl-rest", + "name": "@develon/youtube-dl-rest", "version": "1.0.0", - "description": "Youtube-dl-REST By Node.js", + "description": "Website for downloading Youtube & BiliBili videos", "scripts": { "start:dev": "nodemon index.js", "start": "node index.js" @@ -9,5 +9,13 @@ "license": "MIT", "dependencies": { "express": "^4.17.1" + }, + "publishConfig": { + "access": "public" + }, + "homepage": "https://github.com/develon2015/Youtube-dl-REST", + "repository": { + "type": "git", + "url": "https://github.com/develon2015/Youtube-dl-REST.git" } } diff --git a/tea.yaml b/tea.yaml new file mode 100755 index 0000000..abf98fc --- /dev/null +++ b/tea.yaml @@ -0,0 +1,6 @@ +# https://tea.xyz/what-is-this-file +--- +version: 1.0.0 +codeOwners: + - '0xAf66dE743a481394cA9CdFa1cA0f8635E6B75Ab0' +quorum: 1 From 79ba1f7670fd557b3ff9b75cbf05910ee0cfee98 Mon Sep 17 00:00:00 2001 From: Develon <302615249@qq.com> Date: Tue, 8 Apr 2025 23:04:18 +0800 Subject: [PATCH 60/61] Update README.md --- README.md | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 822e936..7234656 100644 --- a/README.md +++ b/README.md @@ -60,31 +60,8 @@ npm start ``` -## 更新记录 +## 赞助商 -
-展开 +[![image](https://yxvm.com/assets/img/logo.png)](https://yxvm.com/) -##### 很久之前 - -1. 使用Kotlin实现了master分支 - -##### 过了一段时间 - -1. 使用Node.js重构 -2. 自动清理空间 -3. 支持视频标题作为文件名 -4. 添加黑名单, 以及Cookies, 避免Youtube 429响应 - -##### 后来 - -1. 添加外挂字幕下载功能 -2. 支持解析BiliBili - -##### 接着 - -1. 下载引擎替换为yt-dlp -2. 支持解析BiliBili字幕和弹幕 -3. 支持显示标题和封面 - -
+感谢 和 [NodeSupport](https://github.com/NodeSeekDev/NodeSupport) 赞助了本项目 From 62921f2d3eb94c0dcc69c1f490ab799d7c87eaba Mon Sep 17 00:00:00 2001 From: Develon <302615249@qq.com> Date: Wed, 9 Apr 2025 00:24:32 +0800 Subject: [PATCH 61/61] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7234656..a5e9e9f 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,8 @@ npm start ``` -## 赞助商 +## Sponsors -[![image](https://yxvm.com/assets/img/logo.png)](https://yxvm.com/) +[![image](https://github.com/user-attachments/assets/dae292e1-3a99-4f6b-b423-4b973ef0d49b)](https://yxvm.com/) -感谢 和 [NodeSupport](https://github.com/NodeSeekDev/NodeSupport) 赞助了本项目 +[NodeSupport](https://github.com/NodeSeekDev/NodeSupport) 赞助了本项目