btrtracks/download.js
2018-10-05 13:36:57 +03:00

135 lines
3.3 KiB
JavaScript
Executable File

#!/usr/bin/env node
'use strict'
const spawn = require('child_process').spawn
const fs = require('fs')
const readline = require('readline')
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
function download (arg, handleCb) {
let yt = spawn('youtube-dl', ['--no-playlist', '--playlist-end', 1, '-j', '-f', 'bestaudio/best', arg])
let output = ''
yt.stdout.on('data', function (chunk) {
output += chunk.toString('utf8')
})
yt.on('close', function () {
let data = JSON.parse(output)
delete data.formats
fetchVideo(data, handleCb)
})
}
function fetchVideo (data, cb) {
console.log('audio codec:', data.acodec)
if (data.acodec !== 'mp3' || data.vcodec !== 'none') {
let tempName = __dirname + '/tmp.yt.' + data.id + '.mp3'
let ffmpeg = spawn('ffmpeg', ['-hide_banner', '-i', data.url, '-codec:a', 'libmp3lame', '-q:a', 2, '-joint_stereo', 1, '-y', tempName])
ffmpeg.stdout.pipe(process.stderr)
ffmpeg.stderr.pipe(process.stderr)
data.filename = tempName
console.log('Downloading ' + data.title + '...')
ffmpeg.on('close', function () {
outputVideo(data, cb)
})
} else {
console.log('Invalid format returned.')
cb(null)
}
}
function outputVideo (video, cb) {
cb({
title: video.title,
artist: video.uploader,
url: video.webpage_url,
art: video.thumbnail,
source: video.filename
})
}
function parseTitle(data) {
let tt = data.title
// Remove []'s from the beginning
tt = tt.replace(/^\[\w+\]\s?/i, '')
// Remove "Official Video/Audio" tag
tt = tt.replace(/\s?(?:[\(\)\[\]])?Official\s?[\w]+(?:[\(\)\[\]])?/i, '')
// Remove "Audio" tag
tt = tt.replace(/\s?(?:[\(\)\[\]])Audio?(?:[\(\)\[\]])/i, '')
// Remove "lyrics" tag
tt = tt.replace(/\s?(?:[\(\)\[\]])?lyrics?\s?(?:[\w]+)?(?:[\(\)\[\]])?\s?/i, '')
// Artist / Title split
let at = tt.split(' - ', 2)
let artist
let title
if (at.length > 1) {
artist = at[0]
title = tt.substring(artist.length + 3)
} else {
artist = data.artist
title = tt
}
data.title = title
data.artist = artist
return data
}
download(process.argv[2], function (s) {
let clean = parseTitle(s)
let filename = clean.artist + ' - ' + clean.title + '.mp3'
console.log('Cleaning up..')
console.log('Original Title: ' + s.title + '\n')
console.log('Determined Title: ' + clean.title)
console.log('Determined Artist: ' + clean.artist)
console.log('Determined File Name: ' + filename)
rl.question(`Title [${clean.title}] ? `, (answer) => {
if (answer && answer.trim() !== '') {
clean.title = answer
}
rl.question(`Artist [${clean.artist}] ? `, (answer) => {
if (answer && answer.trim() !== '') {
clean.artist = answer
}
rl.question(`File [${filename}] ? `, (answer) => {
if (answer && answer.trim() !== '') {
filename = answer
}
let fn = __dirname + '/' + filename
fs.rename(s.source, fn, function (err) {
if (err) {
console.error(err)
return rl.close()
}
let id3 = spawn('id3', ['-a', clean.artist, '-t', clean.title, fn])
id3.on('close', () => {
console.log('Saved as ' + fn)
rl.close()
})
})
})
})
})
})