|
import { spawn } from 'child_process' |
|
import prompts from 'prompts' |
|
import trash from 'trash' |
|
|
|
let url = process.argv[2] |
|
|
|
if (!url) { |
|
url = await prompts([ |
|
{ |
|
type: 'text', |
|
name: 'url', |
|
message: 'Video URL' |
|
} |
|
]) |
|
} |
|
|
|
const formatSelector = spawn('yt-dlp', ['-F', url]) |
|
formatSelector.stdout.on('data', data => console.log(data.toString('utf-8'))) |
|
formatSelector.stderr.on('data', data => console.error(data.toString('utf-8'))) |
|
await new Promise(resolve => formatSelector.on('close', resolve)) |
|
|
|
const responses = await prompts([ |
|
{ |
|
type: 'number', |
|
name: 'videoformat', |
|
message: 'Video format ID', |
|
initial: '399' |
|
}, |
|
{ |
|
type: 'number', |
|
name: 'audioformat', |
|
message: 'Audio format ID', |
|
initial: '251' |
|
}, |
|
]) |
|
|
|
const timerange = await prompts([ |
|
{ |
|
type: 'text', |
|
name: 'from', |
|
message: 'From (00:00:00 or 00:00)' |
|
}, |
|
{ |
|
type: 'text', |
|
name: 'to', |
|
message: 'To (00:00:00 or 00:00)' |
|
}, |
|
]) |
|
|
|
|
|
const videoformatURLprocess = spawn('yt-dlp', ['-g', '-f', responses.videoformat, url]) |
|
let videoformatURL = '' |
|
videoformatURLprocess.stdout.on('data', data => videoformatURL += data.toString('utf-8')) |
|
videoformatURLprocess.stderr.on('data', data => console.error(data.toString('utf-8'))) |
|
await new Promise(resolve => videoformatURLprocess.on('close', resolve)) |
|
|
|
const audioformatURLprocess = spawn('yt-dlp', ['-g', '-f', responses.audioformat, url]) |
|
let audioformatURL = '' |
|
audioformatURLprocess.stdout.on('data', data => audioformatURL += data.toString('utf-8')) |
|
audioformatURLprocess.stderr.on('data', data => console.error(data.toString('utf-8'))) |
|
await new Promise(resolve => audioformatURLprocess.on('close', resolve)) |
|
|
|
const audioFilename = 'cutyt_' + Date.now() + '_aud.opus' |
|
const videoFilename = 'cutyt_' + Date.now() + '_vid.mp4' |
|
const resultFilename = url.match(/https:\/\/.*\?v=(.+)/)[1] + '.mp4' |
|
|
|
const download = async (url, filename, consolePrefix) => { |
|
console.log('ffmpeg', ['-ss', timerange.from, '-to', timerange.to, '-i', url, filename].join(' ')) |
|
const downloadingProcess = spawn('ffmpeg', ['-ss', timerange.from, '-to', timerange.to, '-i', url, filename]) |
|
downloadingProcess.stdout.on('data', data => console.log(consolePrefix, data.toString('utf-8'))) |
|
downloadingProcess.stderr.on('data', data => console.error(consolePrefix, data.toString('utf-8'))) |
|
await new Promise(resolve => downloadingProcess.on('close', resolve)) |
|
} |
|
|
|
await Promise.all([ |
|
download(audioformatURL.replace('\n', ''), audioFilename, 'audio_stream:'), |
|
download(videoformatURL.replace('\n', ''), videoFilename, 'video_stream:'), |
|
]) |
|
|
|
const mergeStreams = spawn('ffmpeg', ['-i', audioFilename, '-i', videoFilename, '-c:v', 'copy', resultFilename]) |
|
await new Promise(resolve => mergeStreams.on('close', resolve)) |
|
|
|
await trash([audioFilename, videoFilename]) |
|
|
|
console.log('Success!', resultFilename) |