From 18435f58f82849dcc86ab2042491828b2873b39a Mon Sep 17 00:00:00 2001 From: Florrie Date: Fri, 5 Jan 2018 23:20:58 -0400 Subject: WIP(?) metadata processing tool --- src/process-metadata.js | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/process-metadata.js (limited to 'src/process-metadata.js') diff --git a/src/process-metadata.js b/src/process-metadata.js new file mode 100644 index 0000000..43ffe62 --- /dev/null +++ b/src/process-metadata.js @@ -0,0 +1,108 @@ +const fs = require('fs') +const processArgv = require('./process-argv') +const promisifyProcess = require('./promisify-process') +const { spawn } = require('child_process') +const { promisify } = require('util') +const { showTrackProcessStatus } = require('./general-util') +const { updatePlaylistFormat, flattenGrouplike } = require('./playlist-utils') + +const readFile = promisify(fs.readFile) +const writeFile = promisify(fs.writeFile) + +async function probe(filePath) { + const ffprobe = spawn('ffprobe', [ + '-print_format', 'json', + '-show_entries', 'stream=codec_name:format', + '-select_streams', 'a:0', + '-v', 'quiet', + filePath + ]) + + let probeDataString = '' + + ffprobe.stdout.on('data', data => { + probeDataString += data + }) + + await promisifyProcess(ffprobe, false) + + return JSON.parse(probeDataString) +} + +async function main(args) { + if (args.length < 2) { + console.error('Usage: http-music process-metadata (..args..)') + console.error('See \x1b[1mman http-music-process-metadata\x1b[0m!') + return false + } + + const inFile = args[0] + const outFile = args[1] + + // Whether or not to save actual audio tag data. (This includes things like + // genre, track #, and album, as well as any non-standard data set on the + // file.) + let saveTags = false + + // Whether or not to skip tracks which have already been processed. + let skipCompleted = true + + await processArgv(args.slice(1), { + '-save-tags': function() { + saveTags = true + }, + + '-tags': util => util.alias('-save-tags'), + 't': util => util.alias('-save-tags'), + + '-skip-completed': function() { + skipCompleted = true + }, + + '-skip-done': util => util.alias('-skip-completed'), + '-faster': util => util.alias('-skip-completed'), + + '-no-skip-completed': function() { + skipCompleted = false + }, + + '-no-skip-done': util => util.alias('-no-skip-completed'), + '-slower': util => util.alias('-no-skip-completed') + }) + + let doneCount = 0 + + const playlist = updatePlaylistFormat(JSON.parse(await readFile(args[0]))) + + const flattened = flattenGrouplike(playlist) + for (const item of flattened.items) { + if (!(skipCompleted && 'metadata' in item)) { + const probeData = await probe(item.downloaderArg) + + item.metadata = Object.assign(item.metadata || {}, { + duration: parseInt(probeData.format.duration), + size: parseInt(probeData.format.size), + bitrate: parseInt(probeData.format.bit_rate) + }) + + if (saveTags) { + item.metadata.tags = probeData.tags + } + } + + doneCount++ + showTrackProcessStatus(flattened.items.length, doneCount, true) + process.stdout.write(' \r') + } + + await writeFile(outFile, JSON.stringify(playlist, null, 2)) + + console.log(`\nDone! Processed ${flattened.items.length} tracks.`) +} + +module.exports = main + +if (require.main === module) { + main(process.argv.slice(2)) + .catch(err => console.error(err)) +} -- cgit 1.3.0-6-gf8a5