import axios, { AxiosResponse } from 'axios'; import { InternetProviderLyricResponse, InternetProviderLyricSearchResponse, LyricSearchQuery, LyricSource, } from '.'; import { orderSearchResults } from './shared'; const SEARCH_URL = 'https://music.163.com/api/search/get'; const LYRICS_URL = 'https://music.163.com/api/song/lyric'; // Adapted from https://github.com/NyaomiDEV/Sunamu/blob/master/src/main/lyricproviders/netease.ts export interface Result { hasMore: boolean; songCount: number; songs: Song[]; } export interface Song { album: Album; alias: string[]; artists: Artist[]; copyrightId: number; duration: number; fee: number; ftype: number; id: number; mark: number; mvid: number; name: string; rtype: number; rUrl: null; status: number; transNames?: string[]; } interface Album { artist: Artist; copyrightId: number; id: number; mark: number; name: string; picId: number; publishTime: number; size: number; status: number; transNames?: string[]; } interface Artist { albumSize: number; alias: any[]; fansGroup: null; id: number; img1v1: number; img1v1Url: string; name: string; picId: number; picUrl: null; trans: null; } interface NetEaseResponse { code: number; result: Result; } export async function getLyricsBySongId(songId: string): Promise { let result: AxiosResponse; try { result = await axios.get(LYRICS_URL, { params: { id: songId, kv: '-1', lv: '-1', }, }); } catch (e) { console.error('NetEase lyrics request got an error!', e); return null; } return result.data.klyric?.lyric || result.data.lrc?.lyric; } export async function getSearchResults( params: LyricSearchQuery, ): Promise { let result: AxiosResponse; const searchQuery = [params.artist, params.name].join(' '); if (!searchQuery) { return null; } try { result = await axios.get(SEARCH_URL, { params: { limit: 5, offset: 0, s: searchQuery, type: '1', }, }); } catch (e) { console.error('NetEase search request got an error!', e); return null; } const rawSongsResult = result?.data.result?.songs; if (!rawSongsResult) return null; const songResults: InternetProviderLyricSearchResponse[] = rawSongsResult.map((song) => { const artist = song.artists ? song.artists.map((artist) => artist.name).join(', ') : ''; return { artist, id: String(song.id), name: song.name, source: LyricSource.NETEASE, }; }); return orderSearchResults({ params, results: songResults }); } export async function query( params: LyricSearchQuery, ): Promise { const lyricsMatch = await getMatchedLyrics(params); if (!lyricsMatch) { console.error('Could not find the song on NetEase!'); return null; } const lyrics = await getLyricsBySongId(lyricsMatch.id); if (!lyrics) { console.error('Could not get lyrics on NetEase!'); return null; } return { artist: lyricsMatch.artist, id: lyricsMatch.id, lyrics, name: lyricsMatch.name, source: LyricSource.NETEASE, }; } async function getMatchedLyrics( params: LyricSearchQuery, ): Promise> { const results = await getSearchResults(params); const firstMatch = results?.[0]; if (!firstMatch || (firstMatch?.score && firstMatch.score > 0.5)) { return null; } return firstMatch; }