Thanks, Active Colors, these should increase the number of available options for lyrics!Active Colors wrote: ↑August 14th, 2024, 4:24 pm 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.
It is currently September 9th, 2024, 11:49 am
[Friendly Resource] If PlayerType=Lyrics needs an update, LRCLIB can be used
-
- 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
-
- 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
And...done, all in a single measure using the full power of regexing the timestamped lines to bangs and a bit of nested syntax and escaping for variables! I still have to tweak one or two things mainly related to visuals (make the two redraws on skin refresh a single one, implement horizontal scrolling for long lines), but otherwise the code is complete:Yincognito wrote: ↑August 14th, 2024, 9:44 amGoing 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.
Code: Select all
[Variables]
FormatLyrics0='(?siU)\\"':'"',"(?siU)\\n":"#CRLF#"
FormatLyrics1='(?siU)\\"':'"',"(?siU)\\n":"#CRLF#","(?siU)[[\d:.]+\]\h+?":""
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
TrimStamp=0
LastStamp=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="[#FormatLyrics0]"
FinishAction=[!UpdateMeasure Sync]
DynamicVariables=1
[Lyrics]
Measure=WebParser
URL=[LrcLib]
StringIndex=1
RegExpSubstitute=1
Substitute="[#FormatLyrics[#TrimStamp]]"
DynamicVariables=1
[Sync]
Measure=String
String=[LrcLib]
UpdateDivider=-1
RegExpSubstitute=1
Substitute="\[[\d\:]*(\d+)\:(\d+)\.\d+\][^\[]*":"[!SetVariable LineTotal ([#*LineTotal*]+1)][!SetVariable LineStart ([Position:]<\1*60+\2?[#*LineStart*]:([#*LastStamp*]=\1*60+\2?[#*LineStart*]:[#*LineStart*]+[#*LineCount*]))][!SetVariable LineCount ([Position:]<\1*60+\2?[#*LineCount*]:([#*LastStamp*]=\1*60+\2?[#*LineCount*]+1:1))][!SetVariable LastStamp (\1*60+\2)]","^(.*)$":"[!SetVariable LastStamp -1][!SetVariable LineTotal 0][!SetVariable LineStart -1][!SetVariable LineCount 1]\1","\\\d+":""
OnUpdateAction=[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
-
- Posts: 17
- Joined: August 4th, 2024, 6:30 am
Re: [Friendly Resource] If PlayerType=Lyrics needs an update, LRCLIB can be used
Thanks a lot! By the way, just a question—what does each of these lines do?Yincognito wrote: ↑August 14th, 2024, 5:34 pm And...done, all in a single measure using the full power of regexing the timestamped lines to bangs and a bit of nested syntax and escaping for variables! I still have to tweak one or two things mainly related to visuals (make the two redraws on skin refresh a single one, implement horizontal scrolling for long lines), but otherwise the code is complete:
[...]
Displaying timestamps is controlled via the TrimStamp variable (0 to show them, 1 to hide them). Any other potential additions or corrections will be done through edits on this post.
Code: Select all
OffsetX=0
OffsetY=0
LastStamp=0
LineTotal=0
LineStart=0
LineCount=0
LineHeight=0
-
- 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
No problem, you're welcome - I liked the synced lyrics idea in the first place, and that helped with my motivation, because otherwise, apart from the advice on the forum, we generally let the user implement and design their own skins.Rhyuno wrote: ↑August 15th, 2024, 9:54 am Thanks a lot! By the way, just a question—what does each of these lines do?Also, just a suggestion to improve the experience of using the skin—I think it would be cool if we could add a feature where you could click on a line of the lyrics, and the song would skip to the time when that lyric is played. But overall, this skin is almost done. At this point, only small tweaks will be made when bugs are encountered.Code: Select all
OffsetX=0 OffsetY=0 LastStamp=0 LineTotal=0 LineStart=0 LineCount=0 LineHeight=0
Ask as many questions as you like, because it will be key to understand how the skin works if you think about adding or adjusting things to your preference going forward. The lines you mentioned are in the [Variables] section, which is used to declare and define the initial values of various variables used by the skin. The posted variables are about:
- OffsetX = the horizontal scrolling offset in pixels of [LyricsText] in [LyricsContainer], for use on longer lines in the future
- OffsetY (previously named Offset) = the vertical offset in pixels of the first karaoke line within [LyricsText], which is used to compute the vertical scrolling and Y of the [LyricsText] within [LyricsContainer]
- LastStamp = the timestamp in seconds of the previous line while performing the Substitute in [Sync], used to compare it with the timestamp of the current line (aka \1*60+\2) in it, in order to identify where the incrementing of LineStart stops and whether the incrementing of LineCount should happen (see below)
- LineTotal (previously named Lines) = the total number of lines in the lyrics string, incremented to compute it, in the Substitute from [Sync]
- LineStart (previously named Line) = the first karaoke line, incremented (from -1, since its minum valid value is 0) to compute it, in the Substitute from [Sync]
- LineCount = the number of karaoke lines, incremented to compute it, in the Substitute from [Sync], but only as long as the timestamp of the previous line in the Substitute equals the timestamp of the current line in it, as mentioned above
- LineHeight (previously named LineH) = the height of a lyrics line in [LyricsText], computed in the OnUpdateAction of [Sync] as the division of the [LyricsText:H] height of that meter and the LineTotal number of lines in the lyrics
In simple terms, what the Substitute in [Sync] does every time [Position], [Track] or [LrcLib] change is to replace a copy of the lyrics string with the !SetVariable bangs needed to reset and increment to compute the LineTotal, LineStart and LineCount variables (each line in the string becomes 4 such bangs, along with the one for LastStamp). Then in [Sync]'s OnUpdateAction, the measure executes its own value (i.e. the bangs from its replaced string), computes LineHeight and OffsetY based on the newly set values of the said variables, updates all meters and redraws the skin, to reflect the changes. This is what produces the sync jump since that OffsetY is used to position [LyricsText] within [LyricsContainer], and the karaoke effect since the inline settings of [LyricsText] are based on the values of LineStart and LineCount to pick LineCount lines starting with LineStart and color them differently than the regular lyrics text. The principle is somewhat similar to how I used the +1...+1 strings in Calc measures to compute such values, except that now I use bangs to do it, which you can see in the About > Skins tab aka the log, if you right click the value of [Sync] and copy paste it in a text file for examination. Helpful references:
https://docs.rainmeter.net/manual/bangs/#SetVariable
https://docs.rainmeter.net/manual/formulas/#Conditional
https://docs.rainmeter.net/manual/user-interface/about/#SkinsTab
The proposed feature is something I thought about as well, as it's basically the reverse of what happens now. I'll think about it, but I offer no guarantees that I'll implement it. If you're impatient though, and considering that you'll be the one to benefit from it in your skin, you could try to do it yourself, as it's basically about doing the below in a LeftMouseUpAction of [LyricsText]:
- use the mouse variables to get where the mouse was in relation to the meter when clicking on it:
https://docs.rainmeter.net/manual/variables/mouse-variables/
- set the OffsetY variable to the mouse Y above
- determine LineStart based on OffsetY, LineHeight and the simple OffsetY formula in [Sync] (I don't see a way to determine LineCount unless additional steps are made to search the actual line in the lyrics string, so for this simpler approach it would have to always be 1)
- extract the LineStart line's timestamp via a Substitute partly similar to the one in the inline settings from [LyricsText], in a String measure containing a copy of the lyrics string, that you update from the left mouse up action
- set the position in the track using !CommandMeasure as usual, with the value being the percent of the above timestamp in the duration of the track
- update meters and redraw the skin to reflect the sync and the karaoke effects based on the already determined OffsetY, LineStart and LineCount
That's about it. Let me know if something is still not clear yet.