diff options
Diffstat (limited to 'src/data/things')
| -rw-r--r-- | src/data/things/artist.js | 8 | ||||
| -rw-r--r-- | src/data/things/index.js | 2 | ||||
| -rw-r--r-- | src/data/things/music-video.js | 131 | ||||
| -rw-r--r-- | src/data/things/track.js | 25 |
4 files changed, 166 insertions, 0 deletions
diff --git a/src/data/things/artist.js b/src/data/things/artist.js index 01eb2172..439386f8 100644 --- a/src/data/things/artist.js +++ b/src/data/things/artist.js @@ -211,6 +211,14 @@ export class Artist extends Thing { }, ], + musicVideoArtistContributions: reverseReferenceList({ + reverse: soupyReverse.input('musicVideoArtistContributionsBy'), + }), + + musicVideoContributorContributions: reverseReferenceList({ + reverse: soupyReverse.input('musicVideoContributorContributionsBy'), + }), + totalDuration: [ withPropertyFromList('musicContributions', V('thing')), withPropertyFromList('#musicContributions.thing', V('isMainRelease')), diff --git a/src/data/things/index.js b/src/data/things/index.js index 09765fd2..35cd8cf2 100644 --- a/src/data/things/index.js +++ b/src/data/things/index.js @@ -21,6 +21,7 @@ import * as flashClasses from './flash.js'; import * as groupClasses from './group.js'; import * as homepageLayoutClasses from './homepage-layout.js'; import * as languageClasses from './language.js'; +import * as musicVideoClasses from './music-video.js'; import * as newsEntryClasses from './news-entry.js'; import * as sortingRuleClasses from './sorting-rule.js'; import * as staticPageClasses from './static-page.js'; @@ -40,6 +41,7 @@ const allClassLists = { 'group.js': groupClasses, 'homepage-layout.js': homepageLayoutClasses, 'language.js': languageClasses, + 'music-video.js': musicVideoClasses, 'news-entry.js': newsEntryClasses, 'sorting-rule.js': sortingRuleClasses, 'static-page.js': staticPageClasses, diff --git a/src/data/things/music-video.js b/src/data/things/music-video.js new file mode 100644 index 00000000..267349e8 --- /dev/null +++ b/src/data/things/music-video.js @@ -0,0 +1,131 @@ +import {inspect} from 'node:util'; + +import {colors} from '#cli'; +import {input, V} from '#composite'; +import find from '#find'; +import Thing from '#thing'; +import {isDate, isStringNonEmpty, isURL} from '#validators'; +import {parseContributors} from '#yaml'; + +import {exposeConstant, exposeUpdateValueOrContinue} + from '#composite/control-flow'; +import {constituteFrom} from '#composite/wiki-data'; + +import { + contributionList, + dimensions, + directory, + fileExtension, + soupyFind, + soupyReverse, + thing, + urls, +} from '#composite/wiki-properties'; + +export class MusicVideo extends Thing { + static [Thing.referenceType] = 'music-video'; + static [Thing.wikiData] = 'musicVideoData'; + + static [Thing.getPropertyDescriptors] = ({ArtTag}) => ({ + // Update & expose + + thing: thing(), + + label: { + flags: {update: true, expose: true}, + update: {validate: isStringNonEmpty}, + expose: {transform: value => value ?? 'Music video'}, + }, + + unqualifiedDirectory: directory({name: 'label'}), + + date: [ + exposeUpdateValueOrContinue({ + validate: input.value(isDate), + }), + + constituteFrom('thing', V('date')), + ], + + url: { + flags: {update: true, expose: true}, + update: {validate: isURL}, + }, + + coverArtFileExtension: fileExtension(V('jpg')), + coverArtDimensions: dimensions(), + + artistContribs: contributionList({ + artistProperty: input.value('musicVideoArtistContributions'), + }), + + contributorContribs: contributionList({ + artistProperty: input.value('musicVideoContributorContributions'), + }), + + // Update only + + find: soupyFind(), + }); + + static [Thing.yamlDocumentSpec] = { + fields: { + 'Label': {property: 'label'}, + 'Directory': {property: 'unqualifiedDirectory'}, + 'Date': {property: 'date'}, + 'URL': {property: 'url'}, + + 'Cover Art File Extension': {property: 'coverArtFileExtension'}, + 'Cover Art Dimensions': {property: 'coverArtDimensions'}, + + 'Artists': { + property: 'artistContribs', + transform: parseContributors, + }, + + 'Contributors': { + property: 'contributorContribs', + transform: parseContributors, + }, + }, + }; + + static [Thing.reverseSpecs] = { + musicVideoArtistContributionsBy: + soupyReverse.contributionsBy('musicVideoData', 'artistContribs'), + + musicVideoContributorContributionsBy: + soupyReverse.contributionsBy('musicVideoData', 'contributorContribs'), + }; + + get path() { + if (!this.thing) return null; + if (!this.thing.getOwnMusicVideoCoverPath) return null; + + return this.thing.getOwnMusicVideoCoverPath(this); + } + + [inspect.custom](depth, options, inspect) { + const parts = []; + + parts.push(Thing.prototype[inspect.custom].apply(this)); + + if (this.thing) { + if (depth >= 0) { + const newOptions = { + ...options, + depth: + (options.depth === null + ? null + : options.depth - 1), + }; + + parts.push(` for ${inspect(this.thing, newOptions)}`); + } else { + parts.push(` for ${colors.blue(Thing.getReference(this.thing))}`); + } + } + + return parts.join(''); + } +} diff --git a/src/data/things/track.js b/src/data/things/track.js index 3c4b5409..8652fbdf 100644 --- a/src/data/things/track.js +++ b/src/data/things/track.js @@ -31,6 +31,7 @@ import { parseDimensions, parseDuration, parseLyrics, + parseMusicVideos, } from '#yaml'; import { @@ -113,6 +114,7 @@ export class Track extends Thing { CommentaryEntry, CreditingSourcesEntry, LyricsEntry, + MusicVideo, ReferencingSourcesEntry, TrackSection, WikiInfo, @@ -488,6 +490,10 @@ export class Track extends Thing { }), ], + // > Update & expose - Music videos + + musicVideos: thingList(V(MusicVideo)), + // > Update & expose - Additional files additionalFiles: thingList(V(AdditionalFile)), @@ -993,6 +999,13 @@ export class Track extends Thing { 'Referenced Tracks': {property: 'referencedTracks'}, 'Sampled Tracks': {property: 'sampledTracks'}, + // Music videos + + 'Music Videos': { + property: 'musicVideos', + transform: parseMusicVideos, + }, + // Additional files 'Additional Files': { @@ -1216,6 +1229,18 @@ export class Track extends Thing { ]; } + getOwnMusicVideoCoverPath(musicVideo) { + if (!this.album) return null; + if (!musicVideo.unqualifiedDirectory) return null; + + return [ + 'media.trackCover', + this.album.directory, + this.directory + '-' + musicVideo.unqualifiedDirectory, + musicVideo.coverArtFileExtension, + ]; + } + countOwnContributionInContributionTotals(_contrib) { if (!this.countInArtistTotals) { return false; |