collect common functions
This commit is contained in:
parent
266f8d9a3b
commit
97ab22a5f4
63
common/async.js
Normal file
63
common/async.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import {exec} from 'child_process'
|
||||||
|
import fs from 'fs-extra'
|
||||||
|
|
||||||
|
function filewalker (dir, done) {
|
||||||
|
let results = []
|
||||||
|
|
||||||
|
fs.readdir(dir, function (err, list) {
|
||||||
|
if (err) return done(err)
|
||||||
|
|
||||||
|
let pending = list.length
|
||||||
|
|
||||||
|
if (!pending) return done(null, results)
|
||||||
|
|
||||||
|
list.forEach(function (file) {
|
||||||
|
file = path.resolve(dir, file)
|
||||||
|
|
||||||
|
fs.stat(file, function (err, stat) {
|
||||||
|
if (err) return done(err)
|
||||||
|
|
||||||
|
// If directory, execute a recursive call
|
||||||
|
if (stat && stat.isDirectory()) {
|
||||||
|
filewalker(file, function (err, res) {
|
||||||
|
if (err) return done(err)
|
||||||
|
results = results.concat(res)
|
||||||
|
if (!--pending) done(null, results)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
results.push(file)
|
||||||
|
|
||||||
|
if (!--pending) done(null, results)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFiles (dir) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
filewalker(dir, (err, files) => {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve(files)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function promiseExec (cmd, opts) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
exec(cmd, opts, function (err, stdout, stderr) {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve({stdout, stderr})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function askAsync (rl, q) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
rl.question(q, resolve)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let a = {getFiles, promiseExec, askAsync}
|
||||||
|
|
||||||
|
export default a
|
124
common/download.js
Normal file
124
common/download.js
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
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}
|
176
dbpopulate.js
176
dbpopulate.js
@ -1,9 +1,12 @@
|
|||||||
#!/usr/bin/env babel-node
|
#!/usr/bin/env babel-node
|
||||||
|
import fs from 'fs-extra'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import sqlite from 'sqlite'
|
import sqlite from 'sqlite'
|
||||||
import Promise from 'bluebird'
|
import Promise from 'bluebird'
|
||||||
import fs from 'fs-extra'
|
import readline from 'readline'
|
||||||
import {exec} from 'child_process'
|
|
||||||
|
import asn from './common/async'
|
||||||
|
import dl from './common/download'
|
||||||
|
|
||||||
const values = require(path.join(__dirname, 'values.json'))
|
const values = require(path.join(__dirname, 'values.json'))
|
||||||
const musicdir = path.resolve(values.directory)
|
const musicdir = path.resolve(values.directory)
|
||||||
@ -12,163 +15,28 @@ const dbPromise = Promise.resolve()
|
|||||||
.then(() => sqlite.open(path.join(__dirname, values.database), { Promise, cache: true }))
|
.then(() => sqlite.open(path.join(__dirname, values.database), { Promise, cache: true }))
|
||||||
.then(db => db.migrate())
|
.then(db => db.migrate())
|
||||||
|
|
||||||
const readline = require('readline')
|
|
||||||
|
|
||||||
// ffprobe -i <file> -show_entries format=duration -v quiet -of csv="p=0"
|
// ffprobe -i <file> -show_entries format=duration -v quiet -of csv="p=0"
|
||||||
|
|
||||||
function filewalker (dir, done) {
|
|
||||||
let results = []
|
|
||||||
|
|
||||||
fs.readdir(dir, function (err, list) {
|
|
||||||
if (err) return done(err)
|
|
||||||
|
|
||||||
var pending = list.length
|
|
||||||
|
|
||||||
if (!pending) return done(null, results)
|
|
||||||
|
|
||||||
list.forEach(function (file) {
|
|
||||||
file = path.resolve(dir, file)
|
|
||||||
|
|
||||||
fs.stat(file, function (err, stat) {
|
|
||||||
if (err) return done(err)
|
|
||||||
|
|
||||||
// If directory, execute a recursive call
|
|
||||||
if (stat && stat.isDirectory()) {
|
|
||||||
//results.push(file)
|
|
||||||
|
|
||||||
filewalker(file, function (err, res) {
|
|
||||||
if (err) return done(err)
|
|
||||||
results = results.concat(res)
|
|
||||||
if (!--pending) done(null, results)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
results.push(file)
|
|
||||||
|
|
||||||
if (!--pending) done(null, results)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFiles (dir) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
filewalker(dir, (err, files) => {
|
|
||||||
if (err) return reject(err)
|
|
||||||
resolve(files)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function promiseExec (cmd, opts) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
exec(cmd, opts, function (err, stdout, stderr) {
|
|
||||||
if (err) return reject(err)
|
|
||||||
resolve({stdout, stderr})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getInfos (file) {
|
|
||||||
let id3 = await 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 promiseExec(`ffprobe -i "${file}" -show_entries format=duration -v quiet -of csv="p=0"`)
|
|
||||||
len = parseFloat(len.stdout)
|
|
||||||
data.duration = len
|
|
||||||
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
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 askAsync (rl, q) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
rl.question(q, resolve)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function interactive (fpath, db) {
|
async function interactive (fpath, db) {
|
||||||
let rl = readline.createInterface({
|
let rl = readline.createInterface({
|
||||||
input: process.stdin,
|
input: process.stdin,
|
||||||
output: process.stdout
|
output: process.stdout
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('No metadata found for specified file! Interactive mode enabled.\n')
|
console.log('=> No metadata found for specified file! Interactive mode enabled.\n')
|
||||||
|
|
||||||
let pt = path.parse(fpath)
|
let pt = path.parse(fpath)
|
||||||
let track = {
|
let track = {
|
||||||
file: fpath,
|
file: fpath,
|
||||||
title: pt.name
|
title: pt.name
|
||||||
}
|
}
|
||||||
let clean = parseTitle(track)
|
let clean = dl.parseTitle(track)
|
||||||
|
|
||||||
console.log('Determined Title: ' + clean.title)
|
console.log('== Determined Title: ' + clean.title)
|
||||||
console.log('Determined Artist: ' + clean.artist)
|
console.log('== Determined Artist: ' + clean.artist)
|
||||||
|
|
||||||
let newTitle = await askAsync(rl, `Title [${clean.title}] ? `)
|
let newTitle = await asn.askAsync(rl, `Title [${clean.title}] ? `)
|
||||||
let newArtist = await askAsync(rl, `Artist [${clean.artist}] ? `)
|
let newArtist = await asn.askAsync(rl, `Artist [${clean.artist}] ? `)
|
||||||
|
|
||||||
if (newTitle.trim() !== '')
|
if (newTitle.trim() !== '')
|
||||||
track.title = newTitle
|
track.title = newTitle
|
||||||
@ -176,13 +44,7 @@ async function interactive (fpath, db) {
|
|||||||
if (newArtist.trim() !== '')
|
if (newArtist.trim() !== '')
|
||||||
track.artist = newArtist
|
track.artist = newArtist
|
||||||
|
|
||||||
let ensure = await db.get('SELECT * FROM Track WHERE title=? AND artist=?', track.title, track.artist)
|
let len = await asn.promiseExec(`ffprobe -i "${track.file}" -show_entries format=duration -v quiet -of csv="p=0"`)
|
||||||
if (ensure) {
|
|
||||||
console.error('A track of this description already exists in the database.')
|
|
||||||
return rl.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
let len = await promiseExec(`ffprobe -i "${track.file}" -show_entries format=duration -v quiet -of csv="p=0"`)
|
|
||||||
track.duration = parseFloat(len)
|
track.duration = parseFloat(len)
|
||||||
|
|
||||||
rl.close()
|
rl.close()
|
||||||
@ -198,7 +60,7 @@ async function run () {
|
|||||||
let trackinf
|
let trackinf
|
||||||
|
|
||||||
try {
|
try {
|
||||||
trackinf = await getInfos(filePath)
|
trackinf = await dl.getInfos(filePath)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
trackinf = await interactive(filePath, db)
|
trackinf = await interactive(filePath, db)
|
||||||
}
|
}
|
||||||
@ -208,11 +70,17 @@ async function run () {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ensure = await db.get('SELECT * FROM Track WHERE title=? AND artist=?', trackinf.title, trackinf.artist)
|
||||||
|
if (ensure) {
|
||||||
|
console.error('A track of this description already exists in the database.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
await db.run('INSERT INTO Track VALUES (NULL,?,?,?,?,?,?,?,?)',
|
await db.run('INSERT INTO Track VALUES (NULL,?,?,?,?,?,?,?,?)',
|
||||||
[trackinf.title, trackinf.artist, trackinf.file, trackinf.album || null, trackinf.genre || null, trackinf.track || null,
|
[trackinf.title, trackinf.artist, trackinf.file, trackinf.album || null, trackinf.genre || null, trackinf.track || null,
|
||||||
trackinf.year || null, Math.floor(trackinf.duration)])
|
trackinf.year || null, Math.floor(trackinf.duration)])
|
||||||
|
|
||||||
console.log('Done.')
|
console.log('=> Done.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +93,7 @@ async function run () {
|
|||||||
// if (cleanTrackData.length > 10) break // debug purposes
|
// if (cleanTrackData.length > 10) break // debug purposes
|
||||||
process.stdout.write(`\rProcessing file ${parseInt(i) + 1} of ${files.length}.. (${skips} skipped)`)
|
process.stdout.write(`\rProcessing file ${parseInt(i) + 1} of ${files.length}.. (${skips} skipped)`)
|
||||||
try {
|
try {
|
||||||
let fd = await getInfos(file)
|
let fd = await dl.getInfos(file)
|
||||||
cleanTrackData.push(fd)
|
cleanTrackData.push(fd)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
skips++
|
skips++
|
||||||
@ -251,7 +119,7 @@ async function run () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`\n${entries} tracks were successfully added to the cache!`)
|
console.log(`=> \n${entries} tracks were successfully added to the cache!`)
|
||||||
}
|
}
|
||||||
|
|
||||||
run()
|
run()
|
||||||
|
159
download.js
159
download.js
@ -1,134 +1,63 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env babel-node
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const spawn = require('child_process').spawn
|
import fs from 'fs-extra'
|
||||||
const fs = require('fs')
|
import readline from 'readline'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
const readline = require('readline')
|
import asn from './common/async'
|
||||||
|
import dl from './common/download'
|
||||||
|
|
||||||
|
const values = require(path.join(__dirname, 'values.json'))
|
||||||
|
const musicdir = path.resolve(values.directory)
|
||||||
|
|
||||||
const rl = readline.createInterface({
|
const rl = readline.createInterface({
|
||||||
input: process.stdin,
|
input: process.stdin,
|
||||||
output: process.stdout
|
output: process.stdout
|
||||||
})
|
})
|
||||||
|
|
||||||
function download (arg, handleCb) {
|
async function download (furl) {
|
||||||
let yt = spawn('youtube-dl', ['--no-playlist', '--playlist-end', 1, '-j', '-f', 'bestaudio/best', arg])
|
console.log('=> Getting information..')
|
||||||
|
let data = await dl.getVideoInfo(furl)
|
||||||
|
|
||||||
let output = ''
|
console.log('=> Downloading file..')
|
||||||
|
let file = await dl.fetchVideo(data)
|
||||||
|
|
||||||
yt.stdout.on('data', function (chunk) {
|
console.log('=> Cleaning up..')
|
||||||
output += chunk.toString('utf8')
|
let clean = dl.parseTitle(file)
|
||||||
})
|
|
||||||
yt.on('close', function () {
|
|
||||||
let data = JSON.parse(output)
|
|
||||||
delete data.formats
|
|
||||||
fetchVideo(data, handleCb)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function fetchVideo (data, cb) {
|
|
||||||
console.log('audio codec:', data.acodec)
|
|
||||||
if (data.acodec !== 'mp3' || data.vcodec !== 'none') {
|
|
||||||
let tempName = __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)
|
|
||||||
data.filename = tempName
|
|
||||||
console.log('Downloading ' + data.title + '...')
|
|
||||||
|
|
||||||
ffmpeg.on('close', function () {
|
|
||||||
outputVideo(data, cb)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
console.log('Invalid format returned.')
|
|
||||||
cb(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function outputVideo (video, cb) {
|
|
||||||
cb({
|
|
||||||
title: video.title,
|
|
||||||
artist: video.uploader,
|
|
||||||
url: video.webpage_url,
|
|
||||||
art: video.thumbnail,
|
|
||||||
source: video.filename
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
download(process.argv[2], function (s) {
|
|
||||||
let clean = parseTitle(s)
|
|
||||||
let filename = clean.artist + ' - ' + clean.title + '.mp3'
|
let filename = clean.artist + ' - ' + clean.title + '.mp3'
|
||||||
|
|
||||||
console.log('Cleaning up..')
|
console.log('=> Original Title: ' + file.title + '\n')
|
||||||
console.log('Original Title: ' + s.title + '\n')
|
console.log('== Determined Title: ' + clean.title)
|
||||||
console.log('Determined Title: ' + clean.title)
|
console.log('== Determined Artist: ' + clean.artist)
|
||||||
console.log('Determined Artist: ' + clean.artist)
|
console.log('== Determined File Name: ' + filename)
|
||||||
console.log('Determined File Name: ' + filename)
|
|
||||||
|
|
||||||
rl.question(`Title [${clean.title}] ? `, (answer) => {
|
let titleAnsw = await asn.askAsync(rl, `Title [${clean.title}] ? `)
|
||||||
if (answer && answer.trim() !== '') {
|
let artistAnsw = await asn.askAsync(rl, `Artist [${clean.artist}] ? `)
|
||||||
clean.title = answer
|
let fileAnsw = await asn.askAsync(rl, `File [${filename}] ? `)
|
||||||
}
|
|
||||||
|
|
||||||
rl.question(`Artist [${clean.artist}] ? `, (answer) => {
|
if (titleAnsw && titleAnsw.trim() !== '') {
|
||||||
if (answer && answer.trim() !== '') {
|
clean.title = titleAnsw
|
||||||
clean.artist = answer
|
}
|
||||||
}
|
|
||||||
|
|
||||||
rl.question(`File [${filename}] ? `, (answer) => {
|
if (artistAnsw && artistAnsw.trim() !== '') {
|
||||||
if (answer && answer.trim() !== '') {
|
clean.artist = artistAnsw
|
||||||
filename = answer
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let fn = __dirname + '/' + filename
|
if (fileAnsw && fileAnsw.trim() !== '') {
|
||||||
fs.rename(s.source, fn, function (err) {
|
filename = fileAnsw
|
||||||
if (err) {
|
}
|
||||||
console.error(err)
|
|
||||||
return rl.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
let id3 = spawn('id3', ['-a', clean.artist, '-t', clean.title, fn])
|
let fn = path.join(musicdir, filename)
|
||||||
id3.on('close', () => {
|
await fs.rename(file.source, fn)
|
||||||
console.log('Saved as ' + fn)
|
|
||||||
rl.close()
|
let id3 = await asn.promiseExec(`id3 -a "${clean.artist}" -t "${clean.title}" "${fn}"`)
|
||||||
})
|
|
||||||
})
|
console.log('=> Done.')
|
||||||
})
|
rl.close()
|
||||||
})
|
}
|
||||||
})
|
|
||||||
|
download(process.argv[2]).catch((e) => {
|
||||||
|
console.error(e.message)
|
||||||
|
rl.close()
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user