import {spawn} from 'child_process' import ffmpeg from 'fluent-ffmpeg' 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', '-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 ftdata = output.trim().split('\n') if (ftdata.length > 1) { let composite = [] for (let i in ftdata) { let dat try { dat = JSON.parse(ftdata[i]) } catch (e) { console.error(e) continue } delete dat.formats composite.push(dat) } return resolve(composite) } let data = JSON.parse(output) delete data.formats resolve(data) }) }) } function fetchVideo (data) { return new Promise((resolve, reject) => { let tempName = path.join(process.cwd(), `/tmp.yt.${data.id}.mp3`) ffmpeg(data.url || data.file) .audioCodec('libmp3lame') .format('mp3') .on('error', reject) .on('end', function () { resolve({ title: data.title, artist: data.uploader, url: data.webpage_url, art: data.thumbnail, source: tempName }) }) .output(tempName) .run() }) } 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 (Math.floor(data.duration) === 0) throw new Error('Invalid file type!') 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}