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}