125 lines
3.1 KiB
JavaScript
125 lines
3.1 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(__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)
|
||
|
|
||
|
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 id3 = await asn.promiseExec(`id3 "${file}"`)
|
||
|
let prds = id3.stdout.split('\n')
|
||
|
let data = {}
|
||
|
|
||
|
// Get id3 tags
|
||
|
for (let i in prds) {
|
||
|
let line = prds[i]
|
||
|
let parts = line.split(': ')
|
||
|
if (parts.length) {
|
||
|
let tagtype = parts[0].toLowerCase()
|
||
|
let tagdata = line.substring(parts[0].length + 2)
|
||
|
|
||
|
if (tagtype === '') continue
|
||
|
if (tagtype === 'metadata' && tagdata === 'none found') throw new Error(`No metadata for file "${file}"!`)
|
||
|
if (tagtype === 'track' || tagtype === 'year') {
|
||
|
if (tagdata.indexOf('/') !== -1) {
|
||
|
tagdata = tagdata.split('/')[0]
|
||
|
}
|
||
|
|
||
|
tagdata = parseInt(tagdata)
|
||
|
}
|
||
|
|
||
|
data[tagtype] = tagdata
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!data.title) {
|
||
|
let parsed = path.parse(file)
|
||
|
data.title = parsed.name
|
||
|
}
|
||
|
|
||
|
// Get track length
|
||
|
let len = await asn.promiseExec(`ffprobe -i "${file}" -show_entries format=duration -v quiet -of csv="p=0"`)
|
||
|
len = parseFloat(len.stdout)
|
||
|
data.duration = len
|
||
|
|
||
|
return data
|
||
|
}
|
||
|
|
||
|
export default {parseTitle, getVideoInfo, fetchVideo, getInfos}
|