From 75251bb2309505c20dc7500117a17649d41412d8 Mon Sep 17 00:00:00 2001 From: Florrie Date: Mon, 25 Feb 2019 11:27:11 -0400 Subject: Metadata (in memory) --- ui.js | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 5 deletions(-) (limited to 'ui.js') diff --git a/ui.js b/ui.js index 12ef4b2..3fbaa51 100644 --- a/ui.js +++ b/ui.js @@ -1,8 +1,9 @@ const { getAllCrawlersForArg } = require('./crawlers') +const { getMetadataReaderFor } = require('./metadata-readers') const { getDownloaderFor } = require('./downloaders') const { getPlayer } = require('./players') const { parentSymbol, isGroup, isTrack, getItemPath, getItemPathString, flattenGrouplike, countTotalItems, shuffleOrderOfGroups, cloneGrouplike } = require('./playlist-utils') -const { shuffleArray } = require('./general-util') +const { shuffleArray, throttlePromise, getTimeStringsFromSec } = require('./general-util') const processSmartPlaylist = require('./smart-playlist') const UndoManager = require('./undo-manager') const RecordStore = require('./record-store') @@ -40,6 +41,8 @@ class AppElement extends FocusElement { this.player = null this.recordStore = new RecordStore() this.undoManager = new UndoManager() + this.throttleMetadata = throttlePromise(10) + this.metadataDictionary = {} this.queueGrouplike = {name: 'Queue', isTheQueue: true, items: []} this.markGrouplike = {name: 'Marked', items: []} this.editMode = false @@ -284,6 +287,7 @@ class AppElement extends FocusElement { {label: 'Queue!', action: emitControls(false)}, {divider: true}, + {label: 'Process metadata', action: () => this.processMetadata(item)}, {label: 'Remove from queue', action: () => this.unqueueGrouplikeItem(item)} ] } @@ -867,6 +871,26 @@ class AppElement extends FocusElement { this.stopPlaying() this.playbackInfoElement.clearInfo() } + + processMetadata(item) { + if (isGroup(item)) { + return Promise.all(item.items.map(x => this.processMetadata(x))) + } + + return this.throttleMetadata(async () => { + const filePath = await this.downloadGrouplikeItem(item) + const metadataReader = getMetadataReaderFor(filePath) + const data = await metadataReader(filePath) + + this.metadataDictionary[item.downloaderArg] = filePath + this.metadataDictionary[filePath] = data + }) + } + + getMetadataFor(item) { + const key = this.metadataDictionary[item.downloaderArg] + return this.metadataDictionary[key] || null + } } class GrouplikeListingElement extends Form { @@ -1033,6 +1057,10 @@ class GrouplikeListingElement extends Form { const itemElement = new InteractiveGrouplikeItemElement(item, this.app) this.addEventListeners(itemElement) form.addInput(itemElement) + + if (this.grouplike.isTheQueue) { + itemElement.hideMetadata = true + } } } else if (!this.grouplike.isTheQueue) { form.addInput(new BasicGrouplikeItemElement('(This group is empty)')) @@ -1213,7 +1241,10 @@ class BasicGrouplikeItemElement extends Button { constructor(text) { super() + this._text = this._rightText = '' + this.text = text + this.rightText = '' this.drawText = '' } @@ -1224,11 +1255,45 @@ class BasicGrouplikeItemElement extends Button { this.computeText() } + set text(val) { + if (this._text !== val) { + this._text = val + this.computeText() + } + } + + get text() { + return this._text + } + + set rightText(val) { + if (this._rightText !== val) { + this._rightText = val + this.computeText() + } + } + + get rightText() { + return this._rightText + } + computeText() { let text = '' let done = false let heckingWatchOut = false + // TODO: Hide right text if there's not enough columns (plus some padding) + + // 3 = width of status line, basically + let w = this.w - this.x - 3 + + // Also make space for the right text - if we choose to show it. + const rightTextCols = ansi.measureColumns(this.rightText) + const showRightText = (w - rightTextCols > 12) + if (showRightText) { + w -= rightTextCols + } + const writable = { write: characters => { if (heckingWatchOut && done) { @@ -1237,8 +1302,7 @@ class BasicGrouplikeItemElement extends Button { for (const char of characters) { if (heckingWatchOut) { - // 3 = width of status line, basically - if (ansi.measureColumns(text + char) + 3 <= this.w - this.x) { + if (ansi.measureColumns(text + char) <= w) { text += char } else { done = true @@ -1258,8 +1322,10 @@ class BasicGrouplikeItemElement extends Button { heckingWatchOut = false const width = ansi.measureColumns(this.text) - // again, 3 = width of status bar - writable.write(' '.repeat(Math.max(0, this.w - width - 3))) + writable.write(' '.repeat(Math.max(0, w - width))) + if (showRightText) { + writable.write(this.rightText) + } writable.write(ansi.resetAttributes()) this.drawText = text @@ -1422,9 +1488,18 @@ class InteractiveGrouplikeItemElement extends BasicGrouplikeItemElement { super(item.name) this.item = item this.app = app + this.hideMetadata = false } drawTo(writable) { + if (!this.hideMetadata) { + const metadata = this.app.getMetadataFor(this.item) + if (metadata) { + const durationString = getTimeStringsFromSec(0, metadata.duration).duration + this.rightText = ` (${durationString}) ` + } + } + this.text = this.item.name super.drawTo(writable) } -- cgit 1.3.0-6-gf8a5