From 55e4afead38bc541cba4ae1cef183527c254f99a Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 21 Aug 2023 17:28:15 -0300 Subject: data: track: experimental Thing.compose.from() processing style --- src/data/things/track.js | 290 ++++++++++++++++++++++++----------------------- 1 file changed, 148 insertions(+), 142 deletions(-) (limited to 'src/data/things/track.js') diff --git a/src/data/things/track.js b/src/data/things/track.js index 39c2930f..fe6af205 100644 --- a/src/data/things/track.js +++ b/src/data/things/track.js @@ -54,49 +54,53 @@ export class Track extends Thing { // track's unique cover artwork, if any, and does not inherit the cover's // main artwork. (It does inherit `trackCoverArtFileExtension` if present // on the album.) - coverArtFileExtension: { - flags: {update: true, expose: true}, - - update: {validate: isFileExtension}, - - expose: Track.withAlbumProperties(['trackCoverArtistContribsByRef', 'trackCoverArtFileExtension'], { - dependencies: ['coverArtistContribsByRef', 'disableUniqueCoverArt'], - - transform(coverArtFileExtension, { - coverArtistContribsByRef, - disableUniqueCoverArt, - album: {trackCoverArtistContribsByRef, trackCoverArtFileExtension}, - }) { - if (disableUniqueCoverArt) return null; - if (empty(coverArtistContribsByRef) && empty(trackCoverArtistContribsByRef)) return null; - return coverArtFileExtension ?? trackCoverArtFileExtension ?? 'jpg'; + coverArtFileExtension: Thing.composite.from([ + Track.withAlbumProperties(['trackCoverArtistContribsByRef', 'trackCoverArtFileExtension']), + + { + flags: {update: true, expos: true}, + update: {validate: isFileExtension}, + expose: { + dependencies: ['coverArtistContribsByRef', 'disableUniqueCoverArt'], + + transform(coverArtFileExtension, { + coverArtistContribsByRef, + disableUniqueCoverArt, + album: {trackCoverArtistContribsByRef, trackCoverArtFileExtension}, + }) { + if (disableUniqueCoverArt) return null; + if (empty(coverArtistContribsByRef) && empty(trackCoverArtistContribsByRef)) return null; + return coverArtFileExtension ?? trackCoverArtFileExtension ?? 'jpg'; + }, }, - }), - }, + }, + ]), // 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: { - flags: {update: true, expose: true}, - - update: {validate: isDate}, - - expose: Track.withAlbumProperties(['trackArtDate', 'trackCoverArtistContribsByRef'], { - dependencies: ['coverArtistContribsByRef', 'disableUniqueCoverArt'], - - transform(coverArtDate, { - coverArtistContribsByRef, - disableUniqueCoverArt, - album: {trackArtDate, trackCoverArtistContribsByRef}, - }) { - if (disableUniqueCoverArt) return null; - if (empty(coverArtistContribsByRef) && empty(trackCoverArtistContribsByRef)) return null; - return coverArtDate ?? trackArtDate; + coverArtDate: Thing.composite.from([ + Track.withAlbumProperties(['trackArtDate', 'trackCoverArtistContribsByRef']), + + { + flags: {update: true, expose: true}, + update: {validate: isDate}, + expose: { + dependencies: ['coverArtistContribsByRef', 'disableUniqueCoverArt'], + + transform(coverArtDate, { + coverArtistContribsByRef, + disableUniqueCoverArt, + album: {trackArtDate, trackCoverArtistContribsByRef}, + }) { + if (disableUniqueCoverArt) return null; + if (empty(coverArtistContribsByRef) && empty(trackCoverArtistContribsByRef)) return null; + return coverArtDate ?? trackArtDate; + }, }, - }), - }, + } + ]), originalReleaseTrackByRef: Thing.common.singleReference(Track), @@ -176,23 +180,26 @@ export class Track extends Thing { // or a placeholder. (This property is named hasUniqueCoverArt instead of // the usual hasCoverArt to emphasize that it does not inherit from the // album.) - hasUniqueCoverArt: { - flags: {expose: true}, - - expose: Track.withAlbumProperties(['trackCoverArtistContribsByRef'], { - dependencies: ['coverArtistContribsByRef', 'disableUniqueCoverArt'], - compute({ - coverArtistContribsByRef, - disableUniqueCoverArt, - album: {trackCoverArtistContribsByRef}, - }) { - if (disableUniqueCoverArt) return false; - if (!empty(coverArtistContribsByRef)) true; - if (!empty(trackCoverArtistContribsByRef)) return true; - return false; + hasUniqueCoverArt: Thing.composite.from([ + Track.withAlbumProperties(['trackCoverArtistContribsByRef']), + + { + flags: {expose: true}, + expose: { + dependencies: ['coverArtistContribsByRef', 'disableUniqueCoverArt'], + compute({ + coverArtistContribsByRef, + disableUniqueCoverArt, + album: {trackCoverArtistContribsByRef}, + }) { + if (disableUniqueCoverArt) return false; + if (!empty(coverArtistContribsByRef)) true; + if (!empty(trackCoverArtistContribsByRef)) return true; + return false; + }, }, - }), - }, + }, + ]), originalReleaseTrack: Thing.common.dynamicThingFromSingleReference( 'originalReleaseTrackByRef', @@ -228,43 +235,70 @@ export class Track extends Thing { }, }, - artistContribs: - Track.inheritFromOriginalRelease('artistContribs', [], - Thing.common.dynamicInheritContribs( - null, - 'artistContribsByRef', - 'artistContribsByRef', - 'albumData', - Track.findAlbum)), + artistContribs: Thing.composite.from([ + Track.inheritFromOriginalRelease('artistContribs'), + + { + flags: {expose: true}, + expose: { + dependencies: ['artistContribs'], + + compute({ + artistContribsByRef: contribsFromTrack, + album: {artistContribsByRef: contribsFromAlbum}, + }) { + let contribsByRef = contribsFromTrack; + if (empty(contribsByRef)) contribsByRef = contribsFromAlbum; + if (empty(contribsByRef)) return null; - contributorContribs: - Track.inheritFromOriginalRelease('contributorContribs', [], - Thing.common.dynamicContribs('contributorContribsByRef')), + return Thing.findArtistsFromContribs(contribsByRef, artistData); + }, + }, + }, + ]), + + contributorContribs: Thing.composite.from([ + 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)), + coverArtistContribs: Thing.composite.from([ + Track.withAlbumProperties(['trackCoverArtistContribsByRef']), + + { + flags: {expose: true}, + expose: { + dependencies: ['coverArtistContribsByRef', 'disableUniqueCoverArt'], + + compute({ + coverArtistContribsByRef: contribsFromTrack, + disableUniqueCoverArt, + album: {trackCoverArtistContribsByRef: contribsFromAlbum}, + }) { + if (disableUniqueCoverArt) return null; + + let contribsByRef = contribsFromTrack; + if (empty(contribsByRef)) contribsByRef = contribsFromAlbum; + if (empty(contribsByRef)) return null; + + return Thing.findArtistsFromContribs(contribsByRef, artistData); + }, + }, + }, + ]), + + referencedTracks: Thing.composite.from([ + Track.inheritFromOriginalRelease('referencedTracks'), + Thing.common.dynamicThingsFromReferenceList('referencedTracksByRef', 'trackData', find.track), + ]), + + sampledTracks: Thing.composite.from([ + 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 @@ -317,72 +351,44 @@ export class Track extends Thing { ), }); - static inheritFromOriginalRelease( - originalProperty, - originalMissingValue, - ownPropertyDescriptor - ) { - return { - flags: {expose: true}, + static inheritFromOriginalRelease = originalProperty => ({ + flags: {expose: true, compose: true}, - expose: { - dependencies: [ - ...ownPropertyDescriptor.expose.dependencies, - 'originalReleaseTrackByRef', - 'trackData', - ], - - compute(dependencies) { - const { - originalReleaseTrackByRef, - trackData, - } = dependencies; - - if (originalReleaseTrackByRef) { - if (!trackData) return originalMissingValue; - const original = find.track(originalReleaseTrackByRef, trackData, {mode: 'quiet'}); - if (!original) return originalMissingValue; - return original[originalProperty]; - } + expose: { + dependencies: ['originalReleaseTrackByRef', 'trackData'], - return ownPropertyDescriptor.expose.compute(dependencies); - }, - }, - }; - } + compute({originalReleaseTrackByRef, trackData}, callback) { + if (!originalReleaseTrackByRef) return callback(); - static withAlbumProperties(albumProperties, oldExpose) { - const applyAlbumDependency = dependencies => { - const track = dependencies[Track.instance]; - const album = - dependencies.albumData - ?.find((album) => album.tracks.includes(track)); - - const filteredAlbum = Object.create(null); - for (const property of albumProperties) { - filteredAlbum[property] = - (album - ? album[property] - : null); - } + if (!trackData) return null; + const original = find.track(originalReleaseTrackByRef, trackData, {mode: 'quiet'}); + if (!original) return null; + return original[originalProperty]; + }, + }, + }); - return {...dependencies, album: filteredAlbum}; - }; + static withAlbumProperties = albumProperties => ({ + flags: {expose: true, compose: true}, - const newExpose = {dependencies: [...oldExpose.dependencies, 'albumData']}; + expose: { + dependencies: ['albumData'], - if (oldExpose.compute) { - newExpose.compute = dependencies => - oldExpose.compute(applyAlbumDependency(dependencies)); - } + compute({albumData, [Track.instance]: track}, callback) { + const album = albumData?.find((album) => album.tracks.includes(track)); - if (oldExpose.transform) { - newExpose.transform = (value, dependencies) => - oldExpose.transform(value, applyAlbumDependency(dependencies)); - } + const filteredAlbum = Object.create(null); + for (const property of albumProperties) { + filteredAlbum[property] = + (album + ? album[property] + : null); + } - return newExpose; - } + return callback({album: filteredAlbum}); + }, + }, + }); [inspect.custom]() { const base = Thing.prototype[inspect.custom].apply(this); -- cgit 1.3.0-6-gf8a5