btrtracks/src/common/download.js

123 lines
2.9 KiB
JavaScript

import {spawn} from 'child_process'
import path from 'path'
import asn from './async'
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
}
function getVideoInfo (arg) {
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')
})
return new Promise((resolve, reject) => {
yt.on('close', function () {
let data = JSON.parse(output)
delete data.formats
resolve(data)
})
})
}
function fetchVideo (data) {
return new Promise((resolve, reject) => {
if (data.acodec !== 'mp3' || data.vcodec !== 'none') {
let tempName = path.join(process.cwd(), `/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)
ffmpeg.on('error', function (e) {
reject(e)
})
ffmpeg.on('close', function () {
resolve({
title: data.title,
artist: data.uploader,
url: data.webpage_url,
art: data.thumbnail,
source: tempName
})
})
} else {
reject(new Error('Invalid format returned.'))
}
})
}
async function getInfos (file) {
let formatData = await asn.promiseExec(`ffprobe -i "${file}" -show_entries format -v quiet -of json`)
let parsed = JSON.parse(formatData.stdout)
if (!parsed || !parsed.format || !parsed.format.duration) throw new Error('Failed to parse metadata!')
parsed = parsed.format
let data = {
file,
duration: parseFloat(parsed.duration)
}
if (parsed.tags) {
for (let k in parsed.tags) {
let tagtype = k.toLowerCase()
let value = parsed.tags[k]
if (tagtype === 'date') tagtype = 'year'
if (tagtype === 'track' || tagtype === 'year') {
if (value.indexOf('/') !== -1) {
value = value.split('/')[0]
}
value = parseInt(value)
}
data[tagtype] = value
}
}
if (!data.title) {
let parsed = path.parse(file)
data.title = parsed.name
}
return data
}
export default {parseTitle, getVideoInfo, fetchVideo, getInfos}