@@ -595,7 +595,54 @@ function PopupLyrics() {
595595 lyrics = ogLyrics ;
596596
597597 return { lyrics } ;
598- }
598+ } ,
599+
600+ async fetchLrclib ( info ) {
601+ const baseURL = "https://lrclib.net/api/get" ;
602+ const durr = info . duration / 1000 ;
603+ const params = {
604+ track_name : info . title ,
605+ artist_name : info . artist ,
606+ album_name : info . album ,
607+ duration : durr ,
608+ } ;
609+ const finalURL = `${ baseURL } ?${ Object . keys ( params )
610+ . map ( ( key ) => `${ key } =${ encodeURIComponent ( params [ key ] ) } ` )
611+ . join ( "&" ) } `;
612+ const body = await fetch ( finalURL , {
613+ headers : {
614+ "x-user-agent" : `spicetify v${ Spicetify . Config . version } (https://github.com/spicetify/cli)` ,
615+ } ,
616+ } ) ;
617+ if ( body . status !== 200 ) {
618+ return { error : "No lyrics" } ;
619+ }
620+ const meta = await body . json ( ) ;
621+ if ( meta ?. instrumental ) {
622+ return { error : "Instrumental" } ;
623+ }
624+ if ( ! meta ?. syncedLyrics ) {
625+ return { error : "No lyrics" } ;
626+ }
627+ // Preprocess lyrics by removing [tags] and empty lines
628+ const lines = meta ?. syncedLyrics
629+ . replaceAll ( / \[ [ a - z A - Z ] + : .+ \] / g, "" )
630+ . trim ( )
631+ . split ( "\n" ) ;
632+ const syncedTimestamp = / \[ ( [ 0 - 9 : . ] + ) \] / ;
633+ const isSynced = lines [ 0 ] . match ( syncedTimestamp ) ;
634+ const lyrics = lines . map ( ( line ) => {
635+ const time = line . match ( syncedTimestamp ) ?. [ 1 ] ;
636+ const lyricContent = line . replace ( syncedTimestamp , "" ) . trim ( ) ;
637+ const lyric = lyricContent . replaceAll ( / \< ( [ 0 - 9 : . ] + ) \> / g, "" ) . trim ( ) ;
638+ const [ min , sec ] = time . replace ( / \[ \] \< \> / , "" ) . split ( ":" ) ;
639+ if ( line . trim ( ) !== "" && isSynced && time ) {
640+ return { text : lyric || "♪" , startTime : Number ( min ) * 60 + Number ( sec ) } ;
641+ }
642+ return ;
643+ } ) ;
644+ return { lyrics } ;
645+ } ,
599646 } ;
600647
601648 const userConfigs = {
@@ -629,7 +676,12 @@ function PopupLyrics() {
629676 on : boolLocalStorage ( "popup-lyrics:services:spotify:on" ) ,
630677 call : LyricProviders . fetchSpotify ,
631678 desc : "Lyrics sourced from official Spotify API."
632- }
679+ } ,
680+ lrclib : {
681+ on : boolLocalStorage ( "popup-lyrics:services:lrclib:on" ) ,
682+ call : LyricProviders . fetchLrclib ,
683+ desc : "Lyrics sourced from lrclib.net. Supports both synced and unsynced lyrics. LRCLIB is a free and open-source lyrics provider." ,
684+ } ,
633685 } ,
634686 servicesOrder : [ ]
635687 } ;
0 commit comments