mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 04:20:12 +02:00
feat(lyrics): simpmusic lyrics provider (#1820)
* feat(lyrics): simpmusic lyrics provider
This commit is contained in:
@@ -5,6 +5,10 @@ import { getLyricsBySongId as getGenius, getSearchResults as searchGenius } from
|
|||||||
import { getLyricsBySongId as getLrcLib, getSearchResults as searchLrcLib } from './lrclib';
|
import { getLyricsBySongId as getLrcLib, getSearchResults as searchLrcLib } from './lrclib';
|
||||||
import { getLyricsBySongId as getNetease, getSearchResults as searchNetease } from './netease';
|
import { getLyricsBySongId as getNetease, getSearchResults as searchNetease } from './netease';
|
||||||
import { orderSearchResults } from './shared';
|
import { orderSearchResults } from './shared';
|
||||||
|
import {
|
||||||
|
getLyricsBySongId as getSimpMusic,
|
||||||
|
getSearchResults as searchSimpMusic,
|
||||||
|
} from './simpmusic';
|
||||||
|
|
||||||
import { Song } from '/@/shared/types/domain-types';
|
import { Song } from '/@/shared/types/domain-types';
|
||||||
|
|
||||||
@@ -12,6 +16,7 @@ export enum LyricSource {
|
|||||||
GENIUS = 'Genius',
|
GENIUS = 'Genius',
|
||||||
LRCLIB = 'lrclib.net',
|
LRCLIB = 'lrclib.net',
|
||||||
NETEASE = 'NetEase',
|
NETEASE = 'NetEase',
|
||||||
|
SIMPMUSIC = 'SimpMusic',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FullLyricsMetadata = Omit<InternetProviderLyricResponse, 'id' | 'lyrics' | 'source'> & {
|
export type FullLyricsMetadata = Omit<InternetProviderLyricResponse, 'id' | 'lyrics' | 'source'> & {
|
||||||
@@ -66,12 +71,14 @@ const SEARCH_FETCHERS: Record<LyricSource, SearchFetcher> = {
|
|||||||
[LyricSource.GENIUS]: searchGenius,
|
[LyricSource.GENIUS]: searchGenius,
|
||||||
[LyricSource.LRCLIB]: searchLrcLib,
|
[LyricSource.LRCLIB]: searchLrcLib,
|
||||||
[LyricSource.NETEASE]: searchNetease,
|
[LyricSource.NETEASE]: searchNetease,
|
||||||
|
[LyricSource.SIMPMUSIC]: searchSimpMusic,
|
||||||
};
|
};
|
||||||
|
|
||||||
const GET_FETCHERS: Record<LyricSource, GetFetcher> = {
|
const GET_FETCHERS: Record<LyricSource, GetFetcher> = {
|
||||||
[LyricSource.GENIUS]: getGenius,
|
[LyricSource.GENIUS]: getGenius,
|
||||||
[LyricSource.LRCLIB]: getLrcLib,
|
[LyricSource.LRCLIB]: getLrcLib,
|
||||||
[LyricSource.NETEASE]: getNetease,
|
[LyricSource.NETEASE]: getNetease,
|
||||||
|
[LyricSource.SIMPMUSIC]: getSimpMusic,
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_CACHED_ITEMS = 10;
|
const MAX_CACHED_ITEMS = 10;
|
||||||
@@ -191,6 +198,7 @@ const searchRemoteLyrics = async (params: LyricSearchQuery) => {
|
|||||||
[LyricSource.GENIUS]: [],
|
[LyricSource.GENIUS]: [],
|
||||||
[LyricSource.LRCLIB]: [],
|
[LyricSource.LRCLIB]: [],
|
||||||
[LyricSource.NETEASE]: [],
|
[LyricSource.NETEASE]: [],
|
||||||
|
[LyricSource.SIMPMUSIC]: [],
|
||||||
};
|
};
|
||||||
for (const item of allSearchResults) {
|
for (const item of allSearchResults) {
|
||||||
results[item.source].push(item);
|
results[item.source].push(item);
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
import axios, { AxiosResponse } from 'axios';
|
||||||
|
|
||||||
|
import {
|
||||||
|
InternetProviderLyricResponse,
|
||||||
|
InternetProviderLyricSearchResponse,
|
||||||
|
LyricSearchQuery,
|
||||||
|
LyricSource,
|
||||||
|
} from '.';
|
||||||
|
import { orderSearchResults } from './shared';
|
||||||
|
|
||||||
|
const API_URL = 'https://api-lyrics.simpmusic.org/v1';
|
||||||
|
|
||||||
|
const TIMEOUT_MS = 5000;
|
||||||
|
|
||||||
|
export interface SimpMusicLyric {
|
||||||
|
albumName?: string;
|
||||||
|
artistName: string;
|
||||||
|
durationSeconds?: number;
|
||||||
|
id: string;
|
||||||
|
plainLyric?: string;
|
||||||
|
richSyncLyrics?: string;
|
||||||
|
songTitle: string;
|
||||||
|
syncedLyrics?: string;
|
||||||
|
videoId: string;
|
||||||
|
vote?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SimpMusicSearchResponse {
|
||||||
|
data: SimpMusicLyric[];
|
||||||
|
success: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getLyricsBySongId(songId: string): Promise<null | string> {
|
||||||
|
let result: AxiosResponse;
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = await axios.get(`${API_URL}/${songId}`, {
|
||||||
|
timeout: TIMEOUT_MS,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('SimpMusic lyrics request errored:', (e as Error)?.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstLyric = (result.data.data?.[0] ?? null) as null | SimpMusicLyric;
|
||||||
|
if (!firstLyric) return null;
|
||||||
|
|
||||||
|
return firstLyric.syncedLyrics || firstLyric.plainLyric || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSearchResults(
|
||||||
|
params: LyricSearchQuery,
|
||||||
|
): Promise<InternetProviderLyricSearchResponse[] | null> {
|
||||||
|
let result: AxiosResponse<SimpMusicSearchResponse>;
|
||||||
|
|
||||||
|
if (!params.name) return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = await axios.get<SimpMusicSearchResponse>(`${API_URL}/search`, {
|
||||||
|
params: {
|
||||||
|
q: params.name,
|
||||||
|
},
|
||||||
|
timeout: TIMEOUT_MS,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('SimpMusic search errored:', (e as Error)?.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.data?.data) return null;
|
||||||
|
|
||||||
|
const songResults: InternetProviderLyricSearchResponse[] = result.data.data.map((song) => ({
|
||||||
|
artist: song.artistName,
|
||||||
|
id: song.videoId,
|
||||||
|
isSync: song.syncedLyrics ? true : false,
|
||||||
|
name: song.songTitle,
|
||||||
|
source: LyricSource.SIMPMUSIC,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return orderSearchResults({ params, results: songResults });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function query(
|
||||||
|
params: LyricSearchQuery,
|
||||||
|
): Promise<InternetProviderLyricResponse | null> {
|
||||||
|
if (!params.name) return null;
|
||||||
|
|
||||||
|
let search: AxiosResponse<SimpMusicSearchResponse>;
|
||||||
|
|
||||||
|
try {
|
||||||
|
search = await axios.get<SimpMusicSearchResponse>(`${API_URL}/search`, {
|
||||||
|
params: {
|
||||||
|
q: params.name,
|
||||||
|
},
|
||||||
|
timeout: TIMEOUT_MS,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('SimpMusic search errored:', (e as Error).message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const first = search.data?.data?.[0];
|
||||||
|
if (!first) return null;
|
||||||
|
|
||||||
|
let lyric: AxiosResponse<SimpMusicLyric>;
|
||||||
|
|
||||||
|
try {
|
||||||
|
lyric = await axios.get<SimpMusicLyric>(`${API_URL}/${first.videoId}`, {
|
||||||
|
timeout: TIMEOUT_MS,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('SimpMusic lyrics fetch errored:', (e as Error).message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lyrics = lyric.data.syncedLyrics || lyric.data.plainLyric || null;
|
||||||
|
if (!lyrics) return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
artist: lyric.data.artistName,
|
||||||
|
id: lyric.data.videoId,
|
||||||
|
lyrics,
|
||||||
|
name: lyric.data.songTitle,
|
||||||
|
source: LyricSource.SIMPMUSIC,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -167,6 +167,9 @@ const getSettingsProperties = (): SettingsProperties => {
|
|||||||
'settings.lyrics.sources.netease': ignoreWeb(
|
'settings.lyrics.sources.netease': ignoreWeb(
|
||||||
settings.lyrics.sources.includes(LyricSource.NETEASE),
|
settings.lyrics.sources.includes(LyricSource.NETEASE),
|
||||||
),
|
),
|
||||||
|
'settings.lyrics.sources.simpmusic': ignoreWeb(
|
||||||
|
settings.lyrics.sources.includes(LyricSource.SIMPMUSIC),
|
||||||
|
),
|
||||||
'settings.minimizeToTray': ignoreWeb(settings.window.minimizeToTray),
|
'settings.minimizeToTray': ignoreWeb(settings.window.minimizeToTray),
|
||||||
// 'settings.musicBrainz': settings.general.musicBrainz,
|
// 'settings.musicBrainz': settings.general.musicBrainz,
|
||||||
'settings.nativeAspectRatio': settings.general.nativeAspectRatio,
|
'settings.nativeAspectRatio': settings.general.nativeAspectRatio,
|
||||||
|
|||||||
@@ -1346,6 +1346,7 @@ export enum LyricSource {
|
|||||||
GENIUS = 'Genius',
|
GENIUS = 'Genius',
|
||||||
LRCLIB = 'lrclib.net',
|
LRCLIB = 'lrclib.net',
|
||||||
NETEASE = 'NetEase',
|
NETEASE = 'NetEase',
|
||||||
|
SIMPMUSIC = 'SimpMusic',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AlbumRadioArgs = BaseEndpointArgs & {
|
export type AlbumRadioArgs = BaseEndpointArgs & {
|
||||||
|
|||||||
Reference in New Issue
Block a user