diff --git a/providers/Spotify/mod.ts b/providers/Spotify/mod.ts index 2e0e19e..e5e2897 100644 --- a/providers/Spotify/mod.ts +++ b/providers/Spotify/mod.ts @@ -2,9 +2,10 @@ import { ApiAccessToken, type CacheEntry, MetadataApiProvider, ReleaseApiLookup import { DurationPrecision, FeatureQuality, FeatureQualityMap } from '@/providers/features.ts'; import { capitalizeReleaseType } from '@/harmonizer/release_types.ts'; import { parseHyphenatedDate, PartialDate } from '@/utils/date.ts'; -import { splitLabels } from '@/utils/label.ts'; +import { formatCopyrightSymbols } from '@/utils/copyright.ts'; import { ResponseError } from '@/utils/errors.ts'; import { selectLargestImage } from '@/utils/image.ts'; +import { splitLabels } from '@/utils/label.ts'; import { encodeBase64 } from 'std/encoding/base64.ts'; import { availableRegions } from './regions.ts'; @@ -342,12 +343,8 @@ export class SpotifyReleaseLookup extends ReleaseApiLookup { }], media, releaseDate: parseHyphenatedDate(rawRelease.releaseDate), - copyright: rawRelease.copyright, + copyright: formatCopyrightSymbols(rawRelease.copyright), status: 'Official', types: [capitalizeReleaseType(rawRelease.type)], packaging: 'None', diff --git a/utils/copyright.test.ts b/utils/copyright.test.ts new file mode 100644 index 0000000..164e692 --- /dev/null +++ b/utils/copyright.test.ts @@ -0,0 +1,30 @@ +import { formatCopyrightSymbols } from './copyright.ts'; + +import { assertEquals } from 'std/assert/assert_equals.ts'; +import { describe, it } from 'std/testing/bdd.ts'; + +import type { FunctionSpec } from './test_spec.ts'; + +describe('format copyright symbols', () => { + const passingCases: FunctionSpec = [ + ['should keep string without symbols', 'Nuclear Blast', undefined, 'Nuclear Blast'], + ['should replace (P)', '(P) 2016 Century Media Records Ltd.', undefined, '℗ 2016 Century Media Records Ltd.'], + ['should keep symbols', '© 2012 S. Carter Enterprises, LLC.', undefined, '© 2012 S. Carter Enterprises, LLC.'], + [ + 'should convert multiple symbols', + '(p)(c) 2017 S. CARTER ENTERPRISES, LLC. MARKETED BY ROC NATION & DISTRIBUTED BY ROC NATION/UMG RECORDINGS INC.', + undefined, + '℗© 2017 S. CARTER ENTERPRISES, LLC. MARKETED BY ROC NATION & DISTRIBUTED BY ROC NATION/UMG RECORDINGS INC.', + ], + ['should prepend expected symbol', 'Nuclear Blast', '℗', '℗ Nuclear Blast'], + ['should not prepend symbol if it exists', '2024 ℗ Nuclear Blast', '℗', '2024 ℗ Nuclear Blast'], + ['should not prepend symbol if any exists', '2024 © Nuclear Blast', '℗', '2024 © Nuclear Blast'], + ['should not prepend symbol if it exists as text', '(c)+(p) Nuclear Blast', '℗', '©+℗ Nuclear Blast'], + ]; + + passingCases.forEach(([description, copyright, expectedSymbol, expected]) => { + it(description, () => { + assertEquals(formatCopyrightSymbols(copyright, expectedSymbol), expected); + }); + }); +}); diff --git a/utils/copyright.ts b/utils/copyright.ts new file mode 100644 index 0000000..59dca78 --- /dev/null +++ b/utils/copyright.ts @@ -0,0 +1,12 @@ +/** Formats a copyright string, replacing (c) and (p) with the corresponding symbol. + * + * If expectedSymbol is given the symbol will be prepended if no other copyright symbol + * is already present in the string. + */ +export function formatCopyrightSymbols(copyright: string, expectedSymbol: '©' | '℗' | undefined = undefined): string { + copyright = copyright.replace(/\(c\)/i, '©').replace(/\(p\)/i, '℗'); + if (expectedSymbol && !copyright.includes('©') && !copyright.includes('℗')) { + copyright = `${expectedSymbol} ${copyright}`; + } + return copyright; +}