Yincognito wrote: ↑August 4th, 2024, 7:53 pm
I may take a deeper look at this [...] and maybe come up with a rudimentar sample code
Rhyuno wrote: ↑August 7th, 2024, 4:18 pm
Yes, I'm still very interested in this. [...] I really appreciate all the help I'm receiving on this one.
Alright, as promised, here's the - not yet fully polished - sample that demonstrates displaying the synced lyrics, the automatic (when playing) and manual (when stopped or paused) scrolling, as well as the karaoke highlighting of the currently played lyrics line:
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
Player=Winamp
Offset=0
LineH=0
Lines=0
Line=0
[Rainmeter]
Update=1000
AccurateText=1
DynamicWindowSize=1
---Measures---
[Status]
Group=PlayerGroup
Measure=NowPlaying
PlayerName=#Player#
PlayerType=Status
RegExpSubstitute=1
Substitute="^0$":"Closed","^1$":"Open"
TrackChangeAction=[!SetVariable Offset 0][!CommandMeasure SyncedLyrics "Update"]
[State]
Group=PlayerGroup
Measure=NowPlaying
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#"]
[Artist]
Group=PlayerGroup
Measure=NowPlaying
PlayerName=[Status]
PlayerType=Artist
RegExpSubstitute=1
Substitute="^$":"No Artist"
[Album]
Group=PlayerGroup
Measure=NowPlaying
PlayerName=[Status]
PlayerType=Album
RegExpSubstitute=1
Substitute="^$":"No Album"
[Title]
Group=PlayerGroup
Measure=NowPlaying
PlayerName=[Status]
PlayerType=Title
RegExpSubstitute=1
Substitute="^$":"No Title"
[Duration]
Group=PlayerGroup
Measure=NowPlaying
PlayerName=[Status]
PlayerType=Duration
[Position]
Group=PlayerGroup
Measure=NowPlaying
PlayerName=[Status]
PlayerType=Position
OnChangeAction=[!UpdateMeasureGroup LinesGroup]
[Progress]
Group=PlayerGroup
Measure=NowPlaying
PlayerName=[Status]
PlayerType=Progress
[SyncedLyrics]
Measure=WebParser
;URL=file://#@#Madonna - Material Girl (original).json
;URL=file://#@#Eminem - My Name Is (original).json
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
;Debug=2
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]
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#,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#,0,Clamp([LyricsText:H]-[LyricsContainer:H],0,[LyricsText:H])))
W=([LyricsBox:W])
MeasureName=SyncedLyrics
Text=%1
DynamicVariables=1
Desktop_2024_08_08_20_32_42_103-ezgif.com-optimize.gif
It almost certainly has a few "bugs" or things I didn't bother to make perfect, but it's enough to get the general idea. It uses
NowPlaying (not
WebNowPlaying!) as the plugin and Winamp (not Spotify!) as the player, since that's what I use and could test, so it's entirely up to you - or anyone interested - to adapt it to another plugin or less supported player. In some areas, this might be a little challenge, for example replicating the
TrackChangeAction option in NowPlaying, which WebNowPlaying doesn't yet have (here, concatenating the artist, track and duration in a String measure and comparing the outcome with the previous outcome of the same measure that was stored in a variable during the previous update of the measure could be one way to do it, besides using an OnChangeAction on that measure).
Regarding the commented lines from the code:
- I used the
Debug=2 option in the
[SyncedLyrics] measure to save the site's response on two test tracks, renamed and moved the file(s) accordingly, and parsed them as local files in the
URL option in order to avoid excessively polling the site during the building and testing phase of the skin (this is wise to do both as a general rule when working with WebParser and also whenever working with sites that might block or ban you for using them too frequently)
- the IfNotMatchAction is left in case you want to do something else when the currently played line is not found in the lyrics text, since in this implementation both the scrolling (the
((?:.+(?:\R|$)){#Line#}).* part in the
branch reset from
[Line]) and the highlighting (the
IfMatchAction) intentionally stay on the last
#Line# value until another
[Position] value is found in the lyrics string; this is done because otherwise (like the highlighting variant from the code
here) the highlight will only stay on the currently played line for the duration of one
[Position] update, i.e. just one second, which might not be enough time if the lyrics line is or lasts longer (it sometimes is inconvenient though, like when stopping the current track)
Obviously, you don't have to use this sample going forward, you could just add the needed things from it to the Mjdelro skin you're using. I do recommend testing stuff in this sample first though, simply because it's easier and it already works. Yes, you can use measures (like the
[MeasureCountTotalLines],
[MeasureCountCurrentLine] or
[MeasureLineHeight] in the code from your previous reply) instead of variables (like the
#Lines#,
#Line# or
#LineH# in the code from this sample) to store the said numerical values, I only used the latter cause it's more compact and takes less space in the code (I like one measure solutions).
Feel free to ask if you don't understand something - although judging by the quite correct way you already started to implement stuff in the past replies, I'm pretty sure you won't have many problems (besides occasional obstacles due to less Rainmeter experience) getting the principles in this code.
P.S. In case it's not obvious, the above system of scrolling (the karaoke highlighting is not affected) will not work properly if you set the lyrics text to potentially wrap longer lines, because in that case, the height of a "line" will vary depending on whether it's wrapped or not, while its computation assumes that line height value is always constant and equal to the height of an unwrapped line. There are probably solutions that would allow wrapping too, but in the interest of simplicity I didn't cover that above. One way to not need wrapping would be to allow horizontal scrolling too, along with the already existing vertical one.
You do not have the required permissions to view the files attached to this post.