11import { useApp } from "@app/providers" ;
2- import { Container , Icon , Spinner , useTimedText } from "@common" ;
3- import { LyricsUtil , useLyrics , useQueue } from "@queue" ;
2+ import { Button , Container , Divider , Icon , Input , Spinner , Text , useTimedText } from "@common" ;
3+ import { LyricsUtil , useLyrics , usePlayerSpeed , useQueue } from "@queue" ;
4+ import { useSettings } from "@settings" ;
45import { For , Match , Switch , createEffect , onMount , type Component } from "solid-js" ;
56import "./lyrics.style.css" ;
67
@@ -25,12 +26,16 @@ export const Lyrics: Component = () => {
2526 let container ! : HTMLDivElement ;
2627 const app = useApp ( ) ! ;
2728 const queue = useQueue ( ) ! ;
29+ const speed = usePlayerSpeed ( ) ;
30+ const { settings, setSettings } = useSettings ( ) ;
2831 const lyrics = useLyrics ( ) ;
2932 const timedText = useTimedText ( ( ) => {
3033 const lyrics = syncedLyrics ( ) ;
3134 return {
35+ offset : settings [ "app.lyrics.offset" ] ,
3236 elapsed : queue . data . position / 1000 ,
33- timedTexts : lyrics || [ ] ,
37+ timedTexts : lyrics ?. content || [ ] ,
38+ speed : speed ( ) ,
3439 } ;
3540 } ) ;
3641
@@ -52,9 +57,14 @@ export const Lyrics: Component = () => {
5257 const bDiff = Math . abs ( b . duration - nowPlaying . mediaSource . duration ) ;
5358 return aDiff - bDiff ;
5459 } )
55- . at ( 0 ) ?. synced ;
56-
57- return bestMatch ? LyricsUtil . parse ( bestMatch ) . synced : null ;
60+ . at ( 0 ) ;
61+
62+ return bestMatch ?. synced
63+ ? {
64+ source : bestMatch . source ,
65+ content : LyricsUtil . parse ( bestMatch . synced ) . synced ,
66+ }
67+ : null ;
5868 } ;
5969
6070 const normalLyrics = ( ) => {
@@ -68,7 +78,7 @@ export const Lyrics: Component = () => {
6878 if ( unsyncedLyrics ?. unsynced ) {
6979 return {
7080 content : unsyncedLyrics . unsynced ,
71- description : unsyncedLyrics . source ,
81+ source : unsyncedLyrics . source ,
7282 } ;
7383 }
7484
@@ -79,13 +89,17 @@ export const Lyrics: Component = () => {
7989 LyricsUtil . parse ( synced . synced )
8090 . synced ?. map ( ( s ) => s . text )
8191 . join ( "\n" ) || "" ,
82- description : synced . source ,
92+ source : synced . source ,
8393 } ;
8494 }
8595
8696 return null ;
8797 } ;
8898
99+ const source = ( ) => {
100+ return ( syncedLyrics ( ) ?. source || normalLyrics ( ) ?. source || "-" ) . toUpperCase ( ) ;
101+ } ;
102+
89103 createEffect ( ( ) => {
90104 if ( timedText . index ( ) === - 1 && container ) {
91105 container . scrollTop = 0 ;
@@ -112,51 +126,104 @@ export const Lyrics: Component = () => {
112126 } ;
113127
114128 return (
115- < Container
116- size = "full"
117- extraClass = "h-full flex flex-col items-center space-y-2.5"
118- centered
119- ref = { container }
120- onScroll = { onContainerScrollHandler }
121- >
122- < Switch fallback = { < LyricsNotFound /> } >
123- < Match when = { lyrics . data . loading } >
124- < Loading />
125- </ Match >
126- < Match when = { syncedLyrics ( ) } keyed >
127- < For each = { syncedLyrics ( ) } >
128- { ( t , i ) => (
129- < div
130- class = "space-y-1 py-2 text"
131- classList = { {
132- "text-neutral-300" : i ( ) < timedText . index ( ) ,
133- "text-neutral-500" : i ( ) > timedText . index ( ) ,
134- "!text-neutral-300" : i ( ) === timedText . index ( ) + 1 ,
135- "!text-neutral-400" : i ( ) === timedText . index ( ) + 2 ,
136- "text-xl md:text-2xl" : i ( ) !== timedText . index ( ) ,
137- "font-semibold text-2xl md:text-3xl !text-neutral-100" : i ( ) === timedText . index ( ) ,
138- } }
139- >
140- < div > { t . text } </ div >
141- </ div >
129+ < div class = "flex flex-col h-full overflow-y-auto space-y-0.5 md:space-y-2" >
130+ < Container
131+ size = "full"
132+ extraClass = "h-full flex flex-col items-center space-y-2.5"
133+ centered
134+ ref = { container }
135+ onScroll = { onContainerScrollHandler }
136+ >
137+ < Switch fallback = { < LyricsNotFound /> } >
138+ < Match when = { lyrics . data . loading } >
139+ < Loading />
140+ </ Match >
141+ < Match when = { syncedLyrics ( ) } keyed >
142+ < For each = { syncedLyrics ( ) ?. content } >
143+ { ( t , i ) => (
144+ < div
145+ class = "space-y-1 py-2 text"
146+ classList = { {
147+ "text-neutral-300" : i ( ) < timedText . index ( ) ,
148+ "text-neutral-500" : i ( ) > timedText . index ( ) ,
149+ "!text-neutral-300" : i ( ) === timedText . index ( ) + 1 ,
150+ "!text-neutral-400" : i ( ) === timedText . index ( ) + 2 ,
151+ "text-xl md:text-2xl" : i ( ) !== timedText . index ( ) ,
152+ "font-semibold text-2xl md:text-3xl !text-neutral-100" :
153+ i ( ) === timedText . index ( ) ,
154+ } }
155+ >
156+ < div > { t . text } </ div >
157+ </ div >
158+ ) }
159+ </ For >
160+ </ Match >
161+ < Match when = { normalLyrics ( ) } keyed >
162+ { ( { content } ) => (
163+ < >
164+ < For each = { content . split ( / \r ? \n / ) } >
165+ { ( t ) => (
166+ < div
167+ class = "!text-lg md:!text-xl text-neutral-300 text"
168+ classList = { { "py-1" : ! t } }
169+ >
170+ { t }
171+ </ div >
172+ ) }
173+ </ For >
174+ </ >
142175 ) }
143- </ For >
144- </ Match >
145- < Match when = { normalLyrics ( ) } keyed >
146- { ( { content, description } ) => (
147- < >
148- < For each = { content . split ( / \r ? \n / ) } >
149- { ( t ) => (
150- < div class = "!text-lg md:!text-xl text-neutral-300 text" classList = { { "py-1" : ! t } } >
151- { t }
176+ </ Match >
177+ </ Switch >
178+ </ Container >
179+
180+ < div class = "shrink" >
181+ < Container
182+ padless
183+ extraClass = { "h-full py-3 px-4 md:px-8 flex flex-row items-center space-x-4 md:space-x-6" }
184+ >
185+ < div class = "flex flex-row h-full items-center space-x-4" >
186+ < Text . Caption1 > Offset</ Text . Caption1 >
187+ < div class = "flex flex-row h-full space-x-2" >
188+ < Input
189+ type = "number"
190+ outlined
191+ dense
192+ prefix = { ( ) => (
193+ < Button
194+ flat
195+ onClick = { ( ) => setSettings ( "app.lyrics.offset" , ( v ) => v - 100 ) }
196+ class = "px-2"
197+ >
198+ -
199+ </ Button >
200+ ) }
201+ class = "h-full w-36 appearance-none"
202+ inputExtraClass = "text-center"
203+ suffix = { ( ) => (
204+ < div class = "flex flex-row items-center space-x-1.5" >
205+ < Text . Caption1 > s</ Text . Caption1 >
206+ < Button
207+ flat
208+ onClick = { ( ) => setSettings ( "app.lyrics.offset" , ( v ) => v + 100 ) }
209+ class = "px-2"
210+ >
211+ +
212+ </ Button >
152213 </ div >
153214 ) }
154- </ For >
155- < div class = "pt-8 text-neutral-400 text" > { description } </ div >
156- </ >
157- ) }
158- </ Match >
159- </ Switch >
160- </ Container >
215+ value = { settings [ "app.lyrics.offset" ] / 1000 }
216+ step = { 0.1 }
217+ onChange = { ( e ) => {
218+ setSettings ( "app.lyrics.offset" , + e . currentTarget . value * 1000 ) ;
219+ } }
220+ />
221+ </ div >
222+ </ div >
223+ < Divider vertical dark extraClass = "h-full" />
224+ < Text . Caption1 > Source: { source ( ) } </ Text . Caption1 >
225+ </ Container >
226+ </ div >
227+ </ div >
161228 ) ;
162229} ;
0 commit comments