From 79df1f03eca13bcf5c4cda9d2c8fa8e8e7fa7b17 Mon Sep 17 00:00:00 2001 From: Arthur Jamet Date: Thu, 8 Feb 2024 08:54:30 +0100 Subject: [PATCH 1/4] Genre Service: Prevent housekeeping from deleting album-specific genres --- server/src/genre/genre.service.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server/src/genre/genre.service.ts b/server/src/genre/genre.service.ts index 90d7b5307..ee6abb2b1 100644 --- a/server/src/genre/genre.service.ts +++ b/server/src/genre/genre.service.ts @@ -240,11 +240,15 @@ export default class GenreService extends RepositoryService< select: { id: true, _count: { - select: { songs: true }, + select: { songs: true, albums: true }, }, }, }) - .then((genres) => genres.filter((genre) => !genre._count.songs)); + .then((genres) => + genres.filter( + (genre) => !genre._count.songs && !genre._count.albums, + ), + ); await Promise.all(emptyGenres.map(({ id }) => this.delete({ id }))); } From 38560befb27090c369a21898f90e0b8959cdf6c4 Mon Sep 17 00:00:00 2001 From: Arthur Jamet Date: Thu, 8 Feb 2024 08:58:14 +0100 Subject: [PATCH 2/4] External IDs: Preventing fetching if already known --- server/src/providers/external-id.provider.ts | 25 +++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/server/src/providers/external-id.provider.ts b/server/src/providers/external-id.provider.ts index 20b63f814..2a0f56183 100644 --- a/server/src/providers/external-id.provider.ts +++ b/server/src/providers/external-id.provider.ts @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +/* eslint-disable max-depth */ import { Inject, Injectable, forwardRef } from "@nestjs/common"; import PrismaService from "src/prisma/prisma.service"; import ProviderService from "./provider.service"; @@ -301,8 +302,17 @@ export default class ExternalIdService { musicbrainzProvider, resourceMBID.value, ); - - Array.of(...providersToReach).forEach(async (otherProvider) => { + for (const otherProvider of Array.of(...providersToReach)) { + const providerId = this.providerService.getProviderId( + otherProvider.name, + ); + if ( + resource.externalIds.find( + (id) => id.providerId == providerId, + ) + ) { + continue; + } const relation = resourceEntry.relations?.find( (rel) => rel.type == @@ -311,23 +321,20 @@ export default class ExternalIdService { ); if (relation?.url === undefined) { - return; + continue; } const identifier = parseIdentifierFromUrl( relation.url.resource, otherProvider, ); if (identifier == null) { - return; + continue; } try { const metadata = await getResourceMetadataByIdentifier( otherProvider, identifier, ); - const providerId = this.providerService.getProviderId( - otherProvider.name, - ); newIdentifiers.push( formatResourceMetadata(metadata, providerId), @@ -336,9 +343,9 @@ export default class ExternalIdService { (toReach) => toReach.name !== otherProvider.name, ); } catch { - return; + continue; } - }); + } const wikiDataId = resourceEntry.relations ?.map( From 7c63ee6449a88e51646a43acf18f4f5869855796 Mon Sep 17 00:00:00 2001 From: Arthur Jamet Date: Thu, 8 Feb 2024 09:36:34 +0100 Subject: [PATCH 3/4] MusicBrainz: Use Album Type to filter release-groups --- server/src/providers/external-id.provider.ts | 7 +++++- server/src/providers/iprovider.ts | 2 ++ .../musicbrainz/musicbrainz.provider.spec.ts | 24 +++++++++++++++++++ .../musicbrainz/musicbrainz.provider.ts | 24 ++++++++++++++++++- 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/server/src/providers/external-id.provider.ts b/server/src/providers/external-id.provider.ts index 2a0f56183..0bbab3a2a 100644 --- a/server/src/providers/external-id.provider.ts +++ b/server/src/providers/external-id.provider.ts @@ -111,7 +111,11 @@ export default class ExternalIdService { (provider, mbid) => provider.getAlbumMetadataByIdentifier(mbid), (provider, providerId) => { if (!album.artist) { - return provider.getAlbumMetadataByName(album.name); + return provider.getAlbumMetadataByName( + album.name, + undefined, + album.type, + ); } const parentArtistIdentifier = album.artist.externalIds.find( (externalId) => externalId.providerId == providerId, @@ -120,6 +124,7 @@ export default class ExternalIdService { return provider.getAlbumMetadataByName( album.name, parentArtistIdentifier, + album.type, ); }, (provider, mbid) => provider.getAlbumEntry(mbid), diff --git a/server/src/providers/iprovider.ts b/server/src/providers/iprovider.ts index 86b0bfeb2..c21b569d8 100644 --- a/server/src/providers/iprovider.ts +++ b/server/src/providers/iprovider.ts @@ -18,6 +18,7 @@ import { AlbumExternalId, + AlbumType, ArtistExternalId, ReleaseExternalId, SongExternalId, @@ -88,6 +89,7 @@ export default abstract class IProvider { getAlbumMetadataByName( _albumName: string, _artistName?: string, + _albumType?: AlbumType, ): Promise { throw new ProviderMethodNotAvailableError(this.name); } diff --git a/server/src/providers/musicbrainz/musicbrainz.provider.spec.ts b/server/src/providers/musicbrainz/musicbrainz.provider.spec.ts index 495ae80a1..751520c7e 100644 --- a/server/src/providers/musicbrainz/musicbrainz.provider.spec.ts +++ b/server/src/providers/musicbrainz/musicbrainz.provider.spec.ts @@ -126,6 +126,30 @@ describe("MusicBrainz Provider", () => { expect(id.genres).toContain("Electronic"); expect(id.genres).toContain("Dance-pop"); }); + it("should get compilation (and not single) identifier", async () => { + const id = await musicBrainzProvider.getAlbumMetadataByName( + "Celebration", + "79239441-bfd5-4981-a70c-55c3f15c1287", + "Compilation", + ); + expect(id.value).toBe("bd252c17-ff32-4369-8e73-4d0a65a316bd"); + }); + it("should get Single identifier", async () => { + const id = await musicBrainzProvider.getAlbumMetadataByName( + "Celebration - Single", + "79239441-bfd5-4981-a70c-55c3f15c1287", + "Single", + ); + expect(id.value).toBe("8ab9625e-5e09-4e4b-afda-3e64189b624b"); + }); + it("should get album (and not single) identifier", async () => { + const id = await musicBrainzProvider.getAlbumMetadataByName( + "Protection", + "10adbe5e-a2c0-4bf3-8249-2b4cbf6e6ca8", + "StudioRecording" + ); + expect(id.value).toBe("ded46e46-788d-3c1f-b21b-9f5e9c37b1bc"); + }); it("should get compilation album Identifier", async () => { const id = await musicBrainzProvider.getAlbumMetadataByName( "Nova Tunes 01", diff --git a/server/src/providers/musicbrainz/musicbrainz.provider.ts b/server/src/providers/musicbrainz/musicbrainz.provider.ts index ed9c163df..499def0f1 100644 --- a/server/src/providers/musicbrainz/musicbrainz.provider.ts +++ b/server/src/providers/musicbrainz/musicbrainz.provider.ts @@ -33,6 +33,7 @@ import MusicBrainzSettings from "./musicbrainz.settings"; import { ProviderActionFailedError } from "../provider.exception"; import levenshtein from "damerau-levenshtein"; import Slug from "src/slug/slug"; +import { AlbumType } from "@prisma/client"; type MBID = string; @@ -125,13 +126,19 @@ export default class MusicBrainzProvider async getAlbumMetadataByName( albumName: string, artistIdentifier?: string, + albumType?: AlbumType, ): Promise { try { const searchResult = await this.mbClient .searchRelease({ - query: `query="${albumName}" AND arid:${ + query: `query="${albumName.replace( + /\s*-\s*Single$/i, + "", + )}" AND arid:${ artistIdentifier ?? this.compilationArtistID }`, + inc: ["release-groups"], + limit: 1000, }) .then((result) => result.releases.filter((release) => @@ -141,6 +148,21 @@ export default class MusicBrainzProvider (artistIdentifier ?? this.compilationArtistID), ), ), + ) + .then((releases) => + releases.filter((release) => { + const releaseIsSingle = + release["release-group"]?.["primary-type"] == + "Single"; + const albumIsSingle = albumType == "Single"; + if (albumType === undefined) { + return true; + } + if (releaseIsSingle !== albumIsSingle) { + return false; + } + return true; + }), ); const releaseGroupId = searchResult.at(0)!["release-group"]!.id; From 379dad3de957dbc9fc174e81e5c15ad1bfb8596d Mon Sep 17 00:00:00 2001 From: Arthur Jamet Date: Thu, 8 Feb 2024 09:36:54 +0100 Subject: [PATCH 4/4] Front: Avoid using Discogs for album descriptions --- front/src/pages/releases/[slugOrId].tsx | 8 +++++--- .../providers/musicbrainz/musicbrainz.provider.spec.ts | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/front/src/pages/releases/[slugOrId].tsx b/front/src/pages/releases/[slugOrId].tsx index bbf3348a7..389e2c07d 100644 --- a/front/src/pages/releases/[slugOrId].tsx +++ b/front/src/pages/releases/[slugOrId].tsx @@ -260,9 +260,11 @@ const ReleasePage = (props: InferSSRProps) => { ); const externalIdWithDescription = useMemo( () => - album.data?.externalIds.find( - ({ description }) => description !== null, - ), + album.data?.externalIds + .filter( + ({ provider }) => provider.name.toLowerCase() !== "discogs", + ) + .find(({ description }) => description !== null), [album.data], ); const externalIds = useMemo(() => { diff --git a/server/src/providers/musicbrainz/musicbrainz.provider.spec.ts b/server/src/providers/musicbrainz/musicbrainz.provider.spec.ts index 751520c7e..21180327f 100644 --- a/server/src/providers/musicbrainz/musicbrainz.provider.spec.ts +++ b/server/src/providers/musicbrainz/musicbrainz.provider.spec.ts @@ -146,7 +146,7 @@ describe("MusicBrainz Provider", () => { const id = await musicBrainzProvider.getAlbumMetadataByName( "Protection", "10adbe5e-a2c0-4bf3-8249-2b4cbf6e6ca8", - "StudioRecording" + "StudioRecording", ); expect(id.value).toBe("ded46e46-788d-3c1f-b21b-9f5e9c37b1bc"); });