diff options
Diffstat (limited to 'src/data/things/album.js')
-rw-r--r-- | src/data/things/album.js | 719 |
1 files changed, 479 insertions, 240 deletions
diff --git a/src/data/things/album.js b/src/data/things/album.js index 6bf683c5..45cadc12 100644 --- a/src/data/things/album.js +++ b/src/data/things/album.js @@ -3,19 +3,23 @@ export const DATA_ALBUM_DIRECTORY = 'album'; import * as path from 'node:path'; import {inspect} from 'node:util'; +import CacheableObject from '#cacheable-object'; import {colors} from '#cli'; import {input} from '#composite'; import {traverse} from '#node-utils'; import {sortAlbumsTracksChronologically, sortChronologically} from '#sort'; -import {accumulateSum, empty} from '#sugar'; +import {empty} from '#sugar'; import Thing from '#thing'; -import {isColor, isDate, isDirectory} from '#validators'; +import {isColor, isDate, isDirectory, isNumber} from '#validators'; import { parseAdditionalFiles, parseAdditionalNames, parseAnnotatedReferences, + parseArtwork, + parseCommentary, parseContributors, + parseCreditingSources, parseDate, parseDimensions, parseWallpaperParts, @@ -24,16 +28,14 @@ import { import {exitWithoutDependency, exposeDependency, exposeUpdateValueOrContinue} from '#composite/control-flow'; import {withPropertyFromObject} from '#composite/data'; - -import {exitWithoutContribs, withDirectory, withCoverArtDate} +import {exitWithoutArtwork, withDirectory, withHasArtwork} from '#composite/wiki-data'; import { - additionalFiles, - additionalNameList, - commentary, color, commentatorArtists, + constitutibleArtwork, + constitutibleArtworkList, contentString, contribsPresent, contributionList, @@ -44,7 +46,6 @@ import { name, referencedArtworkList, referenceList, - reverseReferenceList, simpleDate, simpleString, soupyFind, @@ -56,20 +57,31 @@ import { wikiData, } from '#composite/wiki-properties'; -import {withTracks} from '#composite/things/album'; -import {withAlbum} from '#composite/things/track-section'; +import {withCoverArtDate, withTracks} from '#composite/things/album'; +import {withAlbum, withContinueCountingFrom, withStartCountingFrom} + from '#composite/things/track-section'; export class Album extends Thing { static [Thing.referenceType] = 'album'; static [Thing.getPropertyDescriptors] = ({ + AdditionalFile, + AdditionalName, ArtTag, + Artwork, + CommentaryEntry, + CreditingSourcesEntry, Group, - Track, TrackSection, WikiInfo, }) => ({ - // Update & expose + // > Update & expose - Internal relationships + + trackSections: thingList({ + class: input.value(TrackSection), + }), + + // > Update & expose - Identifying metadata name: name('Unnamed Album'), directory: directory(), @@ -90,104 +102,112 @@ export class Album extends Thing { alwaysReferenceTracksByDirectory: flag(false), suffixTrackDirectories: flag(false), - color: color(), - urls: urls(), - - additionalNames: additionalNameList(), - bandcampAlbumIdentifier: simpleString(), bandcampArtworkIdentifier: simpleString(), + additionalNames: thingList({ + class: input.value(AdditionalName), + }), + date: simpleDate(), - trackArtDate: simpleDate(), dateAddedToWiki: simpleDate(), + // > Update & expose - Credits and contributors + + artistContribs: contributionList({ + date: 'date', + artistProperty: input.value('albumArtistContributions'), + }), + + // > Update & expose - General configuration + + countTracksInArtistTotals: flag(true), + + hasTrackNumbers: flag(true), + isListedOnHomepage: flag(true), + isListedInGalleries: flag(true), + + // > Update & expose - General metadata + + color: color(), + + urls: urls(), + + // > Update & expose - Artworks + + coverArtworks: [ + // This works, lol, because this array describes `expose.transform` for + // the coverArtworks property, and compositions generally access the + // update value, not what's exposed by property access out in the open. + // There's no recursion going on here. + exitWithoutArtwork({ + contribs: 'coverArtistContribs', + artworks: 'coverArtworks', + value: input.value([]), + }), + + constitutibleArtworkList.fromYAMLFieldSpec + .call(this, 'Cover Artwork'), + ], + + coverArtistContribs: [ + withCoverArtDate(), + + contributionList({ + date: '#coverArtDate', + artistProperty: input.value('albumCoverArtistContributions'), + }), + ], + coverArtDate: [ - // ~~TODO: Why does this fall back, but Track.coverArtDate doesn't?~~ - // TODO: OK so it's because tracks don't *store* dates just like that. - // Really instead of fallback being a flag, it should be a date value, - // if this option is worth existing at all. withCoverArtDate({ from: input.updateValue({ validate: isDate, }), - - fallback: input.value(true), }), exposeDependency({dependency: '#coverArtDate'}), ], coverArtFileExtension: [ - exitWithoutContribs({contribs: 'coverArtistContribs'}), - fileExtension('jpg'), - ], - - trackCoverArtFileExtension: fileExtension('jpg'), + exitWithoutArtwork({ + contribs: 'coverArtistContribs', + artworks: 'coverArtworks', + }), - wallpaperFileExtension: [ - exitWithoutContribs({contribs: 'wallpaperArtistContribs'}), fileExtension('jpg'), ], - bannerFileExtension: [ - exitWithoutContribs({contribs: 'bannerArtistContribs'}), - fileExtension('jpg'), - ], - - wallpaperStyle: [ - exitWithoutContribs({contribs: 'wallpaperArtistContribs'}), - simpleString(), - ], - - wallpaperParts: [ - exitWithoutContribs({contribs: 'wallpaperArtistContribs'}), - wallpaperParts(), - ], - - bannerStyle: [ - exitWithoutContribs({contribs: 'bannerArtistContribs'}), - simpleString(), - ], - coverArtDimensions: [ - exitWithoutContribs({contribs: 'coverArtistContribs'}), - dimensions(), - ], - - trackDimensions: dimensions(), + exitWithoutArtwork({ + contribs: 'coverArtistContribs', + artworks: 'coverArtworks', + }), - bannerDimensions: [ - exitWithoutContribs({contribs: 'bannerArtistContribs'}), dimensions(), ], - hasTrackNumbers: flag(true), - isListedOnHomepage: flag(true), - isListedInGalleries: flag(true), - - commentary: commentary(), - creditSources: commentary(), - additionalFiles: additionalFiles(), - - trackSections: thingList({ - class: input.value(TrackSection), - }), - - artistContribs: contributionList({ - date: 'date', - artistProperty: input.value('albumArtistContributions'), - }), + artTags: [ + exitWithoutArtwork({ + contribs: 'coverArtistContribs', + artworks: 'coverArtworks', + value: input.value([]), + }), - coverArtistContribs: [ - withCoverArtDate({ - fallback: input.value(true), + referenceList({ + class: input.value(ArtTag), + find: soupyFind.input('artTag'), }), + ], - contributionList({ - date: '#coverArtDate', - artistProperty: input.value('albumCoverArtistContributions'), + referencedArtworks: [ + exitWithoutArtwork({ + contribs: 'coverArtistContribs', + artworks: 'coverArtworks', + value: input.value([]), }), + + referencedArtworkList(), ], trackCoverArtistContribs: contributionList({ @@ -200,80 +220,139 @@ export class Album extends Thing { artistProperty: input.value('trackCoverArtistContributions'), }), - wallpaperArtistContribs: [ - withCoverArtDate({ - fallback: input.value(true), + trackArtDate: simpleDate(), + + trackCoverArtFileExtension: fileExtension('jpg'), + + trackDimensions: dimensions(), + + wallpaperArtwork: [ + exitWithoutDependency({ + dependency: 'wallpaperArtistContribs', + mode: input.value('empty'), + value: input.value(null), }), + constitutibleArtwork.fromYAMLFieldSpec + .call(this, 'Wallpaper Artwork'), + ], + + wallpaperArtistContribs: [ + withCoverArtDate(), + contributionList({ date: '#coverArtDate', artistProperty: input.value('albumWallpaperArtistContributions'), }), ], - bannerArtistContribs: [ - withCoverArtDate({ - fallback: input.value(true), + wallpaperFileExtension: [ + exitWithoutArtwork({ + contribs: 'wallpaperArtistContribs', + artwork: 'wallpaperArtwork', + }), + + fileExtension('jpg'), + ], + + wallpaperStyle: [ + exitWithoutArtwork({ + contribs: 'wallpaperArtistContribs', + artwork: 'wallpaperArtwork', }), + simpleString(), + ], + + wallpaperParts: [ + // kinda nonsensical or at least unlikely lol, but y'know + exitWithoutArtwork({ + contribs: 'wallpaperArtistContribs', + artwork: 'wallpaperArtwork', + value: input.value([]), + }), + + wallpaperParts(), + ], + + bannerArtwork: [ + exitWithoutDependency({ + dependency: 'bannerArtistContribs', + mode: input.value('empty'), + value: input.value(null), + }), + + constitutibleArtwork.fromYAMLFieldSpec + .call(this, 'Banner Artwork'), + ], + + bannerArtistContribs: [ + withCoverArtDate(), + contributionList({ date: '#coverArtDate', artistProperty: input.value('albumBannerArtistContributions'), }), ], - groups: referenceList({ - class: input.value(Group), - find: soupyFind.input('group'), - }), - - artTags: [ - exitWithoutContribs({ - contribs: 'coverArtistContribs', - value: input.value([]), + bannerFileExtension: [ + exitWithoutArtwork({ + contribs: 'bannerArtistContribs', + artwork: 'bannerArtwork', }), - referenceList({ - class: input.value(ArtTag), - find: soupyFind.input('artTag'), - }), + fileExtension('jpg'), ], - referencedArtworks: [ - exitWithoutContribs({ - contribs: 'coverArtistContribs', - value: input.value([]), + bannerDimensions: [ + exitWithoutArtwork({ + contribs: 'bannerArtistContribs', + artwork: 'bannerArtwork', }), - { - dependencies: ['coverArtDate', 'date'], - compute: (continuation, { - coverArtDate, - date, - }) => continuation({ - ['#date']: - coverArtDate ?? date, - }), - }, + dimensions(), + ], - referencedArtworkList({ - date: '#date', + bannerStyle: [ + exitWithoutArtwork({ + contribs: 'bannerArtistContribs', + artwork: 'bannerArtwork', }), + + simpleString(), ], + // > Update & expose - Groups + + groups: referenceList({ + class: input.value(Group), + find: soupyFind.input('group'), + }), + + // > Update & expose - Content entries + + commentary: thingList({ + class: input.value(CommentaryEntry), + }), + + creditingSources: thingList({ + class: input.value(CreditingSourcesEntry), + }), + + // Additional files + + additionalFiles: thingList({ + class: input.value(AdditionalFile), + }), + // Update only find: soupyFind(), reverse: soupyReverse(), // used for referencedArtworkList (mixedFind) - albumData: wikiData({ - class: input.value(Album), - }), - - // used for referencedArtworkList (mixedFind) - trackData: wikiData({ - class: input.value(Track), + artworkData: wikiData({ + class: input.value(Artwork), }), // used for withMatchingContributionPresets (indirectly by Contribution) @@ -285,7 +364,15 @@ export class Album extends Thing { commentatorArtists: commentatorArtists(), - hasCoverArt: contribsPresent({contribs: 'coverArtistContribs'}), + hasCoverArt: [ + withHasArtwork({ + contribs: 'coverArtistContribs', + artworks: 'coverArtworks', + }), + + exposeDependency({dependency: '#hasArtwork'}), + ], + hasWallpaperArt: contribsPresent({contribs: 'wallpaperArtistContribs'}), hasBannerArt: contribsPresent({contribs: 'bannerArtistContribs'}), @@ -293,17 +380,6 @@ export class Album extends Thing { withTracks(), exposeDependency({dependency: '#tracks'}), ], - - referencedByArtworks: [ - exitWithoutContribs({ - contribs: 'coverArtistContribs', - value: input.value([]), - }), - - reverseReferenceList({ - reverse: soupyReverse.input('artworksWhichReference'), - }), - ], }); static [Thing.getSerializeDescriptors] = ({ @@ -379,6 +455,31 @@ export class Album extends Thing { ? [] : [album.name]), }, + + albumPrimaryArtwork: { + [Thing.findThisThingOnly]: false, + + referenceTypes: [ + 'album', + 'album-referencing-artworks', + 'album-referenced-artworks', + ], + + bindTo: 'artworkData', + + include: (artwork, {Artwork, Album}) => + artwork instanceof Artwork && + artwork.thing instanceof Album && + artwork === artwork.thing.coverArtworks[0], + + getMatchableNames: ({thing: album}) => + (album.alwaysReferenceByDirectory + ? [] + : [album.name]), + + getMatchableDirectories: ({thing: album}) => + [album.directory], + }, }; static [Thing.reverseSpecs] = { @@ -414,13 +515,13 @@ export class Album extends Thing { soupyReverse.contributionsBy('albumData', 'artistContribs'), albumCoverArtistContributionsBy: - soupyReverse.contributionsBy('albumData', 'coverArtistContribs'), + soupyReverse.artworkContributionsBy('albumData', 'coverArtworks'), albumWallpaperArtistContributionsBy: - soupyReverse.contributionsBy('albumData', 'wallpaperArtistContribs'), + soupyReverse.artworkContributionsBy('albumData', 'wallpaperArtwork', {single: true}), albumBannerArtistContributionsBy: - soupyReverse.contributionsBy('albumData', 'bannerArtistContribs'), + soupyReverse.artworkContributionsBy('albumData', 'bannerArtwork', {single: true}), albumsWithCommentaryBy: { bindTo: 'albumData', @@ -432,21 +533,14 @@ export class Album extends Thing { static [Thing.yamlDocumentSpec] = { fields: { - 'Album': {property: 'name'}, + // Identifying metadata + 'Album': {property: 'name'}, 'Directory': {property: 'directory'}, 'Directory Suffix': {property: 'directorySuffix'}, 'Suffix Track Directories': {property: 'suffixTrackDirectories'}, - 'Always Reference By Directory': {property: 'alwaysReferenceByDirectory'}, - 'Always Reference Tracks By Directory': { - property: 'alwaysReferenceTracksByDirectory', - }, - - 'Additional Names': { - property: 'additionalNames', - transform: parseAdditionalNames, - }, + 'Always Reference Tracks By Directory': {property: 'alwaysReferenceTracksByDirectory'}, 'Bandcamp Album ID': { property: 'bandcampAlbumIdentifier', @@ -458,41 +552,114 @@ export class Album extends Thing { transform: String, }, + 'Additional Names': { + property: 'additionalNames', + transform: parseAdditionalNames, + }, + 'Date': { property: 'date', transform: parseDate, }, - 'Color': {property: 'color'}, - 'URLs': {property: 'urls'}, + 'Date Added': { + property: 'dateAddedToWiki', + transform: parseDate, + }, + + // Credits and contributors + + 'Artists': { + property: 'artistContribs', + transform: parseContributors, + }, + + // General configuration + + 'Count Tracks In Artist Totals': {property: 'countInArtistTotals'}, 'Has Track Numbers': {property: 'hasTrackNumbers'}, 'Listed on Homepage': {property: 'isListedOnHomepage'}, 'Listed in Galleries': {property: 'isListedInGalleries'}, - 'Cover Art Date': { - property: 'coverArtDate', - transform: parseDate, + // General metadata + + 'Color': {property: 'color'}, + + 'URLs': {property: 'urls'}, + + // Artworks + // (Note - this YAML section is deliberately ordered differently + // than the corresponding property descriptors.) + + 'Cover Artwork': { + property: 'coverArtworks', + transform: + parseArtwork({ + thingProperty: 'coverArtworks', + dimensionsFromThingProperty: 'coverArtDimensions', + fileExtensionFromThingProperty: 'coverArtFileExtension', + dateFromThingProperty: 'coverArtDate', + artistContribsFromThingProperty: 'coverArtistContribs', + artistContribsArtistProperty: 'albumCoverArtistContributions', + artTagsFromThingProperty: 'artTags', + referencedArtworksFromThingProperty: 'referencedArtworks', + }), }, - 'Default Track Cover Art Date': { - property: 'trackArtDate', - transform: parseDate, + 'Banner Artwork': { + property: 'bannerArtwork', + transform: + parseArtwork({ + single: true, + thingProperty: 'bannerArtwork', + dimensionsFromThingProperty: 'bannerDimensions', + fileExtensionFromThingProperty: 'bannerFileExtension', + dateFromThingProperty: 'date', + artistContribsFromThingProperty: 'bannerArtistContribs', + artistContribsArtistProperty: 'albumBannerArtistContributions', + }), }, - 'Date Added': { - property: 'dateAddedToWiki', - transform: parseDate, + 'Wallpaper Artwork': { + property: 'wallpaperArtwork', + transform: + parseArtwork({ + single: true, + thingProperty: 'wallpaperArtwork', + dimensionsFromThingProperty: null, + fileExtensionFromThingProperty: 'wallpaperFileExtension', + dateFromThingProperty: 'date', + artistContribsFromThingProperty: 'wallpaperArtistContribs', + artistContribsArtistProperty: 'albumWallpaperArtistContributions', + }), }, - 'Cover Art File Extension': {property: 'coverArtFileExtension'}, - 'Track Art File Extension': {property: 'trackCoverArtFileExtension'}, + 'Cover Artists': { + property: 'coverArtistContribs', + transform: parseContributors, + }, + + 'Cover Art Date': { + property: 'coverArtDate', + transform: parseDate, + }, 'Cover Art Dimensions': { property: 'coverArtDimensions', transform: parseDimensions, }, + 'Default Track Cover Artists': { + property: 'trackCoverArtistContribs', + transform: parseContributors, + }, + + 'Default Track Cover Art Date': { + property: 'trackArtDate', + transform: parseDate, + }, + 'Default Track Dimensions': { property: 'trackDimensions', transform: parseDimensions, @@ -504,7 +671,6 @@ export class Album extends Thing { }, 'Wallpaper Style': {property: 'wallpaperStyle'}, - 'Wallpaper File Extension': {property: 'wallpaperFileExtension'}, 'Wallpaper Parts': { property: 'wallpaperParts', @@ -516,47 +682,51 @@ export class Album extends Thing { transform: parseContributors, }, - 'Banner Style': {property: 'bannerStyle'}, - 'Banner File Extension': {property: 'bannerFileExtension'}, - 'Banner Dimensions': { property: 'bannerDimensions', transform: parseDimensions, }, - 'Commentary': {property: 'commentary'}, - 'Credit Sources': {property: 'creditSources'}, + 'Banner Style': {property: 'bannerStyle'}, - 'Additional Files': { - property: 'additionalFiles', - transform: parseAdditionalFiles, - }, + 'Cover Art File Extension': {property: 'coverArtFileExtension'}, + 'Track Art File Extension': {property: 'trackCoverArtFileExtension'}, + 'Wallpaper File Extension': {property: 'wallpaperFileExtension'}, + 'Banner File Extension': {property: 'bannerFileExtension'}, + + 'Art Tags': {property: 'artTags'}, 'Referenced Artworks': { property: 'referencedArtworks', transform: parseAnnotatedReferences, }, - 'Franchises': {ignore: true}, + // Groups - 'Artists': { - property: 'artistContribs', - transform: parseContributors, + 'Groups': {property: 'groups'}, + + // Content entries + + 'Commentary': { + property: 'commentary', + transform: parseCommentary, }, - 'Cover Artists': { - property: 'coverArtistContribs', - transform: parseContributors, + 'Crediting Sources': { + property: 'creditingSources', + transform: parseCreditingSources, }, - 'Default Track Cover Artists': { - property: 'trackCoverArtistContribs', - transform: parseContributors, + // Additional files + + 'Additional Files': { + property: 'additionalFiles', + transform: parseAdditionalFiles, }, - 'Groups': {property: 'groups'}, - 'Art Tags': {property: 'artTags'}, + // Shenanigans + 'Franchises': {ignore: true}, 'Review Points': {ignore: true}, }, @@ -597,6 +767,12 @@ export class Album extends Thing { const trackSectionData = []; const trackData = []; + const artworkData = []; + const commentaryData = []; + const creditingSourceData = []; + const referencingSourceData = []; + const lyricsData = []; + for (const {header: album, entries} of results) { const trackSections = []; @@ -608,8 +784,6 @@ export class Album extends Thing { isDefaultTrackSection: true, }); - const albumRef = Thing.getReference(album); - const closeCurrentTrackSection = () => { if ( currentTrackSection.isDefaultTrackSection && @@ -636,17 +810,53 @@ export class Album extends Thing { currentTrackSectionTracks.push(entry); trackData.push(entry); - entry.dataSourceAlbum = albumRef; + // Set the track's album before accessing its list of artworks. + // The existence of its artwork objects may depend on access to + // its album's 'Default Track Cover Artists'. + entry.album = album; + + artworkData.push(...entry.trackArtworks); + commentaryData.push(...entry.commentary); + creditingSourceData.push(...entry.creditingSources); + referencingSourceData.push(...entry.referencingSources); + + // TODO: As exposed, Track.lyrics tries to inherit from the main + // release, which is impossible before the data's been linked. + // We just use the update value here. But it's icky! + lyricsData.push(...CacheableObject.getUpdateValue(entry, 'lyrics') ?? []); } closeCurrentTrackSection(); albumData.push(album); + artworkData.push(...album.coverArtworks); + + if (album.bannerArtwork) { + artworkData.push(album.bannerArtwork); + } + + if (album.wallpaperArtwork) { + artworkData.push(album.wallpaperArtwork); + } + + commentaryData.push(...album.commentary); + creditingSourceData.push(...album.creditingSources); + album.trackSections = trackSections; } - return {albumData, trackSectionData, trackData}; + return { + albumData, + trackSectionData, + trackData, + + artworkData, + commentaryData, + creditingSourceData, + referencingSourceData, + lyricsData, + }; }, sort({albumData, trackData}) { @@ -654,13 +864,65 @@ export class Album extends Thing { sortAlbumsTracksChronologically(trackData); }, }); + + getOwnAdditionalFilePath(_file, filename) { + return [ + 'media.albumAdditionalFile', + this.directory, + filename, + ]; + } + + getOwnArtworkPath(artwork) { + if (artwork === this.bannerArtwork) { + return [ + 'media.albumBanner', + this.directory, + artwork.fileExtension, + ]; + } + + if (artwork === this.wallpaperArtwork) { + if (!empty(this.wallpaperParts)) { + return null; + } + + return [ + 'media.albumWallpaper', + this.directory, + artwork.fileExtension, + ]; + } + + // TODO: using trackCover here is obviously, badly wrong + // but we ought to refactor banners and wallpapers similarly + // (i.e. depend on those intrinsic artwork paths rather than + // accessing media.{albumBanner,albumWallpaper} from content + // or other code directly) + return [ + 'media.trackCover', + this.directory, + + (artwork.unqualifiedDirectory + ? 'cover-' + artwork.unqualifiedDirectory + : 'cover'), + + artwork.fileExtension, + ]; + } + + // As of writing, albums don't even have a `duration` property... + // so this function will never be called... but the message stands... + countOwnContributionInDurationTotals(_contrib) { + return false; + } } export class TrackSection extends Thing { static [Thing.friendlyName] = `Track Section`; static [Thing.referenceType] = `track-section`; - static [Thing.getPropertyDescriptors] = ({Album, Track}) => ({ + static [Thing.getPropertyDescriptors] = ({Track}) => ({ // Update & expose name: name('Unnamed Track Section'), @@ -682,6 +944,14 @@ export class TrackSection extends Thing { exposeDependency({dependency: '#album.color'}), ], + startCountingFrom: [ + withStartCountingFrom({ + from: input.updateValue({validate: isNumber}), + }), + + exposeDependency({dependency: '#startCountingFrom'}), + ], + dateOriginallyReleased: simpleDate(), isDefaultTrackSection: flag(false), @@ -731,42 +1001,10 @@ export class TrackSection extends Thing { }, ], - startIndex: [ - withAlbum(), - - withPropertyFromObject({ - object: '#album', - property: input.value('trackSections'), - }), - - { - dependencies: ['#album.trackSections', input.myself()], - compute: (continuation, { - ['#album.trackSections']: trackSections, - [input.myself()]: myself, - }) => continuation({ - ['#index']: - trackSections.indexOf(myself), - }), - }, - - exitWithoutDependency({ - dependency: '#index', - mode: input.value('index'), - value: input.value(0), - }), + continueCountingFrom: [ + withContinueCountingFrom(), - { - dependencies: ['#album.trackSections', '#index'], - compute: ({ - ['#album.trackSections']: trackSections, - ['#index']: index, - }) => - accumulateSum( - trackSections - .slice(0, index) - .map(section => section.tracks.length)), - }, + exposeDependency({dependency: '#continueCountingFrom'}), ], }); @@ -797,6 +1035,7 @@ export class TrackSection extends Thing { fields: { 'Section': {property: 'name'}, 'Color': {property: 'color'}, + 'Start Counting From': {property: 'startCountingFrom'}, 'Date Originally Released': { property: 'dateOriginallyReleased', @@ -812,38 +1051,38 @@ export class TrackSection extends Thing { parts.push(Thing.prototype[inspect.custom].apply(this)); - if (depth >= 0) { + if (depth >= 0) showAlbum: { let album = null; try { album = this.album; - } catch {} + } catch { + break showAlbum; + } let first = null; try { - first = this.startIndex; + first = this.tracks.at(0).trackNumber; } catch {} - let length = null; + let last = null; try { - length = this.tracks.length; + last = this.tracks.at(-1).trackNumber; } catch {} - if (album) { - const albumName = album.name; - const albumIndex = album.trackSections.indexOf(this); + const albumName = album.name; + const albumIndex = album.trackSections.indexOf(this); - const num = - (albumIndex === -1 - ? 'indeterminate position' - : `#${albumIndex + 1}`); + const num = + (albumIndex === -1 + ? 'indeterminate position' + : `#${albumIndex + 1}`); - const range = - (albumIndex >= 0 && first !== null && length !== null - ? `: ${first + 1}-${first + length + 1}` - : ''); + const range = + (albumIndex >= 0 && first !== null && last !== null + ? `: ${first}-${last}` + : ''); - parts.push(` (${colors.yellow(num + range)} in ${colors.green(albumName)})`); - } + parts.push(` (${colors.yellow(num + range)} in ${colors.green(`"${albumName}"`)})`); } return parts.join(''); |