It is currently September 9th, 2024, 11:25 am

[Friendly Resource] If PlayerType=Lyrics needs an update, LRCLIB can be used

Report bugs with the Rainmeter application and suggest features.
User avatar
Yincognito
Rainmeter Sage
Posts: 8050
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Friendly Resource] If PlayerType=Lyrics needs an update, LRCLIB can be used

Post by Yincognito »

Rhyuno wrote: August 11th, 2024, 3:13 pm Oof, my bad—I forgot to change the values of those. Anyway, everything is alright now, and everything is working completely normal. By the way, is there any way to change where the lyrics will start and end? I want the "karaoke" line to always stay in the middle of the skin. Maybe by adding blank "new lines" before and after the lyrics?
lyrics.jpg
Great news! :thumbup:

Yeah, I actually had the same idea as you did when I began writing the sample, with the highlighted karaoke line staying in the vertical middle of the lyrics box / container, and this is why, even though I didn't implemented at the time, I took additional care to Clamp the #Offset# value right in the Y option of the meter and not before.

What you want is easy to do, as it's just simple math - you'd have to slightly adjust the Y in the [LyricsText] meter (or the equivalent in your skin). So, instead of:
Y=(-Clamp(#Offset#,0,Clamp([LyricsText:H]-[LyricsContainer:H],0,[LyricsText:H])))
like it is now, to place the lyrics text with the current line always in the vertical middle of the lyrics box, make it:
Y=(-Clamp(#Offset#,0,Clamp([LyricsText:H]-[LyricsContainer:H],0,[LyricsText:H]))+[LyricsContainer:H]*0.5)
or, to place the lyrics text with the current line in the vertical middle of the lyrics box only when not at the start or end of the lyrics, make it:
Y=(-Clamp(#Offset#-[LyricsContainer:H]*0.5,0,Clamp([LyricsText:H]-[LyricsContainer:H],0,[LyricsText:H])))
I personally prefer the latter so as to not have any ugly empty space in the lyrics box, but it's your choice. Obviously, the 0.5 means a half (of the lyrics box), but you might want to decrease that a bit to account for half of the line height too (in the original sample, 0.48 looks fine to me), in order for the karaoke line to be fully centered vertically.

Now that it works, feel free to make any other adjustments you like (after making a backup of it, of course) or play with the code, to understand what happens better. 8-)
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
Rhyuno
Posts: 17
Joined: August 4th, 2024, 6:30 am

Re: [Friendly Resource] If PlayerType=Lyrics needs an update, LRCLIB can be used

Post by Rhyuno »

Yincognito wrote: August 11th, 2024, 4:43 pm What you want is easy to do, as it's just simple math - you'd have to slightly adjust the Y in the [LyricsText] meter (or the equivalent in your skin). So, instead of:
Y=(-Clamp(#Offset#,0,Clamp([LyricsText:H]-[LyricsContainer:H],0,[LyricsText:H])))
like it is now, to place the lyrics text with the current line always in the vertical middle of the lyrics box, make it:
Y=(-Clamp(#Offset#,0,Clamp([LyricsText:H]-[LyricsContainer:H],0,[LyricsText:H]))+[LyricsContainer:H]*0.5)
or, to place the lyrics text with the current line in the vertical middle of the lyrics box only when not at the start or end of the lyrics, make it:
Y=(-Clamp(#Offset#-[LyricsContainer:H]*0.5,0,Clamp([LyricsText:H]-[LyricsContainer:H],0,[LyricsText:H])))
I tried both options, and both are great, but I'm having trouble manually scrolling whenever the song is stopped. I'm not exactly sure what's causing this, but it seems like the scrolling stops at a certain point in the lyrics (for any song), and I can't scroll further. Here's what it looks like:
troubleshoot.jpg
There are still lyrics past that point, but I can't scroll further. I'm experiencing this problem with both options and never had it with the "original" setup. Here’s what my code looks like:

Code: Select all

[Variables]
BackgroundW=400
BackgroundH=150
Margin=10
LyricsColor=170,170,170,255
KaraokeColor=255,255,255,255
FontFace=Montserrat Light
FontSize=9
FontPerc=1
BoxColor=0,0,0,200
Player=Spotify
Offset=0
LineH=0
Lines=0
Line=0

[Rainmeter]
Update=1000
AccurateText=1
DynamicWindowSize=1

---Measures---

[Status]
Group=PlayerGroup
Measure=Plugin
Plugin=WebNowPlaying
PlayerName=#Player#
PlayerType=Status

[State]
Group=PlayerGroup
Measure=Plugin
Plugin=WebNowPlaying
PlayerName=[Status]
PlayerType=State

[Artist]
Group=PlayerGroup
Measure=Plugin
Plugin=WebNowPlaying
PlayerName=[Status]
PlayerType=Artist

[Album]
Group=PlayerGroup
Measure=Plugin
Plugin=WebNowPlaying
PlayerName=[Status]
PlayerType=Album

[Title]
Group=PlayerGroup
Measure=Plugin
Plugin=WebNowPlaying
PlayerName=[Status]
PlayerType=Title

[Duration]
Group=PlayerGroup
Measure=Plugin
Plugin=WebNowPlaying
PlayerName=[Status]
PlayerType=Duration

[Position]
Group=PlayerGroup
Measure=Plugin
Plugin=WebNowPlaying
PlayerName=[Status]
PlayerType=Position
RegExpSubstitute=1
Substitute="(?sU)^(\d):":"0\1:"
OnChangeAction=[!UpdateMeasureGroup LinesGroup]

[Progress]
Group=PlayerGroup
Measure=Plugin
Plugin=WebNowPlaying
PlayerName=[Status]
PlayerType=Progress

[URL]
Measure=String
String=https://lrclib.net/api/get?artist_name=[&Artist]&album_name=[&Album]&track_name=[&Title]&duration=[&Duration:]
OnChangeAction=[!SetVariable Offset 0][!CommandMeasure SyncedLyrics "Update"]
DynamicVariables=1

[SyncedLyrics]
Measure=WebParser
URL=https://lrclib.net/api/get?artist_name=[&Artist]&album_name=[&Album]&track_name=[&Title]&duration=[&Duration:]
UserAgent=Rainmeter 4.5.18 (https://github.com/rainmeter)
RegExp=(?siU)[{,]"syncedLyrics":"(.*)"[,}]
StringIndex=1
UpdateRate=-1
RegExpSubstitute=1
Substitute='(?sU)\\"':'"',"(?sU)\\n":"#CRLF#"
FinishAction=[!UpdateMeasureGroup LinesGroup]
IfMatch=(?siU)\[\x005B][Position].+\R
IfMatchAction=[!SetOption LyricsText "InlineSetting" "Color | #KaraokeColor#"][!SetOption LyricsText "InlinePattern" "(?siU)\[\x005B][Position].+\R"]
;IfNotMatchAction=[]
IfMatchMode=1
DynamicVariables=1

[Lines]
Group=LinesGroup
Measure=String
String=[SyncedLyrics]
UpdateDivider=-1
RegExpSubstitute=1
Substitute="(?siU).+(?:\R|$)":"+1","(?siU)^(.*)$":"0\1","\\\d+":""
OnUpdateAction=[!SetVariable Lines ([Lines])][!SetVariable LineH ([LyricsText:H]/([#Lines]=0?1:[#Lines]))]
DynamicVariables=1

[Line]
Group=LinesGroup
Measure=String
String=[SyncedLyrics]
UpdateDivider=-1
RegExpSubstitute=1
Substitute="(?siU)^(?|(.*)\[\x005B][Position].+(?:\R|$).*|((?:.+(?:\R|$)){#Line#}).*)$":"\1","\\\d+":"","(?siU).+(?:\R|$)":"+1","(?siU)^(.*)$":"0\1","\\\d+":""
OnUpdateAction=[!SetVariable Line ([Position:]=0?0:[Line])][!SetVariable Offset ([#LineH]*[#Line])][!UpdateMeter *][!Redraw]
DynamicVariables=1

---Styles---

[Texts]
FontFace=#FontFace#
FontSize=#FontSize#
AntiAlias=1

---Meter---

[LyricsBox]
Meter=Image
X=(#Margin#)
Y=(#Margin#/2)R
W=(#BackgroundW#-#Margin#*2)
H=(#BackgroundH#-[LyricsBox:Y]-#Margin#)
SolidColor=#BoxColor#
UpdateDivider=-1
DynamicVariables=1

[LyricsContainer]
Meter=Image
X=([LyricsBox:X])
Y=([LyricsBox:Y])
W=([LyricsBox:W])
H=([LyricsBox:H])
SolidColor=0,0,0,255
UpdateDivider=-1
MouseScrollUpAction=[!SetVariable Offset (Clamp(#Offset#-#LineH#,0,Clamp([LyricsText:H]-[LyricsContainer:H],0,[LyricsText:H])))][!UpdateMeter LyricsContainer][!UpdateMeter LyricsText][!Redraw]
MouseScrollDownAction=[!SetVariable Offset (Clamp(#Offset#+#LineH#,0,Clamp([LyricsText:H]-[LyricsContainer:H],0,[LyricsText:H])))][!UpdateMeter LyricsContainer][!UpdateMeter LyricsText][!Redraw]
DynamicVariables=1

[LyricsText]
Container=LyricsContainer
Meter=String
MeterStyle=Texts
StringAlign=Center
FontColor=#LyricsColor#
FontSize=(#FontSize#*#FontPerc#)
X=([LyricsBox:W]/2)
Y=(-Clamp(#Offset#-[LyricsContainer:H]*0.43,0,Clamp([LyricsText:H]-[LyricsContainer:H],0,[LyricsText:H])))
W=([LyricsBox:W])
MeasureName=SyncedLyrics
Text=%1
DynamicVariables=1
P.S. I also cleaned up the code a little bit to match only what I needed. I don't really know if that's what's causing the problem, but please let me know. :great:
You do not have the required permissions to view the files attached to this post.
User avatar
Yincognito
Rainmeter Sage
Posts: 8050
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Friendly Resource] If PlayerType=Lyrics needs an update, LRCLIB can be used

Post by Yincognito »

Rhyuno wrote: August 12th, 2024, 10:31 am I tried both options, and both are great, but I'm having trouble manually scrolling whenever the song is stopped. I'm not exactly sure what's causing this, but it seems like the scrolling stops at a certain point in the lyrics (for any song), and I can't scroll further. Here's what it looks like:
troubleshoot.jpg
There are still lyrics past that point, but I can't scroll further. I'm experiencing this problem with both options and never had it with the "original" setup. Here’s what my code looks like:
[...]
P.S. I also cleaned up the code a little bit to match only what I needed. I don't really know if that's what's causing the problem, but please let me know. :great:
Yep, I know, I get that issue too. I was about to edit my post yesterday to correct the solutions, but was too tired to implement both like I wanted. I'll investigate things further and post when I covered both possibilities (I might have covered yours already, but it needs a little bit of refinement). In any case, the whole thing is about adjusting the formulas for both the Y in [LyricsText] AND setting the Offset variable in the scroll actions from [LyricsContainer] accordingly, so yeah, like I said, it's not really about the code itself, but rather about tweaking a bit the math in those formulas.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
Yincognito
Rainmeter Sage
Posts: 8050
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Friendly Resource] If PlayerType=Lyrics needs an update, LRCLIB can be used

Post by Yincognito »

Rhyuno wrote: August 12th, 2024, 10:31 amI'm experiencing this problem with both options and never had it with the "original" setup.
Alright, after having slept on it I approached this a bit differently and managed to write the formulas in a way that allows for either of the "line always in the chosen vertical position" and "line in the chosen position only when not at the start or end of the lyrics" variants to be chosen, by simply changing the value of one of the two variables that I included in an improved version of the sample skin earlier (LockLine = 0 for the 2nd variant, 1 for the 1st variant; LockPerc = decimal percentage starting from the top of the lyrics container where the line should stay):

Code: Select all

[Variables]
BackgroundW=400
BackgroundH=600
StrokeWidth=2
CornerRadius=10
Margin=10
BackgroundColor=0,0,0,128
StrokeColor=255,128,0,255
InfoColor0=255,128,128,255
InfoColor1=128,128,255,255
InfoColor2=128,255,128,255
InfoColor3=255,128,255,255
ControlColor0=255,255,128,255
ControlColor1=128,255,255,255
ControlColor2=128,255,255,255
ControlColor3=255,255,128,255
LyricsColor=192,192,192,255
KaraokeColor=255,255,255,255
FontEffectColor=0,0,0,255
FontColor=255,255,255,255
FontFace=Monotype Corsiva
FontSize=16
StringEffect=Shadow
FontPerc=0.75
BarHPerc=0.80
BarSolid=128,128,128,255
BarColor=0,255,0,255
ControlNum=4
ControlGap=50
Prev=[\x23EE]
Stop=[\x23F9]
Play=[\x23F5]
Next=[\x23ED]
Pause=[\x23F8]
BoxColor=0,0,0,128
Plugin=NowPlaying
Player=Winamp
Offset=0
LockLine=0
LockPerc=0
LineH=0
Lines=0
Line=0

[Rainmeter]
Update=1000
AccurateText=1
DynamicWindowSize=1

---Measures---

[Status]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=#Player#
PlayerType=Status
RegExpSubstitute=1
Substitute="^0$":"Closed","^1$":"Open"
DynamicVariables=1

[State]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=State
RegExpSubstitute=1
Substitute="^0$":"Stopped","^1$":"Playing","^2$":"Paused"
IfCondition=(State=1)
IfTrueAction=[!SetOption Play Text "#Pause#"]
IfFalseAction=[!SetOption Play Text "#Play#"]
DynamicVariables=1

[Artist]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=Artist
RegExpSubstitute=1
Substitute="^$":"No Artist"
DynamicVariables=1

[Album]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=Album
RegExpSubstitute=1
Substitute="^$":"No Album"
DynamicVariables=1

[Title]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=Title
RegExpSubstitute=1
Substitute="^$":"No Title"
DynamicVariables=1

[Duration]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=Duration
RegExpSubstitute=1
Substitute="(?<!\d)(\d)(?!\d)":"0\1"
DynamicVariables=1

[Position]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=Position
RegExpSubstitute=1
Substitute="(?<!\d)(\d)(?!\d)":"0\1"
OnChangeAction=[!UpdateMeasureGroup LinesGroup]
DynamicVariables=1

[Progress]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=Progress
DynamicVariables=1

[Track]
Group=PlayerGroup
Measure=String
String=[Artist] - [Album] - [Title] - [Duration:]
OnChangeAction=[!SetVariable Line 0][!SetVariable Offset 0][!CommandMeasure SyncedLyrics "Update"]
DynamicVariables=1

[SyncedLyrics]
Measure=WebParser
URL=https://lrclib.net/api/get?artist_name=[&Artist]&album_name=[&Album]&track_name=[&Title]&duration=[&Duration:]
UserAgent=Rainmeter 4.5.18 (https://github.com/rainmeter)
RegExp=(?siU)[{,]"syncedLyrics":"(.*)"[,}]
StringIndex=1
UpdateRate=-1
RegExpSubstitute=1
Substitute='(?sU)\\"':'"',"(?sU)\\n":"#CRLF#"
IfMatch=(?siU)\[\x005B][Position].+\R
IfMatchAction=[!SetOption LyricsText "InlineSetting" "Color | #KaraokeColor#"][!SetOption LyricsText "InlinePattern" "(?siU)\[\x005B][Position].+\R"]
IfMatchMode=1
FinishAction=[!UpdateMeasureGroup LinesGroup]
DynamicVariables=1

[Lines]
Group=LinesGroup
Measure=String
String=[SyncedLyrics]
UpdateDivider=-1
RegExpSubstitute=1
Substitute="(?siU).+(?:\R|$)":"+1","(?siU)^(.*)$":"0\1","\\\d+":""
OnUpdateAction=[!SetVariable Lines ([Lines])][!SetVariable LineH ([LyricsText:H]/([#Lines]=0?1:[#Lines]))]
DynamicVariables=1

[Line]
Group=LinesGroup
Measure=String
String=[SyncedLyrics]
UpdateDivider=-1
RegExpSubstitute=1
Substitute="(?siU)(?|^(.*)\[\x005B][Position].+(?:\R|$).*?$|^((?:.+(?:\R|$)){#Line#}).*?$)":"\1","\\\d+":"","(?siU).+(?:\R|$)":"+1","(?siU)^(.*)$":"0\1","\\\d+":""
OnUpdateAction=[!SetVariable Line ([Position:]=0?0:[Line])][!SetVariable Offset ([#LineH]*[#Line])]
DynamicVariables=1

[Reset]
Group=LinesGroup
Measure=Calc
Formula=([Position:]=0?1:0)
UpdateDivider=-1
IfCondition=(Reset=1)
IfTrueAction=[!SetOption LyricsText "InlineSetting" "Color | #KaraokeColor#"][!SetOption LyricsText "InlinePattern" "^$"]
IfConditionMode=1
OnUpdateAction=[!UpdateMeter *][!Redraw]
DynamicVariables=1

---Styles---

[Texts]
FontEffectColor=#FontEffectColor#
FontColor=#FontColor#
FontFace=#FontFace#
FontSize=#FontSize#
AntiAlias=1
StringEffect=#StringEffect#

---Meter---

[Background]
Meter=Shape
Shape=Rectangle (#StrokeWidth#/2),(#StrokeWidth#/2),(#BackgroundW#-#StrokeWidth#),(#BackgroundH#-#StrokeWidth#),(#CornerRadius#),(#CornerRadius#) | Fill Color #BackgroundColor# | Stroke Color #StrokeColor# | StrokeWidth #StrokeWidth#
UpdateDivider=-1

[Information]
Meter=String
MeterStyle=Texts
StringAlign=Center
X=(#BackgroundW#/2)
Y=(#Margin#)
W=(#BackgroundW#-#Margin#*2)
InlineSetting=Color | #InfoColor0#
InlinePattern=^(?:\N*\R){0}(\N*)
InlineSetting2=Color | #InfoColor1#
InlinePattern2=^(?:\N*\R){1}(\N*)
InlineSetting3=Color | #InfoColor2#
InlinePattern3=^(?:\N*\R){2}(\N*)
InlineSetting4=Color | #InfoColor3#
InlinePattern4=^(?:\N*\R){3}(\N*)
MeasureName=Artist
MeasureName2=Album
MeasureName3=Title
MeasureName4=Duration
MeasureName5=Position
MeasureName6=Progress
MeasureName7=Status
MeasureName8=State
Text=%1#CRLF#%2#CRLF#%3#CRLF#%5 of %4 (%6%) - Player is %7 & %8
DynamicVariables=1

[ProgressBar]
Meter=Bar
MeasureName=Progress
X=(#Margin#)
Y=(#Margin#/2)R
W=(#BackgroundW#-#Margin#*2)
H=(#FontSize#*#BarHPerc#)
BarColor=#BarColor#
SolidColor=#BarSolid#
BarOrientation=Horizontal
LeftMouseDownAction=[!CommandMeasure Progress "SetPosition $MouseX:%$"][!UpdateMeasureGroup PlayerGroup][!UpdateMeter *][!Redraw]
DynamicVariables=1

[Prev]
Meter=String
MeterStyle=Texts
X=(#BackgroundW#/2-#ControlGap#/2*(#ControlNum#-1))
Y=(#Margin#/2)R
StringAlign=Center
FontColor=#ControlColor0#
Text=#Prev#
LeftMouseUpAction=[!CommandMeasure Status "Previous"][!UpdateMeasureGroup PlayerGroup][!UpdateMeter *][!Redraw]

[Stop]
Meter=String
MeterStyle=Texts
X=(#ControlGap#)r
Y=(0)r
StringAlign=Center
FontColor=#ControlColor1#
Text=#Stop#
LeftMouseUpAction=[!CommandMeasure Status "Stop"][!UpdateMeasureGroup PlayerGroup][!UpdateMeter *][!Redraw]

[Play]
Meter=String
MeterStyle=Texts
X=(#ControlGap#)r
Y=(0)r
StringAlign=Center
FontColor=#ControlColor2#
Text=#Play#
LeftMouseUpAction=[!CommandMeasure Status "PlayPause"][!UpdateMeasureGroup PlayerGroup][!UpdateMeter *][!Redraw]

[Next]
Meter=String
MeterStyle=Texts
X=(#ControlGap#)r
Y=(0)r
StringAlign=Center
FontColor=#ControlColor3#
Text=#Next#
LeftMouseUpAction=[!CommandMeasure Status "Next"][!UpdateMeasureGroup PlayerGroup][!UpdateMeter *][!Redraw]

[LyricsBox]
Meter=Image
X=(#Margin#)
Y=(#Margin#/2)R
W=(#BackgroundW#-#Margin#*2)
H=(#BackgroundH#-[LyricsBox:Y]-#Margin#)
SolidColor=#BoxColor#
UpdateDivider=-1
DynamicVariables=1

[LyricsContainer]
Meter=Image
X=([LyricsBox:X])
Y=([LyricsBox:Y])
W=([LyricsBox:W])
H=([LyricsBox:H])
SolidColor=0,0,0,255
UpdateDivider=-1
MouseScrollUpAction=[!SetVariable Offset (Clamp(#Offset#-#LineH#,[LyricsContainer:H]*#LockPerc#*(1-#LockLine#),Clamp([LyricsText:H]-[LyricsContainer:H]*(1-#LockLine#),0,[LyricsText:H])+[LyricsContainer:H]*#LockPerc#*(1-#LockLine#)))][!UpdateMeter LyricsContainer][!UpdateMeter LyricsText][!Redraw]
MouseScrollDownAction=[!SetVariable Offset (Clamp(#Offset#+#LineH#,[LyricsContainer:H]*#LockPerc#*(1-#LockLine#),Clamp([LyricsText:H]-[LyricsContainer:H]*(1-#LockLine#),0,[LyricsText:H])+[LyricsContainer:H]*#LockPerc#*(1-#LockLine#)))][!UpdateMeter LyricsContainer][!UpdateMeter LyricsText][!Redraw]
DynamicVariables=1

[LyricsText]
Container=LyricsContainer
Meter=String
MeterStyle=Texts
StringAlign=Center
FontColor=#LyricsColor#
FontSize=(#FontSize#*#FontPerc#)
X=([LyricsBox:W]/2)
Y=(-Clamp(#Offset#-[LyricsContainer:H]*#LockPerc#,-[LyricsContainer:H]*#LockPerc#*#LockLine#,Clamp([LyricsText:H]-[LyricsContainer:H],0,[LyricsText:H])+[LyricsContainer:H]*(1-#LockPerc#)*#LockLine#))
W=([LyricsBox:W])
MeasureName=SyncedLyrics
Text=%1
DynamicVariables=1
The improved sample includes:
- the ability to work with either NowPlaying or WebNowPlaying, by changing the value of the Plugin variable in [Variables] accordingly
- the ability to loosely or strictly "lock" the vertical position of the current line in the lyrics box via the LockLine and LockPerc variables, see above
- the ability to detect changing the track for either plugin, as mentioned earlier in the thread, via the [Track] measure
- corrections to the way the current line is computed, see the slightly adjusted Substitute in the [Line] measure
- the ability to reset the highlighted / karaoke line to nothing when the track position is 0 (aka track is stopped), in the [Reset] measure
- the adjusted formulas for any variant of locking the current line vertical position, in the scroll actions of [LyricsContainer] and the Y of [LyricsText]

Feel free to add what you prefer in the code you posted above. You can use a LockLine of 0 for the loose lock or 1 for the strict lock, and a LockPerc of 0.43 as per your code. Alternatively, if you don't like adding the variables or the longer formulas and you only need one of the position locking variants, you can skip adding the variables and just replace #LockLine# and #LockPerc# with your chosen values in the formulas and, when possible, reduce the formulas if some terms cancel each other or themselves out.

What's probably left to do if desired is to allow horizontal scrolling too, in case the lyrics lines are too long to fit the container (considering that wrapping them has unwanted effects on computing the line height, aka #LineH#). I suppose that would work best on mouse hovering near the left and right sides of the container, since mouse scrolling on the container is already populated by the vertical scrolling. I'll let you do that if you want, since it's trivial to change the X of [LyricsText] from some MouseOverAction / MouseLeaveAction in [LyricsContainer] (the result should be clamped though, so that it doesn't go forever).
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
Rhyuno
Posts: 17
Joined: August 4th, 2024, 6:30 am

Re: [Friendly Resource] If PlayerType=Lyrics needs an update, LRCLIB can be used

Post by Rhyuno »

Yincognito wrote: August 12th, 2024, 8:08 pm Alright, after having slept on it I approached this a bit differently and managed to write the formulas in a way that allows for either of the "line always in the chosen vertical position" and "line in the chosen position only when not at the start or end of the lyrics" variants to be chosen, by simply changing the value of one of the two variables that I included in an improved version of the sample skin earlier (LockLine = 0 for the 2nd variant, 1 for the 1st variant; LockPerc = decimal percentage starting from the top of the lyrics container where the line should stay):

[...]

What's probably left to do if desired is to allow horizontal scrolling too, in case the lyrics lines are too long to fit the container (considering that wrapping them has unwanted effects on computing the line height, aka #LineH#). I suppose that would work best on mouse hovering near the left and right sides of the container, since mouse scrolling on the container is already populated by the vertical scrolling. I'll let you do that if you want, since it's trivial to change the X of [LyricsText] from some MouseOverAction / MouseLeaveAction in [LyricsContainer] (the result should be clamped though, so that it doesn't go forever).
This is the most amazing thing I've seen today. Thanks for this! :thumbup:

Regarding the lyrics lines being too long, I've actually been trying to figure out how to filter out the timestamps in the lyrics without messing up the sync and karaoke features. I don't mind writing the Lua for the timestamp filter if needed, but I have no idea which section variable to put it in. I also considered just using the lyrics without the timestamps from the LRCLIB API and connecting them with [LyricsText]. While it syncs, it messes up the karaoke function. :???:
User avatar
Yincognito
Rainmeter Sage
Posts: 8050
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Friendly Resource] If PlayerType=Lyrics needs an update, LRCLIB can be used

Post by Yincognito »

Rhyuno wrote: August 13th, 2024, 10:17 am This is the most amazing thing I've seen today. Thanks for this! :thumbup:

Regarding the lyrics lines being too long, I've actually been trying to figure out how to filter out the timestamps in the lyrics without messing up the sync and karaoke features. I don't mind writing the Lua for the timestamp filter if needed, but I have no idea which section variable to put it in. I also considered just using the lyrics without the timestamps from the LRCLIB API and connecting them with [LyricsText]. While it syncs, it messes up the karaoke function. :???:
Thanks, and you're welcome!

Not displaying the timestamps won't reduce wide lines by much, but has been on my mind as well - I left them because they are a valuable way to test if the sync, scrolling and highlighting works well, and if the response from the site suits the actual playing track in that regard.

That being said, it's actually easy to display a lyrics text without the timestamps, if you approach this in a "creative", "unorthodox" way. Just apply a general inline setting / pattern directly in [LyricsText], that colors the timestamps transparently, and shift the meter's X with half the width of a timestamp to the left. Then, the timestamps will still exist in the lyrics text and be displayed but you won't see them, while the lyrics text will be horizontally centered in the container as if it didn't have timestamps at all. A bit of a "hack", but it should work.

You might need to use InlineSetting / InlinePattern for the general inline settings above, and InlineSetting2 / InlinePattern2 for the karaoke highlighting, since the latter is non permanent (Rainmeter considers indexed options as invalid if there's a "break" / "gap" in indexing). Also, you should exclude timestamps from highlighting in the karaoke line(s) by enclosing the non timestamp part of the line(s) you highlight between round brackets in the IfMatchAction, so adjust things accordingly in the code.

Obviously, this is not the only way to do what you want, just the easiest one, involving minimal changes to the code.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
Rhyuno
Posts: 17
Joined: August 4th, 2024, 6:30 am

Re: [Friendly Resource] If PlayerType=Lyrics needs an update, LRCLIB can be used

Post by Rhyuno »

Thanks for the idea! I applied that same principle, but instead of using color with a value of 0,0,0,0 I went with size value that is close to 0 but not 0 so I went with 0.0001. So that my lyrics would look more centered than manually adjusting the x value.

Code: Select all

[SyncedLyrics]
IfMatchAction=[!SetOption LyricsText "InlineSetting" "Size | 0.0001"][!SetOption LyricsText "InlinePattern" "(?siU)\[\d{2}:\d{2}\.\d{2}\]"],[!SetOption LyricsText "InlineSetting2" "Color | #KaraokeColor#"][!SetOption LyricsText "InlinePattern2" "(?siU)\[\x005B][Position].+\R"]
Rhyuno
Posts: 17
Joined: August 4th, 2024, 6:30 am

Re: [Friendly Resource] If PlayerType=Lyrics needs an update, LRCLIB can be used

Post by Rhyuno »

Rhyuno wrote: August 13th, 2024, 1:45 pm

Code: Select all

[SyncedLyrics]
IfMatchAction=[!SetOption LyricsText "InlineSetting" "Size | 0.0001"][!SetOption LyricsText "InlinePattern" "(?siU)\[\d{2}:\d{2}\.\d{2}\]"],[!SetOption LyricsText "InlineSetting2" "Color | #KaraokeColor#"][!SetOption LyricsText "InlinePattern2" "(?siU)\[\x005B][Position].+\R"]
I redid and improved this code and added it to [LyricsText]:

Code: Select all

InlineSetting2=Size | 0.0001 | Color | 0,0,0,0
InlinePattern2=(?sU)\[\d{2}:\d{2}\.\d{2,3}\]
I haven't tested it yet, but I also added new lines to the code that identify connection errors and any web parsing errors:

Code: Select all

[ConnectionStatus]
Measure=Calc
Formula=([SyncedLyrics])=0
IfCondition=(ConnectionStatus=1)
IfTrueAction=[!SetOption LyricsText Text "There is a problem with your connection."][!UpdateMeter LyricsText][!Redraw]
DynamicVariables=1

[LyricsStatus]
Measure=String
String=[SyncedLyrics]
IfCondition=("[SyncedLyrics]" = "")
IfTrueAction=[!SetOption LyricsText Text "Lyrics not found."][!UpdateMeter LyricsText][!Redraw]
IfFalseAction=[!SetOption LyricsText Text "[SyncedLyrics]"][!UpdateMeter LyricsText][!Redraw]
DynamicVariables=1

[LoadingLyrics]
Measure=Calc
Formula=1
IfCondition=("[Track]" != "" && "[SyncedLyrics]" = "")
IfTrueAction=[!SetOption LyricsText Text "Searching..."][!UpdateMeter LyricsText][!Redraw]
DynamicVariables=1
I'm pretty sure you're aware of this bug—the one that appears whenever we skip to a certain point in a song. The position has to "hit" the timestamp before the karaoke and sync features start working. It's not highlighting or syncing the current line that's being played when we skip to a specific point in the song.
User avatar
Yincognito
Rainmeter Sage
Posts: 8050
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Friendly Resource] If PlayerType=Lyrics needs an update, LRCLIB can be used

Post by Yincognito »

Rhyuno wrote: August 14th, 2024, 8:39 am I redid and improved this code and added it to [LyricsText]:
[...]
I'm pretty sure you're aware of this bug—the one that appears whenever we skip to a certain point in a song. The position has to "hit" the timestamp before the karaoke and sync features start working. It's not highlighting or syncing the current line that's being played when we skip to a specific point in the song.
Yep, I'm well aware of it. Another form of this bug (I told you such bugs might exist, as the initial sample was only meant as a demo on how the sync and karaoke could be done) is the fact that when refreshing the skin while playing / paused with the current position not among the timestamps in the lyrics, the skin will "lose" the "last" karaoke and sync "position". I could !WriteKeyValue the value of variables in the skin, but I don't like that idea for several reasons and want to avoid it.

Currently, I've changed / renamed some parts in the code to be more self explanatory and make the karaoke thing not dependent on the lyrics being displayed, so in the code below, there's no need to to the tricks you did to hide / shrink the timestamps anymore...

Code: Select all

[Variables]
BackgroundW=400
BackgroundH=600
StrokeWidth=2
CornerRadius=10
Margin=10
BackgroundColor=0,0,0,128
StrokeColor=255,128,0,255
InfoColor0=255,128,128,255
InfoColor1=128,128,255,255
InfoColor2=128,255,128,255
InfoColor3=255,128,255,255
ControlColor0=255,255,128,255
ControlColor1=128,255,255,255
ControlColor2=128,255,255,255
ControlColor3=255,255,128,255
LyricsColor=192,192,192,255
HighlightColor=255,255,255,255
FontEffectColor=0,0,0,255
FontColor=255,255,255,255
FontFace=Monotype Corsiva
FontSize=16
StringEffect=Shadow
FontPerc=0.75
BarHPerc=0.80
BarSolid=128,128,128,255
BarColor=0,255,0,255
ControlNum=4
ControlGap=50
Prev=[\x23EE]
Stop=[\x23F9]
Play=[\x23F5]
Next=[\x23ED]
Pause=[\x23F8]
BoxColor=0,0,0,128
Plugin=NowPlaying
Player=Winamp
OffsetX=0
OffsetY=0
LockLine=0
LockPerc=0
LineTotal=0
LineStart=0
LineCount=0
LineHeight=0

[Rainmeter]
Update=1000
AccurateText=1
DynamicWindowSize=1

---Measures---

[Status]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=#Player#
PlayerType=Status
RegExpSubstitute=1
Substitute="^0$":"Closed","^1$":"Open"
DynamicVariables=1

[State]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=State
RegExpSubstitute=1
Substitute="^0$":"Stopped","^1$":"Playing","^2$":"Paused"
IfCondition=(State=1)
IfTrueAction=[!SetOption Play Text "#Pause#"]
IfFalseAction=[!SetOption Play Text "#Play#"]
DynamicVariables=1

[Artist]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=Artist
RegExpSubstitute=1
Substitute="^$":"No Artist"
DynamicVariables=1

[Album]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=Album
RegExpSubstitute=1
Substitute="^$":"No Album"
DynamicVariables=1

[Title]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=Title
RegExpSubstitute=1
Substitute="^$":"No Title"
DynamicVariables=1

[Duration]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=Duration
RegExpSubstitute=1
Substitute="(?<!\d)(\d)(?!\d)":"0\1"
DynamicVariables=1

[Position]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=Position
RegExpSubstitute=1
Substitute="(?<!\d)(\d)(?!\d)":"0\1"
OnChangeAction=[!UpdateMeasure Sync]
DynamicVariables=1

[Progress]
Group=PlayerGroup
Measure=Plugin
Plugin=#Plugin#
PlayerName=[Status]
PlayerType=Progress
DynamicVariables=1

[Track]
Group=PlayerGroup
Measure=String
String=[Artist] - [Album] - [Title] - [Duration:]
OnChangeAction=[!CommandMeasure LrcLib "Update"]
DynamicVariables=1

[LrcLib]
Measure=WebParser
URL=https://lrclib.net/api/get?artist_name=[&Artist]&album_name=[&Album]&track_name=[&Title]&duration=[&Duration:]
UserAgent=Rainmeter 4.5.18 (https://github.com/rainmeter)
RegExp=(?siU)[{,]"syncedLyrics":"(.*)"[,}]
StringIndex=1
UpdateRate=-1
RegExpSubstitute=1
Substitute='(?siU)\\"':'"',"(?siU)\\n":"#CRLF#"
FinishAction=[!UpdateMeasure Sync]
DynamicVariables=1

[Lyrics]
Measure=WebParser
URL=[LrcLib]
StringIndex=1
RegExpSubstitute=1
Substitute='(?siU)\\"':'"',"(?siU)\\n":"#CRLF#","(?siU)[[\d:.]+\]\h+?":""

[Sync]
Measure=String
String=[LrcLib]
UpdateDivider=-1
RegExpSubstitute=1
Substitute="(?siU)((?:\[[Position].*(?:\R|$))+?)":"[\x200B]\1[\x200B]","(?siU)[^[\x200B]]+(?:\R|$)":"+1","(?siU)^((.*)[\x200B](.*)[\x200B].*)$":"[!SetVariable LineTotal (0\1)][!SetVariable LineStart (0\2)][!SetVariable LineCount (0\3)]","^((?:\+1)*)$":"[!SetVariable LineTotal (0\1)]","(?:\\\d+|[\x200B])":""
OnUpdateAction=[!SetVariable LineStart ([Position:]=0?0:#LineStart#)][!SetVariable LineCount ([Position:]=0?0:#LineCount#)][Sync][!SetVariable LineHeight ([LyricsText:H]/([#LineTotal]=0?1:[#LineTotal]))][!SetVariable OffsetY ([#LineHeight]*[#LineStart])][!UpdateMeter *][!Redraw]
DynamicVariables=1

---Styles---

[Texts]
FontEffectColor=#FontEffectColor#
FontColor=#FontColor#
FontFace=#FontFace#
FontSize=#FontSize#
AntiAlias=1
StringEffect=#StringEffect#

---Meter---

[Background]
Meter=Shape
Shape=Rectangle (#StrokeWidth#/2),(#StrokeWidth#/2),(#BackgroundW#-#StrokeWidth#),(#BackgroundH#-#StrokeWidth#),(#CornerRadius#),(#CornerRadius#) | Fill Color #BackgroundColor# | Stroke Color #StrokeColor# | StrokeWidth #StrokeWidth#
UpdateDivider=-1

[Information]
Meter=String
MeterStyle=Texts
StringAlign=Center
X=(#BackgroundW#/2)
Y=(#Margin#)
W=(#BackgroundW#-#Margin#*2)
InlineSetting=Color | #InfoColor0#
InlinePattern=^(?:\N*\R){0}(\N*)
InlineSetting2=Color | #InfoColor1#
InlinePattern2=^(?:\N*\R){1}(\N*)
InlineSetting3=Color | #InfoColor2#
InlinePattern3=^(?:\N*\R){2}(\N*)
InlineSetting4=Color | #InfoColor3#
InlinePattern4=^(?:\N*\R){3}(\N*)
MeasureName=Artist
MeasureName2=Album
MeasureName3=Title
MeasureName4=Duration
MeasureName5=Position
MeasureName6=Progress
MeasureName7=Status
MeasureName8=State
Text=%1#CRLF#%2#CRLF#%3#CRLF#%5 of %4 (%6%) - Player is %7 & %8
DynamicVariables=1

[ProgressBar]
Meter=Bar
MeasureName=Progress
X=(#Margin#)
Y=(#Margin#/2)R
W=(#BackgroundW#-#Margin#*2)
H=(#FontSize#*#BarHPerc#)
BarColor=#BarColor#
SolidColor=#BarSolid#
BarOrientation=Horizontal
LeftMouseDownAction=[!CommandMeasure Progress "SetPosition $MouseX:%$"][!UpdateMeasureGroup PlayerGroup][!UpdateMeter *][!Redraw]
DynamicVariables=1

[Prev]
Meter=String
MeterStyle=Texts
X=(#BackgroundW#/2-#ControlGap#/2*(#ControlNum#-1))
Y=(#Margin#/2)R
StringAlign=Center
FontColor=#ControlColor0#
Text=#Prev#
LeftMouseUpAction=[!CommandMeasure Status "Previous"][!UpdateMeasureGroup PlayerGroup][!UpdateMeter *][!Redraw]

[Stop]
Meter=String
MeterStyle=Texts
X=(#ControlGap#)r
Y=(0)r
StringAlign=Center
FontColor=#ControlColor1#
Text=#Stop#
LeftMouseUpAction=[!CommandMeasure Status "Stop"][!UpdateMeasureGroup PlayerGroup][!UpdateMeter *][!Redraw]

[Play]
Meter=String
MeterStyle=Texts
X=(#ControlGap#)r
Y=(0)r
StringAlign=Center
FontColor=#ControlColor2#
Text=#Play#
LeftMouseUpAction=[!CommandMeasure Status "PlayPause"][!UpdateMeasureGroup PlayerGroup][!UpdateMeter *][!Redraw]

[Next]
Meter=String
MeterStyle=Texts
X=(#ControlGap#)r
Y=(0)r
StringAlign=Center
FontColor=#ControlColor3#
Text=#Next#
LeftMouseUpAction=[!CommandMeasure Status "Next"][!UpdateMeasureGroup PlayerGroup][!UpdateMeter *][!Redraw]

[LyricsBox]
Meter=Image
X=(#Margin#)
Y=(#Margin#/2)R
W=(#BackgroundW#-#Margin#*2)
H=(#BackgroundH#-[LyricsBox:Y]-#Margin#)
SolidColor=#BoxColor#
UpdateDivider=-1
DynamicVariables=1

[LyricsContainer]
Meter=Image
X=([LyricsBox:X])
Y=([LyricsBox:Y])
W=([LyricsBox:W])
H=([LyricsBox:H])
SolidColor=0,0,0,255
UpdateDivider=-1
MouseScrollUpAction=[!SetVariable OffsetY (Clamp(#OffsetY#-#LineHeight#,[LyricsContainer:H]*#LockPerc#*(1-#LockLine#),Clamp([LyricsText:H]-[LyricsContainer:H]*(1-#LockLine#),0,[LyricsText:H])+[LyricsContainer:H]*#LockPerc#*(1-#LockLine#)))][!UpdateMeter LyricsContainer][!UpdateMeter LyricsText][!Redraw]
MouseScrollDownAction=[!SetVariable OffsetY (Clamp(#OffsetY#+#LineHeight#,[LyricsContainer:H]*#LockPerc#*(1-#LockLine#),Clamp([LyricsText:H]-[LyricsContainer:H]*(1-#LockLine#),0,[LyricsText:H])+[LyricsContainer:H]*#LockPerc#*(1-#LockLine#)))][!UpdateMeter LyricsContainer][!UpdateMeter LyricsText][!Redraw]
DynamicVariables=1

[LyricsText]
Container=LyricsContainer
Meter=String
MeterStyle=Texts
StringAlign=Center
FontColor=#LyricsColor#
FontSize=(#FontSize#*#FontPerc#)
InlineSetting=Color | #HighlightColor#
InlinePattern=(?siU)^(?:.*(?:\R|$)){#LineStart#}((?:.*(?:\R|$)){#LineCount#}).*?$
TrailingSpaces=1
X=([LyricsContainer:W]/2)
Y=(-Clamp(#OffsetY#-[LyricsContainer:H]*#LockPerc#,-[LyricsContainer:H]*#LockPerc#*#LockLine#,Clamp([LyricsText:H]-[LyricsContainer:H],0,[LyricsText:H])+[LyricsContainer:H]*(1-#LockPerc#)*#LockLine#))
W=([LyricsContainer:W])
MeasureName=Lyrics
Text="%1"
DynamicVariables=1
Basically, now the inline settings are based on the value of the LineStart and LineCount variables (that are set in the sole [Sync] measure using my favorite trick of using a zero width space to indicate the boundaries of multiple parts in a single string), instead of looking for the timestamp in the lyrics string from the meter as before. The timestamp is still looked for in the lyrics string, but exclusively from the [Sync] measure, so you can have anything in the [Lyrics] measure as long as the total number of lines aka LineTotal coincides (like the lyrics after timestamps have been eliminated, as above).

Going forward, I'll be looking to always identify the greatest lyrics timestamp that's lower than the current position and set things up on that base, ideally in plain Rainmeter instead of Lua. That should in theory solve the "not hit" timestamp issue.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
Active Colors
Moderator
Posts: 1301
Joined: February 16th, 2012, 3:32 am
Location: Berlin, Germany

Re: [Friendly Resource] If PlayerType=Lyrics needs an update, LRCLIB can be used

Post by Active Colors »

Found two open-source stiped off minimal interfaces for Genius called "dumb" and "intelligent". Search and loading works without js. If no timed lyrics needed, these could be used.

dumb - https://github.com/rramiachraf/dumb
intellectual - https://github.com/Insprill/intellectual

The github pages list few publicly available instances. For example,
for dumb - https://dumb.ducks.party/
for intellectual - https://intellectual.catsarch.com/