diff --git a/controller/websocket.js b/controller/websocket.js index 443a020..7f2e997 100644 --- a/controller/websocket.js +++ b/controller/websocket.js @@ -73,7 +73,7 @@ exports.save = async (ws, req) => { async function startDownloading() { ws.send('INFO - Spawning yt-dlp!') - const download = await ytdlp.downloadVideo(`https://www.youtube.com/watch?v=${id}`, ws) + const download = await ytdlp.downloadVideo(`https://www.youtube.com/watch?v=${id}`, ws, id) if (download.fail) { await redis.del(id) ws.send(`DATA - ${download.message}`) @@ -170,7 +170,7 @@ exports.playlist = async (ws, req) => { ws.send(`INFO - Downloading ${video.title}

`) await redis.set(id, 'downloading') - const download = await ytdlp.downloadVideo('https://www.youtube.com' + video.url, ws) + const download = await ytdlp.downloadVideo('https://www.youtube.com' + video.url, ws, id) if (download.fail) { ws.send(`DATA - ${download.message}`) await redis.del(id) @@ -269,7 +269,7 @@ exports.channel = async (ws, req) => { ws.send(`INFO - Downloading ${video.title}

`) await redis.set(id, 'downloading') - const download = await ytdlp.downloadVideo('https://www.youtube.com' + video.url, ws) + const download = await ytdlp.downloadVideo('https://www.youtube.com' + video.url, ws, id) if (download.fail) { ws.send(`DATA - ${download.message}`) await redis.del(id) diff --git a/utils/metadata.js b/utils/metadata.js index ca19a79..7ab5628 100644 --- a/utils/metadata.js +++ b/utils/metadata.js @@ -30,7 +30,7 @@ async function getVideoMetadata(id) { for (let retries = 0; retries < maxRetries; retries++) { try { const instance = await getInstance() - const response = await fetch(`${instance}/api/v1/videos/${id}?fields=videoId,title,descriptionHtml,videoThumbnails,published,authorId,error&pretty=1`, { + const response = await fetch(`${instance}/api/v1/videos/${id}?fields=videoId,title,descriptionHtml,videoThumbnails,published,authorId,lengthSeconds,error&pretty=1`, { headers: { 'User-Agent': 'Mozilla/5.0 (compatible; PreserveTube/0.0; +https://preservetube.com)' } diff --git a/utils/ytdlp.js b/utils/ytdlp.js index ea29cb8..6c3048e 100644 --- a/utils/ytdlp.js +++ b/utils/ytdlp.js @@ -1,9 +1,19 @@ const child_process = require('child_process') const DOMPurify = require('isomorphic-dompurify') +const metadata = require('./metadata.js') -async function downloadVideo(url, ws) { - return new Promise((resolve, reject) => { - const child = child_process.spawn("../yt-dlp", ["--proxy", "socks5://gluetun:1080", url], {cwd: 'videos', shell: false}) +async function downloadVideo(url, ws, id) { + return new Promise(async (resolve, reject) => { + const args = ['--proxy', 'socks5://gluetun:1080', url] + const video = await metadata.getVideoMetadata(id) + if (video.lengthSeconds > 1500) { + const formats = await getFormats(url, ws) + if (!formats.fail && formats.includes('18 mp4')) { + args.push('-f 18') + } + } + + const child = child_process.spawn('../yt-dlp', args, {cwd: 'videos', shell: false}) // https://github.com/yt-dlp/yt-dlp/blob/cc8d8441524ec3442d7c0d3f8f33f15b66aa06f3/README.md?plain=1#L1500 child.stdout.on("data", data => { @@ -34,4 +44,35 @@ async function downloadVideo(url, ws) { }) } +async function getFormats(url, ws) { + return new Promise((resolve, reject) => { + const child = child_process.spawn("../yt-dlp", [url, "-F"], {cwd: 'videos', shell: false}) + let outputs = '' + + child.stdout.on("data", data => { + const msg = data.toString().trim() + if (!msg) return + + outputs = outputs + msg + }) + + child.stderr.on("data", data => { + const msg = data.toString().trim() + if (!msg) return + + if (ws) ws.send(`DATA - ${DOMPurify.sanitize(msg)}`) + }) + + child.on("close", async (code, signal) => { + if (code == 2 || code == 1) { // https://github.com/yt-dlp/yt-dlp/issues/4262 + reject({ + fail: true + }) + } else { + resolve(outputs) + } + }) + }) +} + module.exports = { downloadVideo } \ No newline at end of file