diff options
Diffstat (limited to 'src/data/things/track.js')
-rw-r--r-- | src/data/things/track.js | 919 |
1 files changed, 516 insertions, 403 deletions
diff --git a/src/data/things/track.js b/src/data/things/track.js index e176acb4..a8d59023 100644 --- a/src/data/things/track.js +++ b/src/data/things/track.js @@ -1,295 +1,259 @@ import {inspect} from 'node:util'; -import {color} from '#cli'; +import {colors} from '#cli'; import find from '#find'; import {empty} from '#sugar'; -import Thing from './thing.js'; +import { + compositeFrom, + exitWithoutDependency, + exposeConstant, + exposeDependency, + exposeDependencyOrContinue, + exposeUpdateValueOrContinue, + withPropertyFromObject, + withResultOfAvailabilityCheck, + withUpdateValueAsDependency, +} from '#composite'; + +import { + isColor, + isContributionList, + isDate, + isFileExtension, +} from '#validators'; + +import CacheableObject from './cacheable-object.js'; + +import Thing, { + additionalFiles, + commentary, + commentatorArtists, + contributionList, + directory, + duration, + flag, + name, + referenceList, + reverseReferenceList, + simpleDate, + singleReference, + simpleString, + urls, + wikiData, + withResolvedContribs, + withResolvedReference, + withReverseReferenceList, +} from './thing.js'; export class Track extends Thing { static [Thing.referenceType] = 'track'; - static [Thing.getPropertyDescriptors] = ({ - Album, - ArtTag, - Artist, - Flash, - - validators: { - isBoolean, - isColor, - isDate, - isDuration, - isFileExtension, - }, - }) => ({ + static [Thing.getPropertyDescriptors] = ({Album, ArtTag, Artist, Flash}) => ({ // Update & expose - name: Thing.common.name('Unnamed Track'), - directory: Thing.common.directory(), - - duration: { - flags: {update: true, expose: true}, - update: {validate: isDuration}, - }, - - urls: Thing.common.urls(), - dateFirstReleased: Thing.common.simpleDate(), - - artistContribsByRef: Thing.common.contribsByRef(), - contributorContribsByRef: Thing.common.contribsByRef(), - coverArtistContribsByRef: Thing.common.contribsByRef(), - - referencedTracksByRef: Thing.common.referenceList(Track), - sampledTracksByRef: Thing.common.referenceList(Track), - artTagsByRef: Thing.common.referenceList(ArtTag), - - hasCoverArt: { - flags: {update: true, expose: true}, - - update: { - validate(value) { - if (value !== false) { - throw new TypeError(`Expected false or null`); - } - - return true; - }, - }, - - expose: { - dependencies: ['albumData', 'coverArtistContribsByRef'], - transform: (hasCoverArt, { - albumData, - coverArtistContribsByRef, - [Track.instance]: track, - }) => - Track.hasCoverArt( - track, - albumData, - coverArtistContribsByRef, - hasCoverArt - ), - }, - }, - - coverArtFileExtension: { - flags: {update: true, expose: true}, + name: name('Unnamed Track'), + directory: directory(), + + duration: duration(), + urls: urls(), + dateFirstReleased: simpleDate(), + + color: [ + exposeUpdateValueOrContinue(), + + withContainingTrackSection(), + withPropertyFromObject({object: '#trackSection', property: 'color'}), + exposeDependencyOrContinue({dependency: '#trackSection.color'}), + + withPropertyFromAlbum({property: 'color'}), + exposeDependency({ + dependency: '#album.color', + update: {validate: isColor}, + }), + ], + + // Disables presenting the track as though it has its own unique artwork. + // This flag should only be used in select circumstances, i.e. to override + // an album's trackCoverArtists. This flag supercedes that property, as well + // as the track's own coverArtists. + disableUniqueCoverArt: flag(), + + // File extension for track's corresponding media file. This represents the + // track's unique cover artwork, if any, and does not inherit the extension + // of the album's main artwork. It does inherit trackCoverArtFileExtension, + // if present on the album. + coverArtFileExtension: [ + exitWithoutUniqueCoverArt(), + + exposeUpdateValueOrContinue(), + + withPropertyFromAlbum({property: 'trackCoverArtFileExtension'}), + exposeDependencyOrContinue({dependency: '#album.trackCoverArtFileExtension'}), + + exposeConstant({ + value: 'jpg', + update: {validate: isFileExtension}, + }), + ], + + // Date of cover art release. Like coverArtFileExtension, this represents + // only the track's own unique cover artwork, if any. This exposes only as + // the track's own coverArtDate or its album's trackArtDate, so if neither + // is specified, this value is null. + coverArtDate: [ + withHasUniqueCoverArt(), + exitWithoutDependency({dependency: '#hasUniqueCoverArt', mode: 'falsy'}), + + exposeUpdateValueOrContinue(), + + withPropertyFromAlbum({property: 'trackArtDate'}), + exposeDependency({ + dependency: '#album.trackArtDate', + update: {validate: isDate}, + }), + ], + + commentary: commentary(), + lyrics: simpleString(), + + additionalFiles: additionalFiles(), + sheetMusicFiles: additionalFiles(), + midiProjectFiles: additionalFiles(), + + originalReleaseTrack: singleReference({ + class: Track, + find: find.track, + data: 'trackData', + }), + + // Internal use only - for directly identifying an album inside a track's + // util.inspect display, if it isn't indirectly available (by way of being + // included in an album's track list). + dataSourceAlbum: singleReference({ + class: Album, + find: find.album, + data: 'albumData', + }), + + artistContribs: [ + inheritFromOriginalRelease({property: 'artistContribs'}), + + withUpdateValueAsDependency(), + withResolvedContribs({from: '#updateValue', into: '#artistContribs'}), + exposeDependencyOrContinue({dependency: '#artistContribs'}), + + withPropertyFromAlbum({property: 'artistContribs'}), + exposeDependency({ + dependency: '#album.artistContribs', + update: {validate: isContributionList}, + }), + ], + + contributorContribs: [ + inheritFromOriginalRelease({property: 'contributorContribs'}), + contributionList(), + ], - update: {validate: isFileExtension}, - - expose: { - dependencies: ['albumData', 'coverArtistContribsByRef'], - transform: (coverArtFileExtension, { - albumData, - coverArtistContribsByRef, - hasCoverArt, - [Track.instance]: track, - }) => - coverArtFileExtension ?? - (Track.hasCoverArt( - track, - albumData, - coverArtistContribsByRef, - hasCoverArt - ) - ? Track.findAlbum(track, albumData)?.trackCoverArtFileExtension - : Track.findAlbum(track, albumData)?.coverArtFileExtension) ?? - 'jpg', - }, - }, - - originalReleaseTrackByRef: Thing.common.singleReference(Track), - - dataSourceAlbumByRef: Thing.common.singleReference(Album), - - commentary: Thing.common.commentary(), - lyrics: Thing.common.simpleString(), - additionalFiles: Thing.common.additionalFiles(), - sheetMusicFiles: Thing.common.additionalFiles(), - midiProjectFiles: Thing.common.additionalFiles(), + // Cover artists aren't inherited from the original release, since it + // typically varies by release and isn't defined by the musical qualities + // of the track. + coverArtistContribs: [ + exitWithoutUniqueCoverArt(), + + withUpdateValueAsDependency(), + withResolvedContribs({from: '#updateValue', into: '#coverArtistContribs'}), + exposeDependencyOrContinue({dependency: '#coverArtistContribs'}), + + withPropertyFromAlbum({property: 'trackCoverArtistContribs'}), + exposeDependency({ + dependency: '#album.trackCoverArtistContribs', + update: {validate: isContributionList}, + }), + ], + + referencedTracks: [ + inheritFromOriginalRelease({property: 'referencedTracks'}), + referenceList({ + class: Track, + find: find.track, + data: 'trackData', + }), + ], + + sampledTracks: [ + inheritFromOriginalRelease({property: 'sampledTracks'}), + referenceList({ + class: Track, + find: find.track, + data: 'trackData', + }), + ], + + artTags: referenceList({ + class: ArtTag, + find: find.artTag, + data: 'artTagData', + }), // Update only - albumData: Thing.common.wikiData(Album), - artistData: Thing.common.wikiData(Artist), - artTagData: Thing.common.wikiData(ArtTag), - flashData: Thing.common.wikiData(Flash), - trackData: Thing.common.wikiData(Track), + albumData: wikiData(Album), + artistData: wikiData(Artist), + artTagData: wikiData(ArtTag), + flashData: wikiData(Flash), + trackData: wikiData(Track), // Expose only - commentatorArtists: Thing.common.commentatorArtists(), - - album: { - flags: {expose: true}, - - expose: { - dependencies: ['albumData'], - compute: ({[Track.instance]: track, albumData}) => - albumData?.find((album) => album.tracks.includes(track)) ?? null, - }, - }, - - // Note - this is an internal property used only to help identify a track. - // It should not be assumed in general that the album and dataSourceAlbum match - // (i.e. a track may dynamically be moved from one album to another, at - // which point dataSourceAlbum refers to where it was originally from, and is - // not generally relevant information). It's also not guaranteed that - // dataSourceAlbum is available (depending on the Track creator to optionally - // provide dataSourceAlbumByRef). - dataSourceAlbum: Thing.common.dynamicThingFromSingleReference( - 'dataSourceAlbumByRef', - 'albumData', - find.album - ), - - date: { - flags: {expose: true}, - - expose: { - dependencies: ['albumData', 'dateFirstReleased'], - compute: ({albumData, dateFirstReleased, [Track.instance]: track}) => - dateFirstReleased ?? Track.findAlbum(track, albumData)?.date ?? null, - }, - }, - - color: { - flags: {update: true, expose: true}, - - update: {validate: isColor}, - - expose: { - dependencies: ['albumData'], - - transform: (color, {albumData, [Track.instance]: track}) => - color ?? - Track.findAlbum(track, albumData) - ?.trackSections.find(({tracks}) => tracks.includes(track)) - ?.color ?? null, - }, - }, - - coverArtDate: { - flags: {update: true, expose: true}, - - update: {validate: isDate}, - - expose: { - dependencies: [ - 'albumData', - 'coverArtistContribsByRef', - 'dateFirstReleased', - 'hasCoverArt', - ], - transform: (coverArtDate, { - albumData, - coverArtistContribsByRef, - dateFirstReleased, - hasCoverArt, - [Track.instance]: track, - }) => - (Track.hasCoverArt(track, albumData, coverArtistContribsByRef, hasCoverArt) - ? coverArtDate ?? - dateFirstReleased ?? - Track.findAlbum(track, albumData)?.trackArtDate ?? - Track.findAlbum(track, albumData)?.date ?? - null - : null), - }, - }, - - hasUniqueCoverArt: { - flags: {expose: true}, - - expose: { - dependencies: ['albumData', 'coverArtistContribsByRef', 'hasCoverArt'], - compute: ({ - albumData, - coverArtistContribsByRef, - hasCoverArt, - [Track.instance]: track, - }) => - Track.hasUniqueCoverArt( - track, - albumData, - coverArtistContribsByRef, - hasCoverArt - ), - }, - }, - - originalReleaseTrack: Thing.common.dynamicThingFromSingleReference( - 'originalReleaseTrackByRef', - 'trackData', - find.track - ), - - otherReleases: { - flags: {expose: true}, - - expose: { - dependencies: ['originalReleaseTrackByRef', 'trackData'], - - compute: ({ - originalReleaseTrackByRef: t1origRef, - trackData, - [Track.instance]: t1, - }) => { - if (!trackData) { - return []; - } - - const t1orig = find.track(t1origRef, trackData); - - return [ - t1orig, - ...trackData.filter((t2) => { - const {originalReleaseTrack: t2orig} = t2; - return t2 !== t1 && t2orig && (t2orig === t1orig || t2orig === t1); - }), - ].filter(Boolean); + commentatorArtists: commentatorArtists(), + + album: [ + withAlbum(), + exposeDependency({dependency: '#album'}), + ], + + date: [ + exposeDependencyOrContinue({dependency: 'dateFirstReleased'}), + withPropertyFromAlbum({property: 'date'}), + exposeDependency({dependency: '#album.date'}), + ], + + // Whether or not the track has "unique" cover artwork - a cover which is + // specifically associated with this track in particular, rather than with + // the track's album as a whole. This is typically used to select between + // displaying the track artwork and a fallback, such as the album artwork + // or a placeholder. (This property is named hasUniqueCoverArt instead of + // the usual hasCoverArt to emphasize that it does not inherit from the + // album.) + hasUniqueCoverArt: [ + withHasUniqueCoverArt(), + exposeDependency({dependency: '#hasUniqueCoverArt'}), + ], + + otherReleases: [ + exitWithoutDependency({dependency: 'trackData', mode: 'empty'}), + withOriginalRelease({selfIfOriginal: true}), + + { + flags: {expose: true}, + expose: { + dependencies: ['this', 'trackData', '#originalRelease'], + compute: ({ + this: thisTrack, + trackData, + '#originalRelease': originalRelease, + }) => + (originalRelease === thisTrack + ? [] + : [originalRelease]) + .concat(trackData.filter(track => + track !== originalRelease && + track !== thisTrack && + track.originalReleaseTrack === originalRelease)), }, }, - }, - - artistContribs: - Track.inheritFromOriginalRelease('artistContribs', [], - Thing.common.dynamicInheritContribs( - null, - 'artistContribsByRef', - 'artistContribsByRef', - 'albumData', - Track.findAlbum)), - - contributorContribs: - Track.inheritFromOriginalRelease('contributorContribs', [], - Thing.common.dynamicContribs('contributorContribsByRef')), - - // Cover artists aren't inherited from the original release, since it - // typically varies by release and isn't defined by the musical qualities - // of the track. - coverArtistContribs: - Thing.common.dynamicInheritContribs( - 'hasCoverArt', - 'coverArtistContribsByRef', - 'trackCoverArtistContribsByRef', - 'albumData', - Track.findAlbum), - - referencedTracks: - Track.inheritFromOriginalRelease('referencedTracks', [], - Thing.common.dynamicThingsFromReferenceList( - 'referencedTracksByRef', - 'trackData', - find.track)), - - sampledTracks: - Track.inheritFromOriginalRelease('sampledTracks', [], - Thing.common.dynamicThingsFromReferenceList( - 'sampledTracksByRef', - 'trackData', - find.track)), + ], // Specifically exclude re-releases from this list - while it's useful to // get from a re-release to the tracks it references, re-releases aren't @@ -299,162 +263,311 @@ export class Track extends Thing { // counting the number of times a track has been referenced, for use in // the "Tracks - by Times Referenced" listing page (or other data // processing). - referencedByTracks: { - flags: {expose: true}, - - expose: { - dependencies: ['trackData'], - - compute: ({trackData, [Track.instance]: track}) => - trackData - ? trackData - .filter((t) => !t.originalReleaseTrack) - .filter((t) => t.referencedTracks?.includes(track)) - : [], - }, - }, + referencedByTracks: trackReverseReferenceList({ + property: 'referencedTracks', + }), // For the same reasoning, exclude re-releases from sampled tracks too. - sampledByTracks: { - flags: {expose: true}, - - expose: { - dependencies: ['trackData'], - - compute: ({trackData, [Track.instance]: track}) => - trackData - ? trackData - .filter((t) => !t.originalReleaseTrack) - .filter((t) => t.sampledTracks?.includes(track)) - : [], - }, - }, + sampledByTracks: trackReverseReferenceList({ + property: 'sampledTracks', + }), + + featuredInFlashes: reverseReferenceList({ + data: 'flashData', + list: 'featuredTracks', + }), + }); - featuredInFlashes: Thing.common.reverseReferenceList( - 'flashData', - 'featuredTracks' - ), + [inspect.custom](depth) { + const parts = []; - artTags: Thing.common.dynamicThingsFromReferenceList( - 'artTagsByRef', - 'artTagData', - find.artTag - ), - }); + parts.push(Thing.prototype[inspect.custom].apply(this)); - // This is a quick utility function for now, since the same code is reused in - // several places. Ideally it wouldn't be - we'd just reuse the `album` - // property - but support for that hasn't been coded yet :P - static findAlbum = (track, albumData) => - albumData?.find((album) => album.tracks.includes(track)); - - // Another reused utility function. This one's logic is a bit more complicated. - static hasCoverArt( - track, - albumData, - coverArtistContribsByRef, - hasCoverArt - ) { - if (!empty(coverArtistContribsByRef)) { - return true; + if (CacheableObject.getUpdateValue(this, 'originalReleaseTrack')) { + parts.unshift(`${colors.yellow('[rerelease]')} `); } - const album = Track.findAlbum(track, albumData); - if (album && !empty(album.trackCoverArtistContribsByRef)) { - return true; + let album; + if (depth >= 0 && (album = this.album ?? this.dataSourceAlbum)) { + const albumName = album.name; + const albumIndex = album.tracks.indexOf(this); + const trackNum = + (albumIndex === -1 + ? '#?' + : `#${albumIndex + 1}`); + parts.push(` (${colors.yellow(trackNum)} in ${colors.green(albumName)})`); } - return false; + return parts.join(''); } +} - static hasUniqueCoverArt( - track, - albumData, - coverArtistContribsByRef, - hasCoverArt - ) { - if (!empty(coverArtistContribsByRef)) { - return true; - } +// Early exits with a value inherited from the original release, if +// this track is a rerelease, and otherwise continues with no further +// dependencies provided. If allowOverride is true, then the continuation +// will also be called if the original release exposed the requested +// property as null. +function inheritFromOriginalRelease({ + property: originalProperty, + allowOverride = false, +}) { + return compositeFrom(`inheritFromOriginalRelease`, [ + withOriginalRelease(), + + { + dependencies: ['#originalRelease'], + compute({'#originalRelease': originalRelease}, continuation) { + if (!originalRelease) return continuation.raise(); + + const value = originalRelease[originalProperty]; + if (allowOverride && value === null) return continuation.raise(); + + return continuation.exit(value); + }, + }, + ]); +} - if (hasCoverArt === false) { - return false; - } +// Gets the track's album. This will early exit if albumData is missing. +// By default, if there's no album whose list of tracks includes this track, +// the output dependency will be null; set {notFoundMode: 'exit'} to early +// exit instead. +function withAlbum({ + into = '#album', + notFoundMode = 'null', +} = {}) { + return compositeFrom(`withAlbum`, [ + withResultOfAvailabilityCheck({ + fromDependency: 'albumData', + mode: 'empty', + into: '#albumDataAvailability', + }), + + { + dependencies: ['#albumDataAvailability'], + options: {notFoundMode}, + mapContinuation: {into}, + + compute: ({ + '#albumDataAvailability': albumDataAvailability, + '#options': {notFoundMode}, + }, continuation) => + (albumDataAvailability + ? continuation() + : (notFoundMode === 'exit' + ? continuation.exit(null) + : continuation.raise({into: null}))), + }, - const album = Track.findAlbum(track, albumData); - if (album && !empty(album.trackCoverArtistContribsByRef)) { - return true; - } + { + dependencies: ['this', 'albumData'], + compute: ({this: track, albumData}, continuation) => + continuation({ + '#album': albumData.find(album => album.tracks.includes(track)), + }), + }, - return false; - } + withResultOfAvailabilityCheck({ + fromDependency: '#album', + mode: 'null', + into: '#albumAvailability', + }), + + { + dependencies: ['#albumAvailability'], + options: {notFoundMode}, + mapContinuation: {into}, + + compute: ({ + '#albumAvailability': albumAvailability, + '#options': {notFoundMode}, + }, continuation) => + (albumAvailability + ? continuation() + : (notFoundMode === 'exit' + ? continuation.exit(null) + : continuation.raise({into: null}))), + }, - static inheritFromOriginalRelease( - originalProperty, - originalMissingValue, - ownPropertyDescriptor - ) { - return { - flags: {expose: true}, + { + dependencies: ['#album'], + mapContinuation: {into}, + compute: ({'#album': album}, continuation) => + continuation({into: album}), + }, + ]); +} - expose: { - dependencies: [ - ...ownPropertyDescriptor.expose.dependencies, - 'originalReleaseTrackByRef', - 'trackData', - ], - - compute(dependencies) { - const { - originalReleaseTrackByRef, - trackData, - } = dependencies; +// Gets a single property from this track's album, providing it as the same +// property name prefixed with '#album.' (by default). If the track's album +// isn't available, then by default, the property will be provided as null; +// set {notFoundMode: 'exit'} to early exit instead. +function withPropertyFromAlbum({ + property, + into = '#album.' + property, + notFoundMode = 'null', +}) { + return compositeFrom(`withPropertyFromAlbum`, [ + withAlbum({notFoundMode}), + withPropertyFromObject({object: '#album', property, into}), + ]); +} - if (originalReleaseTrackByRef) { - if (!trackData) return originalMissingValue; - const original = find.track(originalReleaseTrackByRef, trackData, {mode: 'quiet'}); - if (!original) return originalMissingValue; - return original[originalProperty]; - } +// Gets the track section containing this track from its album's track list. +// If notFoundMode is set to 'exit', this will early exit if the album can't be +// found or if none of its trackSections includes the track for some reason. +function withContainingTrackSection({ + into = '#trackSection', + notFoundMode = 'null', +} = {}) { + if (!['exit', 'null'].includes(notFoundMode)) { + throw new TypeError(`Expected notFoundMode to be exit or null`); + } - return ownPropertyDescriptor.expose.compute(dependencies); - }, + return compositeFrom(`withContainingTrackSection`, [ + withPropertyFromAlbum({property: 'trackSections', notFoundMode}), + + { + dependencies: ['this', '#album.trackSections'], + options: {notFoundMode}, + mapContinuation: {into}, + + compute({ + this: track, + '#album.trackSections': trackSections, + '#options': {notFoundMode}, + }, continuation) { + if (!trackSections) { + return continuation.raise({into: null}); + } + + const trackSection = + trackSections.find(({tracks}) => tracks.includes(track)); + + if (trackSection) { + return continuation.raise({into: trackSection}); + } else if (notFoundMode === 'exit') { + return continuation.exit(null); + } else { + return continuation.raise({into: null}); + } }, - }; - } + }, + ]); +} - [inspect.custom]() { - const base = Thing.prototype[inspect.custom].apply(this); +// Just includes the original release of this track as a dependency. +// If this track isn't a rerelease, then it'll provide null, unless the +// {selfIfOriginal} option is set, in which case it'll provide this track +// itself. Note that this will early exit if the original release is +// specified by reference and that reference doesn't resolve to anything. +// Outputs to '#originalRelease' by default. +function withOriginalRelease({ + into = '#originalRelease', + selfIfOriginal = false, +} = {}) { + return compositeFrom(`withOriginalRelease`, [ + withResolvedReference({ + ref: 'originalReleaseTrack', + data: 'trackData', + into: '#originalRelease', + find: find.track, + notFoundMode: 'exit', + }), + + { + dependencies: ['this', '#originalRelease'], + options: {selfIfOriginal}, + mapContinuation: {into}, + compute: ({ + this: track, + '#originalRelease': originalRelease, + '#options': {selfIfOriginal}, + }, continuation) => + continuation.raise({ + into: + (originalRelease ?? + (selfIfOriginal + ? track + : null)), + }), + }, + ]); +} - const rereleasePart = - (this.originalReleaseTrackByRef - ? `${color.yellow('[rerelease]')} ` - : ``); +// The algorithm for checking if a track has unique cover art is used in a +// couple places, so it's defined in full as a compositional step. +function withHasUniqueCoverArt({ + into = '#hasUniqueCoverArt', +} = {}) { + return compositeFrom(`withHasUniqueCoverArt`, [ + { + dependencies: ['disableUniqueCoverArt'], + mapContinuation: {into}, + compute: ({disableUniqueCoverArt}, continuation) => + (disableUniqueCoverArt + ? continuation.raise({into: false}) + : continuation()), + }, - const {album, dataSourceAlbum} = this; + withResolvedContribs({ + from: 'coverArtistContribs', + into: '#coverArtistContribs', + }), + + { + dependencies: ['#coverArtistContribs'], + mapContinuation: {into}, + compute: ({'#coverArtistContribs': contribsFromTrack}, continuation) => + (empty(contribsFromTrack) + ? continuation() + : continuation.raise({into: true})), + }, - const albumName = - (album - ? album.name - : dataSourceAlbum?.name); + withPropertyFromAlbum({property: 'trackCoverArtistContribs'}), - const albumIndex = - albumName && - (album - ? album.tracks.indexOf(this) - : dataSourceAlbum.tracks.indexOf(this)); + { + dependencies: ['#album.trackCoverArtistContribs'], + mapContinuation: {into}, + compute: ({'#album.trackCoverArtistContribs': contribsFromAlbum}, continuation) => + (empty(contribsFromAlbum) + ? continuation.raise({into: false}) + : continuation.raise({into: true})), + }, + ]); +} - const trackNum = - albumName && - (albumIndex === -1 - ? '#?' - : `#${albumIndex + 1}`); +// Shorthand for checking if the track has unique cover art and exposing a +// fallback value if it isn't. +function exitWithoutUniqueCoverArt({ + value = null, +} = {}) { + return compositeFrom(`exitWithoutUniqueCoverArt`, [ + withHasUniqueCoverArt(), + exitWithoutDependency({ + dependency: '#hasUniqueCoverArt', + mode: 'falsy', + value, + }), + ]); +} - const albumPart = - albumName - ? ` (${color.yellow(trackNum)} in ${color.green(albumName)})` - : ``; +function trackReverseReferenceList({ + property: refListProperty, +}) { + return compositeFrom(`trackReverseReferenceList`, [ + withReverseReferenceList({ + data: 'trackData', + list: refListProperty, + }), - return rereleasePart + base + albumPart; - } + { + flags: {expose: true}, + expose: { + dependencies: ['#reverseReferenceList'], + compute: ({'#reverseReferenceList': reverseReferenceList}) => + reverseReferenceList.filter(track => !track.originalReleaseTrack), + }, + }, + ]); } |