Add support for OpenSubsonic enhanced lyrics (#2208)

This commit is contained in:
Jeff
2026-07-09 21:32:05 -07:00
committed by GitHub
parent 0c89fea1ea
commit 355b19c1cb
55 changed files with 4213 additions and 480 deletions
@@ -8,6 +8,7 @@ import md5 from 'md5';
import { z } from 'zod';
import { contract, ssApiClient } from '/@/renderer/api/subsonic/subsonic-api';
import { mapStructuredLyric } from '/@/renderer/api/subsonic/subsonic-structured-lyrics';
import {
getDefaultTranscodingProfiles,
getDirectPlayProfiles,
@@ -21,7 +22,13 @@ import {
ssType,
SubsonicExtensions,
} from '/@/shared/api/subsonic/subsonic-types';
import { hasFeature, sortAlbumArtistList, sortAlbumList, sortSongList } from '/@/shared/api/utils';
import {
hasFeature,
hasFeatureWithVersion,
sortAlbumArtistList,
sortAlbumList,
sortSongList,
} from '/@/shared/api/utils';
import {
AlbumListSort,
GenreListSort,
@@ -1381,7 +1388,7 @@ export const SubsonicController: InternalControllerEndpoint = {
}
if (subsonicFeatures[SubsonicExtensions.SONG_LYRICS]) {
features.lyricsMultipleStructured = [1];
features.lyricsMultipleStructured = subsonicFeatures[SubsonicExtensions.SONG_LYRICS];
}
if (subsonicFeatures[SubsonicExtensions.FORM_POST]) {
@@ -1961,9 +1968,16 @@ export const SubsonicController: InternalControllerEndpoint = {
},
getStructuredLyrics: async (args) => {
const { apiClientProps, query } = args;
const server = apiClientProps.server;
const supportsEnhancedLyrics = hasFeatureWithVersion(
server,
ServerFeature.LYRICS_MULTIPLE_STRUCTURED,
2,
);
const res = await ssApiClient(apiClientProps).getStructuredLyrics({
query: {
enhanced: supportsEnhancedLyrics ? true : undefined,
id: query.songId,
},
});
@@ -1978,28 +1992,9 @@ export const SubsonicController: InternalControllerEndpoint = {
return [];
}
return lyrics.map((lyric) => {
const baseLyric = {
artist: lyric.displayArtist || '',
lang: lyric.lang,
name: lyric.displayTitle || '',
remote: false,
source: apiClientProps.server?.name || 'music server',
};
const source = apiClientProps.server?.name || 'music server';
if (lyric.synced) {
return {
...baseLyric,
lyrics: lyric.line.map((line) => [line.start!, line.value]),
synced: true,
};
}
return {
...baseLyric,
lyrics: lyric.line.map((line) => [line.value]).join('\n'),
synced: false,
};
});
return lyrics.map((lyric) => mapStructuredLyric(lyric, source));
},
getTopSongs: async (args) => {
const { apiClientProps, query } = args;