11import { createStore } from 'solid-js/store' ;
22import { createMemo } from 'solid-js' ;
3+ import { detect } from 'tinyld' ;
34
45import { getSongInfo } from '@/providers/song-info-front' ;
56
@@ -10,7 +11,7 @@ import {
1011} from '../providers' ;
1112import { providers } from '../providers/renderer' ;
1213
13- import type { LyricProvider } from '../types' ;
14+ import type { LyricProvider , LyricResult } from '../types' ;
1415import type { SongInfo } from '@/providers/song-info' ;
1516
1617type LyricsStore = {
@@ -51,6 +52,39 @@ interface SearchCache {
5152
5253// TODO: Maybe use localStorage for the cache.
5354const searchCache = new Map < VideoId , SearchCache > ( ) ;
55+
56+ /**
57+ * Detects the language of lyrics and adds it to the result.
58+ * Handles edge cases: no lyrics, empty text, detection failure.
59+ */
60+ const detectLyricsLanguage = ( result : LyricResult | null ) : LyricResult | null => {
61+ if ( ! result ) return null ;
62+
63+ try {
64+ // Extract text from either plain lyrics or synced lines
65+ let textToAnalyze = '' ;
66+
67+ if ( result . lyrics ) {
68+ textToAnalyze = result . lyrics . trim ( ) ;
69+ } else if ( result . lines && result . lines . length > 0 ) {
70+ textToAnalyze = result . lines . map ( line => line . text ) . join ( '\n' ) . trim ( ) ;
71+ }
72+
73+ // Only attempt detection if we have meaningful text
74+ if ( textToAnalyze . length > 0 ) {
75+ const detectedLang = detect ( textToAnalyze ) ;
76+ // Only set language if detection was successful (not empty string)
77+ if ( detectedLang ) {
78+ result . language = detectedLang ;
79+ }
80+ }
81+ } catch ( error ) {
82+ // Detection failed - log but don't throw, just leave language undefined
83+ console . warn ( 'Language detection failed:' , error ) ;
84+ }
85+
86+ return result ;
87+ } ;
5488export const fetchLyrics = ( info : SongInfo ) => {
5589 if ( searchCache . has ( info . videoId ) ) {
5690 const cache = searchCache . get ( info . videoId ) ! ;
@@ -100,16 +134,19 @@ export const fetchLyrics = (info: SongInfo) => {
100134 provider
101135 . search ( info )
102136 . then ( ( res ) => {
137+ // Detect language from the lyrics result
138+ const resultWithLanguage = detectLyricsLanguage ( res ) ;
139+
103140 pCache . state = 'done' ;
104- pCache . data = res ;
141+ pCache . data = resultWithLanguage ;
105142
106143 if ( getSongInfo ( ) . videoId === info . videoId ) {
107144 setLyricsStore ( 'lyrics' , ( old ) => {
108145 return {
109146 ...old ,
110147 [ providerName ] : {
111148 state : 'done' ,
112- data : res ? { ...res } : null ,
149+ data : resultWithLanguage ? { ...resultWithLanguage } : null ,
113150 error : null ,
114151 } ,
115152 } ;
@@ -157,10 +194,13 @@ export const retrySearch = (provider: ProviderName, info: SongInfo) => {
157194 providers [ provider ]
158195 . search ( info )
159196 . then ( ( res ) => {
197+ // Detect language from the lyrics result
198+ const resultWithLanguage = detectLyricsLanguage ( res ) ;
199+
160200 setLyricsStore ( 'lyrics' , ( old ) => {
161201 return {
162202 ...old ,
163- [ provider ] : { state : 'done' , data : res , error : null } ,
203+ [ provider ] : { state : 'done' , data : resultWithLanguage , error : null } ,
164204 } ;
165205 } ) ;
166206 } )
0 commit comments