mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 04:20:12 +02:00
add automatic country prioritization based on existing releases
This commit is contained in:
@@ -897,12 +897,14 @@
|
|||||||
"musicbrainz": "show MusicBrainz links",
|
"musicbrainz": "show MusicBrainz links",
|
||||||
"musicBrainzQueries": "enable MusicBrainz integration",
|
"musicBrainzQueries": "enable MusicBrainz integration",
|
||||||
"musicBrainzQueries_description": "the integration will query MusicBrainz for missing artist releases and other miscellaneous data",
|
"musicBrainzQueries_description": "the integration will query MusicBrainz for missing artist releases and other miscellaneous data",
|
||||||
"musicbrainzExcludeReleaseTypes": "exclude MusicBrainz release types",
|
"musicbrainzExcludeReleaseTypes": "MusicBrainz release type exclusion",
|
||||||
"musicbrainzExcludeReleaseTypes_description": "release types to exclude when loading MusicBrainz artist releases",
|
"musicbrainzExcludeReleaseTypes_description": "release types to exclude when loading MusicBrainz artist releases",
|
||||||
"musicbrainzPrioritizeCountries": "prioritize MusicBrainz countries",
|
"musicbrainzPrioritizeCountries": "MusicBrainz country priority",
|
||||||
"musicbrainzPrioritizeCountries_description": "countries to prioritize when ordering MusicBrainz releases (first in list has highest priority)",
|
"musicbrainzPrioritizeCountries_description": "countries to prioritize when ordering MusicBrainz releases (first in list has highest priority)",
|
||||||
"youtube": "enable youtube integration",
|
"musicbrainzAutoCountryPriority": "automatic country priority",
|
||||||
"youtube_description": "external songs will attempt to use YouTube to resolve stream URLs for playback (desktop only)",
|
"musicbrainzAutoCountryPriority_description": "derive country priority from the artist's MusicBrainz releases (countries with more releases are ranked higher)",
|
||||||
|
"youtube": "enable YouTube playback",
|
||||||
|
"youtube_description": "external songs will attempt to use YouTube to resolve stream URLs (desktop only)",
|
||||||
"neteaseTranslation_description": "When enabled, fetches and displays translated lyrics from NetEase if available",
|
"neteaseTranslation_description": "When enabled, fetches and displays translated lyrics from NetEase if available",
|
||||||
"neteaseTranslation": "Enable NetEase translations",
|
"neteaseTranslation": "Enable NetEase translations",
|
||||||
"notify": "enable song notifications",
|
"notify": "enable song notifications",
|
||||||
|
|||||||
@@ -275,6 +275,7 @@ export const queryKeys: Record<
|
|||||||
limit: number | undefined,
|
limit: number | undefined,
|
||||||
mbzArtistId: string,
|
mbzArtistId: string,
|
||||||
config?: {
|
config?: {
|
||||||
|
autoCountryPriority: boolean;
|
||||||
excludeReleaseTypes: string[];
|
excludeReleaseTypes: string[];
|
||||||
prioritizeCountries: string[];
|
prioritizeCountries: string[];
|
||||||
},
|
},
|
||||||
@@ -286,6 +287,7 @@ export const queryKeys: Record<
|
|||||||
limit,
|
limit,
|
||||||
config
|
config
|
||||||
? [
|
? [
|
||||||
|
String(config.autoCountryPriority),
|
||||||
[...config.excludeReleaseTypes].sort().join(','),
|
[...config.excludeReleaseTypes].sort().join(','),
|
||||||
[...config.prioritizeCountries].sort().join(','),
|
[...config.prioritizeCountries].sort().join(','),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1381,6 +1381,9 @@ const ArtistAlbums = ({ albumsQuery }: ArtistAlbumsProps) => {
|
|||||||
const musicBrainzExcludeReleaseTypes = useSettingsStore(
|
const musicBrainzExcludeReleaseTypes = useSettingsStore(
|
||||||
(state) => state.integrations.musicBrainzExcludeReleaseTypes,
|
(state) => state.integrations.musicBrainzExcludeReleaseTypes,
|
||||||
);
|
);
|
||||||
|
const musicbrainzAutoCountryPriority = useSettingsStore(
|
||||||
|
(state) => state.integrations.musicbrainzAutoCountryPriority,
|
||||||
|
);
|
||||||
const musicBrainzPrioritizeCountries = useSettingsStore(
|
const musicBrainzPrioritizeCountries = useSettingsStore(
|
||||||
(state) => state.integrations.musicBrainzPrioritizeCountries,
|
(state) => state.integrations.musicBrainzPrioritizeCountries,
|
||||||
);
|
);
|
||||||
@@ -1410,6 +1413,7 @@ const ArtistAlbums = ({ albumsQuery }: ArtistAlbumsProps) => {
|
|||||||
const musicBrainzEnabled = useSettingsStore((state) => state.integrations.musicBrainz);
|
const musicBrainzEnabled = useSettingsStore((state) => state.integrations.musicBrainz);
|
||||||
const musicbrainzArtistQuery = useQuery({
|
const musicbrainzArtistQuery = useQuery({
|
||||||
...musicbrainzQueries.artist({
|
...musicbrainzQueries.artist({
|
||||||
|
autoCountryPriority: musicbrainzAutoCountryPriority,
|
||||||
excludeReleaseTypes: musicBrainzExcludeReleaseTypes,
|
excludeReleaseTypes: musicBrainzExcludeReleaseTypes,
|
||||||
mbzArtistId: detailQuery.data?.mbz as string,
|
mbzArtistId: detailQuery.data?.mbz as string,
|
||||||
prioritizeCountries: musicBrainzPrioritizeCountries,
|
prioritizeCountries: musicBrainzPrioritizeCountries,
|
||||||
@@ -1418,6 +1422,7 @@ const ArtistAlbums = ({ albumsQuery }: ArtistAlbumsProps) => {
|
|||||||
meta: {
|
meta: {
|
||||||
albumArtist: detailQuery.data,
|
albumArtist: detailQuery.data,
|
||||||
albums: albumsQuery.data?.items || [],
|
albums: albumsQuery.data?.items || [],
|
||||||
|
autoCountryPriority: musicbrainzAutoCountryPriority,
|
||||||
excludeReleaseTypes: musicBrainzExcludeReleaseTypes,
|
excludeReleaseTypes: musicBrainzExcludeReleaseTypes,
|
||||||
prioritizeCountries: musicBrainzPrioritizeCountries,
|
prioritizeCountries: musicBrainzPrioritizeCountries,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export type IRelationWithWork = IRelation & { work?: IWork };
|
|||||||
export type MusicBrainzArtistSelectMeta = {
|
export type MusicBrainzArtistSelectMeta = {
|
||||||
albumArtist: AlbumArtist;
|
albumArtist: AlbumArtist;
|
||||||
albums?: Album[];
|
albums?: Album[];
|
||||||
|
autoCountryPriority?: boolean;
|
||||||
excludeReleaseTypes?: string[];
|
excludeReleaseTypes?: string[];
|
||||||
prioritizeCountries?: string[];
|
prioritizeCountries?: string[];
|
||||||
};
|
};
|
||||||
@@ -123,7 +124,22 @@ const artistSelect = memoize(
|
|||||||
|
|
||||||
const excludeReleaseTypes = (meta.excludeReleaseTypes ?? []).map((t) => t.toLowerCase());
|
const excludeReleaseTypes = (meta.excludeReleaseTypes ?? []).map((t) => t.toLowerCase());
|
||||||
const excludeSet = new Set(excludeReleaseTypes);
|
const excludeSet = new Set(excludeReleaseTypes);
|
||||||
const prioritizeCountries = (meta.prioritizeCountries ?? []).map((c) => c.toUpperCase());
|
|
||||||
|
let prioritizeCountries: string[];
|
||||||
|
if (meta.autoCountryPriority) {
|
||||||
|
const countryCounts = new Map<string, number>();
|
||||||
|
for (const release of data.releases.releases) {
|
||||||
|
const country = release.country?.toUpperCase();
|
||||||
|
if (country) {
|
||||||
|
countryCounts.set(country, (countryCounts.get(country) ?? 0) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prioritizeCountries = [...countryCounts.entries()]
|
||||||
|
.sort(([, a], [, b]) => b - a)
|
||||||
|
.map(([code]) => code);
|
||||||
|
} else {
|
||||||
|
prioritizeCountries = (meta.prioritizeCountries ?? []).map((c) => c.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
const releaseEntries = Array.from(unownedReleases.entries())
|
const releaseEntries = Array.from(unownedReleases.entries())
|
||||||
.filter(([, release]) => {
|
.filter(([, release]) => {
|
||||||
@@ -290,11 +306,13 @@ const EMPTY_BROWSE_RELEASES: IBrowseReleasesResult = {
|
|||||||
|
|
||||||
export const musicbrainzQueries = {
|
export const musicbrainzQueries = {
|
||||||
artist: (args: {
|
artist: (args: {
|
||||||
|
autoCountryPriority?: boolean;
|
||||||
excludeReleaseTypes?: string[];
|
excludeReleaseTypes?: string[];
|
||||||
mbzArtistId: string;
|
mbzArtistId: string;
|
||||||
prioritizeCountries?: string[];
|
prioritizeCountries?: string[];
|
||||||
}) => {
|
}) => {
|
||||||
const config = {
|
const config = {
|
||||||
|
autoCountryPriority: args.autoCountryPriority ?? false,
|
||||||
excludeReleaseTypes: args.excludeReleaseTypes ?? [],
|
excludeReleaseTypes: args.excludeReleaseTypes ?? [],
|
||||||
prioritizeCountries: args.prioritizeCountries ?? [],
|
prioritizeCountries: args.prioritizeCountries ?? [],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -378,6 +378,27 @@ export const IntegrationsTab = memo(() => {
|
|||||||
isHidden: !musicBrainz || !settings.musicBrainz,
|
isHidden: !musicBrainz || !settings.musicBrainz,
|
||||||
title: t('setting.musicbrainzPrioritizeCountries', { postProcess: 'sentenceCase' }),
|
title: t('setting.musicbrainzPrioritizeCountries', { postProcess: 'sentenceCase' }),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
control: (
|
||||||
|
<Switch
|
||||||
|
aria-label={t('setting.musicbrainzAutoCountryPriority', {
|
||||||
|
postProcess: 'sentenceCase',
|
||||||
|
})}
|
||||||
|
defaultChecked={settings.musicbrainzAutoCountryPriority}
|
||||||
|
onChange={(e) =>
|
||||||
|
updateIntegrations({
|
||||||
|
musicbrainzAutoCountryPriority: e.currentTarget.checked,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
description: t('setting.musicbrainzAutoCountryPriority', {
|
||||||
|
context: 'description',
|
||||||
|
postProcess: 'sentenceCase',
|
||||||
|
}),
|
||||||
|
isHidden: !musicBrainz || !settings.musicBrainz,
|
||||||
|
title: t('setting.musicbrainzAutoCountryPriority', { postProcess: 'sentenceCase' }),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
control: (
|
control: (
|
||||||
<Switch
|
<Switch
|
||||||
@@ -397,10 +418,7 @@ export const IntegrationsTab = memo(() => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<SettingsSection
|
<SettingsSection options={options} title={'MusicBrainz'} />
|
||||||
options={options}
|
|
||||||
title={t('page.setting.integrationsTab', { postProcess: 'sentenceCase' })}
|
|
||||||
/>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -614,6 +614,7 @@ const QueryBuilderSettingsSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const IntegrationsSettingsSchema = z.object({
|
const IntegrationsSettingsSchema = z.object({
|
||||||
|
musicbrainzAutoCountryPriority: z.boolean(),
|
||||||
musicBrainz: z.boolean(),
|
musicBrainz: z.boolean(),
|
||||||
musicBrainzExcludeReleaseTypes: z.array(z.string()),
|
musicBrainzExcludeReleaseTypes: z.array(z.string()),
|
||||||
musicBrainzPrioritizeCountries: z.array(z.string()),
|
musicBrainzPrioritizeCountries: z.array(z.string()),
|
||||||
@@ -1105,6 +1106,7 @@ const initialState: SettingsState = {
|
|||||||
globalMediaHotkeys: true,
|
globalMediaHotkeys: true,
|
||||||
},
|
},
|
||||||
integrations: {
|
integrations: {
|
||||||
|
musicbrainzAutoCountryPriority: false,
|
||||||
musicBrainz: true,
|
musicBrainz: true,
|
||||||
musicBrainzExcludeReleaseTypes: [],
|
musicBrainzExcludeReleaseTypes: [],
|
||||||
musicBrainzPrioritizeCountries: [],
|
musicBrainzPrioritizeCountries: [],
|
||||||
@@ -2108,6 +2110,7 @@ export const useSettingsStore = createWithEqualityFn<SettingsSlice>()(
|
|||||||
// Move MusicBrainz release/country options to Integrations; keep musicBrainz in general
|
// Move MusicBrainz release/country options to Integrations; keep musicBrainz in general
|
||||||
const general = state.general as Record<string, unknown>;
|
const general = state.general as Record<string, unknown>;
|
||||||
state.integrations = {
|
state.integrations = {
|
||||||
|
musicbrainzAutoCountryPriority: initialState.integrations.musicbrainzAutoCountryPriority,
|
||||||
musicBrainz: initialState.integrations.musicBrainz,
|
musicBrainz: initialState.integrations.musicBrainz,
|
||||||
musicBrainzExcludeReleaseTypes:
|
musicBrainzExcludeReleaseTypes:
|
||||||
(general?.musicBrainzExcludeReleaseTypes as string[]) ??
|
(general?.musicBrainzExcludeReleaseTypes as string[]) ??
|
||||||
@@ -2130,10 +2133,19 @@ export const useSettingsStore = createWithEqualityFn<SettingsSlice>()(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (version <= 26) {
|
||||||
|
state.integrations = {
|
||||||
|
...state.integrations,
|
||||||
|
musicbrainzAutoCountryPriority:
|
||||||
|
(state.integrations as { musicbrainzAutoCountryPriority?: boolean })
|
||||||
|
?.musicbrainzAutoCountryPriority ?? false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return persistedState;
|
return persistedState;
|
||||||
},
|
},
|
||||||
name: 'store_settings',
|
name: 'store_settings',
|
||||||
version: 26,
|
version: 27,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user