sigma patch
This commit is contained in:
		
							parent
							
								
									7a0089d3e6
								
							
						
					
					
						commit
						858091eb60
					
				| 
						 | 
					@ -23,7 +23,8 @@
 | 
				
			||||||
    "readable-to-ms": "^1.0.3",
 | 
					    "readable-to-ms": "^1.0.3",
 | 
				
			||||||
    "rolling-rate-limiter": "^0.4.2",
 | 
					    "rolling-rate-limiter": "^0.4.2",
 | 
				
			||||||
    "wget-improved": "^3.4.0",
 | 
					    "wget-improved": "^3.4.0",
 | 
				
			||||||
    "winston": "^3.8.2"
 | 
					    "winston": "^3.8.2",
 | 
				
			||||||
 | 
					    "ws": "^8.17.1"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "prisma": "4.9.0"
 | 
					    "prisma": "4.9.0"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										153
									
								
								utils/ytdlp.js
								
								
								
								
							
							
						
						
									
										153
									
								
								utils/ytdlp.js
								
								
								
								
							| 
						 | 
					@ -1,13 +1,5 @@
 | 
				
			||||||
const wget = require('wget-improved')
 | 
					const WebSocket = require('ws')
 | 
				
			||||||
const DOMPurify = require('isomorphic-dompurify')
 | 
					 | 
				
			||||||
const metadata = require('./metadata.js')
 | 
					const metadata = require('./metadata.js')
 | 
				
			||||||
const hr = require('@tsmx/human-readable')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const ffmpeg = require('fluent-ffmpeg')
 | 
					 | 
				
			||||||
const ffmpegStatic = require('ffmpeg-static')
 | 
					 | 
				
			||||||
const fs = require('node:fs')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ffmpeg.setFfmpegPath(ffmpegStatic)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function downloadVideo(url, ws, id) {
 | 
					async function downloadVideo(url, ws, id) {
 | 
				
			||||||
    return new Promise(async (resolve, reject) => {
 | 
					    return new Promise(async (resolve, reject) => {
 | 
				
			||||||
| 
						 | 
					@ -21,138 +13,29 @@ async function downloadVideo(url, ws, id) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (video.basic_info.duration >= 900) quality = '360' // 15 minutes
 | 
					        if (video.basic_info.duration >= 900) quality = '360' // 15 minutes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const downloadJson = await metadata.getVideoDownload(video, quality)
 | 
					        let isDownloading = true 
 | 
				
			||||||
 | 
					        const downloader = new WebSocket(`ws://${process.env.METADATA.replace('http://', '')}/download/${id}/${quality}p`)
 | 
				
			||||||
        let size = ''
 | 
					        downloader.on('message', async function message(data) {
 | 
				
			||||||
        let startTime = Date.now()
 | 
					            const text = data.toString()
 | 
				
			||||||
        let prevBytes = 0
 | 
					            if (text == 'done') {
 | 
				
			||||||
        let speed = 0
 | 
					                isDownloading = false
 | 
				
			||||||
        const alreadyPrecentages = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const target = Array.isArray(downloadJson.url) ? downloadJson.url[0] : downloadJson.url
 | 
					 | 
				
			||||||
        const download = wget.download(target, `./videos/${id}.mp4`, {
 | 
					 | 
				
			||||||
            proxy: {
 | 
					 | 
				
			||||||
                protocol: 'http',
 | 
					 | 
				
			||||||
                host: 'gluetun',
 | 
					 | 
				
			||||||
                port: '8888',
 | 
					 | 
				
			||||||
                headers: {
 | 
					 | 
				
			||||||
                    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
 | 
					 | 
				
			||||||
                    accept: '*/*',
 | 
					 | 
				
			||||||
                    origin: 'https://www.youtube.com',
 | 
					 | 
				
			||||||
                    referer: 'https://www.youtube.com',
 | 
					 | 
				
			||||||
                    DNT: '?1'
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        download.on('start', fileSize => {
 | 
					 | 
				
			||||||
            size = fileSize
 | 
					 | 
				
			||||||
            if (ws) ws.send(`DATA - Download has started in ${quality}p`)
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        download.on('progress', progress => {
 | 
					 | 
				
			||||||
            if (alreadyPrecentages.includes((progress*100).toFixed(0))) return 
 | 
					 | 
				
			||||||
            alreadyPrecentages.push((progress*100).toFixed(0))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            const currentTime = Date.now()
 | 
					 | 
				
			||||||
            const elapsedTime = (currentTime - startTime) / 1000
 | 
					 | 
				
			||||||
            const currentBytes = progress * size
 | 
					 | 
				
			||||||
            const bytesDownloaded = currentBytes - prevBytes
 | 
					 | 
				
			||||||
            speed = bytesDownloaded / elapsedTime 
 | 
					 | 
				
			||||||
            prevBytes = currentBytes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            const speedInMBps = speed / 1048576 
 | 
					 | 
				
			||||||
            const remainingBytes = size - currentBytes
 | 
					 | 
				
			||||||
            const remainingTime = remainingBytes / speed 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (ws) ws.send(`DATA - [download] ${(progress*100).toFixed(2)}% of ${hr.fromBytes(size)} at ${speedInMBps.toFixed(2)} MB/s ETA ${secondsToTime(remainingTime.toFixed(0))}`)
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        download.on('error', err => {
 | 
					 | 
				
			||||||
            if (ws) ws.send(`DATA - ${DOMPurify.sanitize(err)}`)
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        download.on('end', output => {
 | 
					 | 
				
			||||||
            if (output !== 'Finished writing to disk') {
 | 
					 | 
				
			||||||
                return resolve({
 | 
					 | 
				
			||||||
                    fail: true
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (Array.isArray(downloadJson.url)) { // this means video is separate
 | 
					 | 
				
			||||||
                ws.send(`DATA - Downloading the video has finished, downloading audio.`);
 | 
					 | 
				
			||||||
                
 | 
					 | 
				
			||||||
                const audioDownload = wget.download(downloadJson.url[1], `./videos/${id}_audio.mp4`, {
 | 
					 | 
				
			||||||
                    proxy: {
 | 
					 | 
				
			||||||
                        protocol: 'http',
 | 
					 | 
				
			||||||
                        host: 'gluetun',
 | 
					 | 
				
			||||||
                        port: '8888',
 | 
					 | 
				
			||||||
                        headers: {
 | 
					 | 
				
			||||||
                            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
 | 
					 | 
				
			||||||
                            accept: '*/*',
 | 
					 | 
				
			||||||
                            origin: 'https://www.youtube.com',
 | 
					 | 
				
			||||||
                            referer: 'https://www.youtube.com',
 | 
					 | 
				
			||||||
                            DNT: '?1'
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                audioDownload.on('end', async (audioOutput) => {
 | 
					 | 
				
			||||||
                    if (audioOutput !== 'Finished writing to disk') {
 | 
					 | 
				
			||||||
                        return resolve({ fail: true });
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    fs.renameSync(`./videos/${id}.mp4`, `./videos/${id}_video.mp4`);
 | 
					 | 
				
			||||||
                    try {
 | 
					 | 
				
			||||||
                        await mergeIt(`./videos/${id}_audio.mp4`, `./videos/${id}_video.mp4`, `./videos/${id}.mp4`);
 | 
					 | 
				
			||||||
                        ws.send(`DATA - Merging succeeded.`)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        fs.rmSync(`./videos/${id}_audio.mp4`)
 | 
					 | 
				
			||||||
                        fs.rmSync(`./videos/${id}_video.mp4`)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        return resolve({ fail: false });
 | 
					 | 
				
			||||||
                    } catch (error) {
 | 
					 | 
				
			||||||
                        console.error('Merging error:', error);
 | 
					 | 
				
			||||||
                        return resolve({ fail: true });
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                audioDownload.on('error', (err) => {
 | 
					 | 
				
			||||||
                    console.error('Audio download error:', err);
 | 
					 | 
				
			||||||
                    return resolve({ fail: true });
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                ws.send(`DATA - Download has finished`)
 | 
					 | 
				
			||||||
                return resolve({
 | 
					                return resolve({
 | 
				
			||||||
                    fail: false
 | 
					                    fail: false
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                ws.send(text)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        downloader.on('close', function close(code, reason) {
 | 
				
			||||||
 | 
					            if (!isDownloading) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return resolve({
 | 
				
			||||||
 | 
					                fail: true,
 | 
				
			||||||
 | 
					                message: 'The metadata server unexpectedly closed the websocket. Please try again.'
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function mergeIt(audioPath, videoPath, outputPath) {
 | 
					 | 
				
			||||||
    return new Promise((resolve, reject) => {
 | 
					 | 
				
			||||||
        ffmpeg()
 | 
					 | 
				
			||||||
            .addInput(videoPath)
 | 
					 | 
				
			||||||
            .addInput(audioPath)
 | 
					 | 
				
			||||||
            .outputOptions('-c:v copy') 
 | 
					 | 
				
			||||||
            .outputOptions('-c:a aac') 
 | 
					 | 
				
			||||||
            .output(outputPath)
 | 
					 | 
				
			||||||
            .on('end', () => {
 | 
					 | 
				
			||||||
                resolve('Merging finished!');
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .on('error', (err) => {
 | 
					 | 
				
			||||||
                reject(new Error('An error occurred: ' + err.message));
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .run();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function secondsToTime(seconds) {
 | 
					 | 
				
			||||||
    const minutes = Math.floor(seconds / 60);
 | 
					 | 
				
			||||||
    const remainingSeconds = seconds % 60;
 | 
					 | 
				
			||||||
    const formattedSeconds = remainingSeconds < 10 ? '0' + remainingSeconds : remainingSeconds;
 | 
					 | 
				
			||||||
    return `${minutes}:${formattedSeconds}`;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module.exports = { downloadVideo }
 | 
					module.exports = { downloadVideo }
 | 
				
			||||||
| 
						 | 
					@ -1502,6 +1502,11 @@ ws@^8.11.0:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.1.tgz#c51e583d79140b5e42e39be48c934131942d4a8f"
 | 
					  resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.1.tgz#c51e583d79140b5e42e39be48c934131942d4a8f"
 | 
				
			||||||
  integrity sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==
 | 
					  integrity sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ws@^8.17.1:
 | 
				
			||||||
 | 
					  version "8.17.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b"
 | 
				
			||||||
 | 
					  integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
xml-name-validator@^4.0.0:
 | 
					xml-name-validator@^4.0.0:
 | 
				
			||||||
  version "4.0.0"
 | 
					  version "4.0.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835"
 | 
					  resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue