diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/duration-graph.js | 105 |
1 files changed, 85 insertions, 20 deletions
diff --git a/src/duration-graph.js b/src/duration-graph.js index 2ffdef7..47183c9 100644 --- a/src/duration-graph.js +++ b/src/duration-graph.js @@ -4,11 +4,21 @@ const fs = require('fs') const util = require('util') const processArgv = require('./process-argv') -const { updatePlaylistFormat, isGroup, isItem, getItemPathString } = require('./playlist-utils') +const { + updatePlaylistFormat, + isGroup, isItem, + getItemPathString, + flattenGrouplike +} = require('./playlist-utils') const readFile = util.promisify(fs.readFile) -const cachedDuration = Symbol('Cached duration') +const metrics = {} +metrics.duration = Symbol('Duration') +metrics.length = metrics.duration +metrics.time = metrics.duration +metrics.tracks = Symbol('# of tracks') +metrics.items = metrics.tracks function getUncachedDurationOfItem(item) { if (isGroup(item)) { @@ -26,11 +36,23 @@ function getUncachedDurationOfItem(item) { // This is mostly just to avoid logging out "item missing metadata" warnings // multiple times. function getDurationOfItem(item) { - if (cachedDuration in item === false) { - item[cachedDuration] = getUncachedDurationOfItem(item) + if (metrics.duration in item === false) { + item[metrics.duration] = getUncachedDurationOfItem(item) } - return item[cachedDuration] + return item[metrics.duration] +} + +function getTrackCount(item) { + if (metrics.tracks in item === false) { + if (isGroup(item)) { + item[metrics.tracks] = flattenGrouplike(item).items.length + } else { + item[metrics.tracks] = 1 + } + } + + return item[metrics.tracks] } const getHours = n => Math.floor(n / 3600) @@ -75,19 +97,48 @@ function padStartList(strings) { return strings.map(s => s.padStart(len, ' ')) } +function measureItem(item, metric) { + if (metric === metrics.duration) { + return getDurationOfItem(item) + } else if (metric === metrics.tracks) { + return getTrackCount(item) + } else { + throw new Error('Invalid metric: ' + metric) + } +} + function makePlaylistGraph(playlist, { graphWidth = 60, - onlyFirst = 20 + onlyFirst = 20, + metric = metrics.duration } = {}) { const output = [] - const wholePlaylistLength = getDurationOfItem(playlist) + const wholePlaylistLength = measureItem(playlist, metric) - let topThings = playlist.items.map((item, i) => ({ - item, - duration: getDurationOfItem(item), - digitalDuration: digitalFormatDuration(getDurationOfItem(item)) - })) + const briefFormatDuration = duration => { + if (metric === metrics.duration) { + return digitalFormatDuration(duration) + } else { + return duration.toString() + } + } + + const longFormatDuration = duration => { + if (metric === metrics.duration) { + return wordFormatDuration(duration) + } else if (metric === metrics.tracks) { + return `${duration} tracks` + } else { + return duration.toString() + } + } + + let topThings = playlist.items.map((item, i) => { + const duration = measureItem(item, metric) + const briefDuration = briefFormatDuration(duration) + return {item, duration, briefDuration} + }) topThings.sort((a, b) => b.duration - a.duration) @@ -97,11 +148,11 @@ function makePlaylistGraph(playlist, { const displayLength = topThings.reduce((a, b) => a + b.duration, 0) - // Left-pad the digital durations so they're all the same length. + // Left-pad the brief durations so they're all the same length. { - const len = topThings.reduce((a, b) => Math.max(a, b.digitalDuration.length), 0) + const len = topThings.reduce((a, b) => Math.max(a, b.briefDuration.length), 0) for (const obj of topThings) { - obj.digitalDuration = obj.digitalDuration.padStart(len, ' ') + obj.padDuration = obj.briefDuration.padStart(len, ' ') } } @@ -122,7 +173,7 @@ function makePlaylistGraph(playlist, { topThings[i].visualWidth = w } - output.push(' Whole length: ' + wordFormatDuration(wholePlaylistLength), '') + output.push(' Whole length: ' + longFormatDuration(wholePlaylistLength), '') output.push(' ' + topThings.map(({ bgColor, fgColor, visualWidth }) => { return bgColor + fgColor + '-'.repeat(visualWidth) @@ -130,15 +181,16 @@ function makePlaylistGraph(playlist, { output.push(' Length by item:') - output.push(...topThings.map(({ item, digitalDuration, visualWidth, fgColor }) => + output.push(...topThings.map(({ item, padDuration, visualWidth, fgColor }) => ` ${fgColor}${ // Dim the row if it doesn't show up in the graph. visualWidth === 0 ? '\x1b[2m- ' : ' ' - }${digitalDuration} ${item.name}\x1b[0m` + }${padDuration} ${item.name}\x1b[0m` )) if (ignoredThings.length) { - const dur = wordFormatDuration(ignoredThings.reduce((a, b) => a + b.duration, 0)) + const totalDuration = ignoredThings.reduce((a, b) => a + b.duration, 0) + const dur = longFormatDuration(totalDuration) output.push( ` \x1b[2m(* Plus ${ignoredThings.length} skipped items, accounting `, ` for ${dur}.)\x1b[0m` @@ -163,8 +215,21 @@ async function main(args) { let graphWidth = 60 let onlyFirst = 20 + let metric = metrics.duration await processArgv(args.slice(1), { + '-metric': util => { + const arg = util.nextArg() + if (Object.keys(metrics).includes(arg)) { + metric = metrics[arg] + } else { + console.warn('Didn\'t set metric because it isn\'t recognized:', arg) + } + }, + + '-measure': util => util.alias('-metric'), + 'm': util => util.alias('-metric'), + '-graph-width': util => { const arg = util.nextArg() const newVal = parseInt(arg) @@ -201,7 +266,7 @@ async function main(args) { const playlist = updatePlaylistFormat(JSON.parse(await readFile(args[0]))) for (const line of makePlaylistGraph(playlist, { - graphWidth, onlyFirst + graphWidth, onlyFirst, metric })) { console.log(line) } |