diff --git a/harmonizer/types.ts b/harmonizer/types.ts index 1852877c..af10b07d 100644 --- a/harmonizer/types.ts +++ b/harmonizer/types.ts @@ -4,7 +4,7 @@ import type { EntityType } from '@kellnerd/musicbrainz'; import type { ReleasePackaging, ReleaseStatus } from '@kellnerd/musicbrainz/data/release'; import type { ReleaseGroupType } from '@kellnerd/musicbrainz/data/release-group'; export type { ReleaseGroupType } from '@kellnerd/musicbrainz/data/release-group'; -import type { PartialDate } from '../utils/date.ts'; +import type { ReleaseDate } from '../utils/date.ts'; import type { ScriptFrequency } from '../utils/script.ts'; /** MusicBrainz entity types which Harmony supports. */ @@ -52,7 +52,7 @@ export type HarmonyRelease = { script?: ScriptFrequency; status?: ReleaseStatus; types?: ReleaseGroupType[]; - releaseDate?: PartialDate; + releaseDate?: ReleaseDate; labels?: Label[]; packaging?: ReleasePackaging; images?: Artwork[]; diff --git a/musicbrainz/seeding.ts b/musicbrainz/seeding.ts index 1d07eea3..bd39c167 100644 --- a/musicbrainz/seeding.ts +++ b/musicbrainz/seeding.ts @@ -77,7 +77,7 @@ export function createReleaseSeed(release: HarmonyRelease, options: ReleaseSeedO release_group: release.releaseGroup?.mbid, barcode: release.gtin?.toString(), events: countries.map((country) => ({ - date: release.releaseDate, + date: release.releaseDate?.date, country, })), labels: release.labels?.map((label) => ({ diff --git a/providers/Bandcamp/__snapshots__/mod.test.ts.snap b/providers/Bandcamp/__snapshots__/mod.test.ts.snap index b6449011..cd9aa10a 100644 --- a/providers/Bandcamp/__snapshots__/mod.test.ts.snap +++ b/providers/Bandcamp/__snapshots__/mod.test.ts.snap @@ -128,9 +128,12 @@ suika.love", ], packaging: "None", releaseDate: { - day: 17, - month: 7, - year: 2019, + date: { + day: 17, + month: 7, + year: 2019, + }, + quality: "assumed-valid", }, status: "Official", title: "and it was a burned into my mind! yet i faltered like a broken record", @@ -220,9 +223,12 @@ snapshot[`Bandcamp provider > release lookup > subscriber-only release 1`] = ` ], packaging: "None", releaseDate: { - day: 30, - month: 4, - year: 2025, + date: { + day: 30, + month: 4, + year: 2025, + }, + quality: "assumed-valid", }, status: "Official", title: "Des papiers II", @@ -320,9 +326,12 @@ All the things, Steve. Cover model: Flapjack.", ], packaging: "None", releaseDate: { - day: 4, - month: 7, - year: 2025, + date: { + day: 4, + month: 7, + year: 2025, + }, + quality: "assumed-valid", }, status: "Official", title: "Ambiguous Hands", @@ -416,9 +425,12 @@ Artwork by David Rundlöf", ], packaging: "None", releaseDate: { - day: 27, - month: 9, - year: 2024, + date: { + day: 27, + month: 9, + year: 2024, + }, + quality: "assumed-valid", }, status: "Official", title: "Mr. Florida '81", @@ -605,9 +617,12 @@ snapshot[`Bandcamp provider > release lookup > release with name your price (non ], packaging: "None", releaseDate: { - day: 7, - month: 4, - year: 2023, + date: { + day: 7, + month: 4, + year: 2023, + }, + quality: "assumed-valid", }, status: "Official", title: "demo", @@ -776,9 +791,12 @@ snapshot[`Bandcamp provider > release lookup > release with name your price (non ], packaging: "None", releaseDate: { - day: 8, - month: 9, - year: 2013, + date: { + day: 8, + month: 9, + year: 2013, + }, + quality: "assumed-valid", }, status: "Official", title: "Ambient Energy (Name your price)", @@ -918,9 +936,12 @@ snapshot[`Bandcamp provider > release lookup > release with some download only t ], packaging: "None", releaseDate: { - day: 22, - month: 9, - year: 2023, + date: { + day: 22, + month: 9, + year: 2023, + }, + quality: "assumed-valid", }, status: "Official", title: "Futon Feels", @@ -1112,9 +1133,12 @@ snapshot[`Bandcamp provider > release lookup > release with a hidden track 1`] = ], packaging: "None", releaseDate: { - day: 12, - month: 5, - year: 2022, + date: { + day: 12, + month: 5, + year: 2022, + }, + quality: "assumed-valid", }, status: "Official", title: "Do You Like Acid EP", @@ -1424,9 +1448,12 @@ LM005", ], packaging: "None", releaseDate: { - day: 26, - month: 9, - year: 2025, + date: { + day: 26, + month: 9, + year: 2025, + }, + quality: "assumed-valid", }, status: "Official", title: "Bear Creek", diff --git a/providers/Bandcamp/mod.ts b/providers/Bandcamp/mod.ts index 89182b5e..96e14d88 100644 --- a/providers/Bandcamp/mod.ts +++ b/providers/Bandcamp/mod.ts @@ -13,7 +13,7 @@ import type { } from '@/harmonizer/types.ts'; import { type CacheEntry, MetadataProvider, ReleaseLookup } from '@/providers/base.ts'; import { DurationPrecision, FeatureQuality, FeatureQualityMap } from '@/providers/features.ts'; -import { parseISODateTime, PartialDate } from '@/utils/date.ts'; +import { parseISODateTime, PartialDate, type ReleaseDate } from '@/utils/date.ts'; import { ProviderError, ResponseError } from '@/utils/errors.ts'; import { extractDataAttribute, extractMetadataTag, extractTextFromHtml } from '@/utils/html.ts'; import { plural, pluralWithCount } from '@/utils/plural.ts'; @@ -436,7 +436,7 @@ export class BandcampReleaseLookup extends ReleaseLookup { diff --git a/providers/Beatport/mod.ts b/providers/Beatport/mod.ts index e23c44d5..606c5283 100644 --- a/providers/Beatport/mod.ts +++ b/providers/Beatport/mod.ts @@ -145,7 +145,7 @@ export class BeatportReleaseLookup extends ReleaseLookup release lookup > single by two artists 1`] = ` ], packaging: "None", releaseDate: { - day: 16, - month: 8, - year: 2024, + date: { + day: 16, + month: 8, + year: 2024, + }, + quality: "assumed-valid", }, status: "Official", title: "Die With A Smile", diff --git a/providers/Deezer/mod.ts b/providers/Deezer/mod.ts index 015886ec..ee8800e0 100644 --- a/providers/Deezer/mod.ts +++ b/providers/Deezer/mod.ts @@ -208,7 +208,7 @@ export class DeezerReleaseLookup extends ReleaseApiLookup release lookup > release with GTIN in distPartNo 1`] = ], packaging: "None", releaseDate: { - day: 31, - month: 10, - year: 2025, + date: { + day: 31, + month: 10, + year: 2025, + }, + quality: "assumed-valid", }, status: "Official", title: "MAGIC", @@ -673,9 +676,12 @@ snapshot[`Mora provider > release lookup > release with GTIN in cdPartNo 1`] = ` ], packaging: "None", releaseDate: { - day: 15, - month: 10, - year: 2025, + date: { + day: 15, + month: 10, + year: 2025, + }, + quality: "assumed-valid", }, status: "Official", title: "バンドリ! ガールズバンドパーティ! カバーコレクションVol.10", @@ -767,9 +773,12 @@ snapshot[`Mora provider > release lookup > video release 1`] = ` ], packaging: "None", releaseDate: { - day: 22, - month: 11, - year: 2025, + date: { + day: 22, + month: 11, + year: 2025, + }, + quality: "assumed-valid", }, status: "Official", title: "Woman is a Tree", diff --git a/providers/Mora/mod.ts b/providers/Mora/mod.ts index c7bab6a4..6d3bd544 100644 --- a/providers/Mora/mod.ts +++ b/providers/Mora/mod.ts @@ -186,7 +186,7 @@ export class MoraReleaseLookup extends ReleaseLookup artists: [this.makeArtistCreditName(albumPage.artistName, albumPage.artistNo)], labels: [label], gtin, - releaseDate: parseISODateTime(albumPage.startDate + ' +0'), + releaseDate: this.convertReleaseDate(parseISODateTime(albumPage.startDate + ' +0')), availableIn: ['JP'], media: [{ format: 'Digital Media', diff --git a/providers/MusicBrainz/mod.ts b/providers/MusicBrainz/mod.ts index 738a3b2c..41e3d9d2 100644 --- a/providers/MusicBrainz/mod.ts +++ b/providers/MusicBrainz/mod.ts @@ -164,7 +164,7 @@ export class MusicBrainzReleaseLookup extends ReleaseApiLookup ({ name: info.label?.name, catalogNumber: info['catalog-number'] ?? undefined, diff --git a/providers/Ototoy/__snapshots__/mod.test.ts.snap b/providers/Ototoy/__snapshots__/mod.test.ts.snap index 6c8eaaee..4e78dcd8 100644 --- a/providers/Ototoy/__snapshots__/mod.test.ts.snap +++ b/providers/Ototoy/__snapshots__/mod.test.ts.snap @@ -78,9 +78,12 @@ snapshot[`OTOTOY provider > release lookup > single track release 1`] = ` ], packaging: "None", releaseDate: { - day: 1, - month: 9, - year: 2025, + date: { + day: 1, + month: 9, + year: 2025, + }, + quality: "assumed-valid", }, status: "Official", title: "トゥイー・ボックスの人形劇場", @@ -1644,9 +1647,12 @@ snapshot[`OTOTOY provider > release lookup > multi-disc release 1`] = ` ], packaging: "None", releaseDate: { - day: 21, - month: 11, - year: 2025, + date: { + day: 21, + month: 11, + year: 2025, + }, + quality: "assumed-valid", }, status: "Official", title: "Anthology Collection", @@ -1775,9 +1781,12 @@ snapshot[`OTOTOY provider > release lookup > multiple artists 1`] = ` ], packaging: "None", releaseDate: { - day: 25, - month: 2, - year: 2021, + date: { + day: 25, + month: 2, + year: 2021, + }, + quality: "assumed-valid", }, status: "Official", title: "Gimme吟味virtuaる最高star!!!! (feat. さくらみこ, 白上フブキ, 夏色まつり & 宝鐘マリン)", @@ -2124,9 +2133,12 @@ snapshot[`OTOTOY provider > release lookup > no label 1`] = ` ], packaging: "None", releaseDate: { - day: 19, - month: 11, - year: 2025, + date: { + day: 19, + month: 11, + year: 2025, + }, + quality: "assumed-valid", }, status: "Official", title: "UNTIL", @@ -2274,9 +2286,12 @@ snapshot[`OTOTOY provider > release lookup > original release date only 1`] = ` ], packaging: "None", releaseDate: { - day: 4, - month: 10, - year: 2023, + date: { + day: 4, + month: 10, + year: 2023, + }, + quality: "assumed-valid", }, status: "Official", title: "THE BOOK 3", @@ -2424,9 +2439,12 @@ snapshot[`OTOTOY provider > release lookup > catalog number 1`] = ` ], packaging: "None", releaseDate: { - day: 4, - month: 10, - year: 2023, + date: { + day: 4, + month: 10, + year: 2023, + }, + quality: "assumed-valid", }, status: "Official", title: "THE BOOK 3", @@ -2672,9 +2690,12 @@ snapshot[`OTOTOY provider > release lookup > per-track artists 1`] = ` ], packaging: "None", releaseDate: { - day: 12, - month: 12, - year: 2025, + date: { + day: 12, + month: 12, + year: 2025, + }, + quality: "assumed-valid", }, status: "Official", title: "Friends", diff --git a/providers/Ototoy/mod.test.ts b/providers/Ototoy/mod.test.ts index a0535293..3ba0e6a0 100644 --- a/providers/Ototoy/mod.test.ts +++ b/providers/Ototoy/mod.test.ts @@ -68,7 +68,7 @@ describe('OTOTOY provider', () => { assert: async (release, ctx) => { await assertSnapshot(ctx, release); - assertEquals(release.releaseDate, { + assertEquals(release.releaseDate?.date, { day: 4, month: 10, year: 2023, diff --git a/providers/Ototoy/mod.ts b/providers/Ototoy/mod.ts index 250626d7..40219c55 100644 --- a/providers/Ototoy/mod.ts +++ b/providers/Ototoy/mod.ts @@ -380,7 +380,7 @@ export class OtotoyReleaseLookup extends ReleaseLookup release lookup > single by two artists 1`] = ` ], packaging: "None", releaseDate: { - day: 16, - month: 8, - year: 2024, + date: { + day: 16, + month: 8, + year: 2024, + }, + quality: "assumed-valid", }, status: "Official", title: "Die With A Smile", diff --git a/providers/Spotify/mod.ts b/providers/Spotify/mod.ts index 891ee83f..b54fbfe3 100644 --- a/providers/Spotify/mod.ts +++ b/providers/Spotify/mod.ts @@ -287,7 +287,7 @@ export class SpotifyReleaseLookup extends ReleaseApiLookup release lookup > live album with video tracks and fea ], packaging: "None", releaseDate: { - day: 1, - month: 1, - year: 2012, + date: { + day: 1, + month: 1, + year: 2012, + }, + note: "Release predates platform launch date.", + quality: "assumed-invalid", }, status: "Official", title: "Live In Brooklyn", @@ -555,9 +559,12 @@ snapshot[`Tidal provider > release lookup > single by two artists (v2 API) 1`] = ], packaging: "None", releaseDate: { - day: 16, - month: 8, - year: 2024, + date: { + day: 16, + month: 8, + year: 2024, + }, + quality: "assumed-valid", }, status: "Official", title: "Die With A Smile", @@ -662,9 +669,12 @@ snapshot[`Tidal provider > release lookup > lyric video (v2 API) 1`] = ` ], packaging: "None", releaseDate: { - day: 19, - month: 4, - year: 2024, + date: { + day: 19, + month: 4, + year: 2024, + }, + quality: "assumed-valid", }, status: "Official", title: "My Boy Only Breaks His Favorite Toys (Lyric Video)", diff --git a/providers/Tidal/v1/lookup.ts b/providers/Tidal/v1/lookup.ts index 3290caf7..6823ad03 100644 --- a/providers/Tidal/v1/lookup.ts +++ b/providers/Tidal/v1/lookup.ts @@ -108,7 +108,7 @@ export class TidalV1ReleaseLookup extends ReleaseApiLookup types: this.provider.getLinkTypesForEntity(), }], media, - releaseDate: parseHyphenatedDate(rawRelease.releaseDate), + releaseDate: this.convertReleaseDate(parseHyphenatedDate(rawRelease.releaseDate)), copyright: rawRelease.copyright ? formatCopyrightSymbols(rawRelease.copyright) : undefined, status: 'Official', types: [capitalizeReleaseType(rawRelease.type)], diff --git a/providers/Tidal/v2/lookup.ts b/providers/Tidal/v2/lookup.ts index 3db43c64..f2a84132 100644 --- a/providers/Tidal/v2/lookup.ts +++ b/providers/Tidal/v2/lookup.ts @@ -152,7 +152,7 @@ export class TidalV2ReleaseLookup extends ReleaseApiLookup; + protected convertReleaseDate(date?: PartialDate): ReleaseDate { + const launchDate = this.provider.launchDate; + if ( + date === undefined || + (launchDate.day === undefined && launchDate.month === undefined && launchDate.year === undefined) + ) { + return { + date, + quality: 'none-found', + }; + } + + if ( + !date?.year || date.year < launchDate.year! || (date.year === launchDate.year && date.month! < launchDate.month!) + ) { + return { + date, + quality: 'assumed-invalid', + note: 'Release predates platform launch date.', + }; + } + + return { + date, + quality: 'assumed-valid', + }; + } + /** Adds a message to the generated release info. */ protected addMessage(text: string, type: MessageType = 'info'): void { this.messages.push({ diff --git a/providers/iTunes/__snapshots__/mod.test.ts.snap b/providers/iTunes/__snapshots__/mod.test.ts.snap index 24e2e965..88375e63 100644 --- a/providers/iTunes/__snapshots__/mod.test.ts.snap +++ b/providers/iTunes/__snapshots__/mod.test.ts.snap @@ -811,9 +811,13 @@ snapshot[`iTunes provider > release lookup > multi-disc download with video trac ], packaging: "None", releaseDate: { - day: 21, - month: 11, - year: 1975, + date: { + day: 21, + month: 11, + year: 1975, + }, + note: "Release predates platform launch date.", + quality: "assumed-invalid", }, status: "Official", title: "A Night at the Opera (Deluxe Edition)", diff --git a/providers/iTunes/mod.ts b/providers/iTunes/mod.ts index 17541ffe..1758407a 100644 --- a/providers/iTunes/mod.ts +++ b/providers/iTunes/mod.ts @@ -193,7 +193,7 @@ export class iTunesReleaseLookup extends ReleaseApiLookup Release date - {formatPartialDate(release.releaseDate ?? {}) || '[unknown]'} + {formatPartialDate(release.releaseDate?.date ?? {}) || '[unknown]'} release.releaseDate} + property={(release) => release.releaseDate?.date} display={formatPartialDate} identifier={formatPartialDate} /> diff --git a/utils/date.ts b/utils/date.ts index 516e1f3d..da443f11 100644 --- a/utils/date.ts +++ b/utils/date.ts @@ -6,6 +6,12 @@ export type PartialDate = Partial<{ year: number; }>; +export interface ReleaseDate { + date?: PartialDate; + quality: 'assumed-invalid' | 'assumed-valid' | 'none-found'; + note?: string; +} + export function formatPartialDate(date: PartialDate) { const dateComponents: string[] = [];