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 = { 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}