It is currently September 9th, 2024, 11:02 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 10th, 2024, 3:07 pmThat's exactly right. I'm not entirely sure which part is causing it, but based on my research, Spotify only provides time in the mm:ss format. Because of this, I had to create a custom timer in the mm:ss.xx format that syncs with Spotify's mm:ss format to approximately sync the lyrics. I think this could be a pretty universal solution across any music player.
I see. Well, the granularity of most music players (not just Spotify) is to the second instead of millisecond. Now sure why you'd need the ms anyway, unless you really want to display a single lyrics line based on that granularity, instead of all the lines belonging to the current second in the track like demonstrated in the sample. In any case, you know better than me what you want to do in the skin you're using, so it's entirely your choice.
Rhyuno wrote: August 10th, 2024, 3:07 pmAs of now, I'm still working on finding a substitute method for TrackChangeAction. I'm also having problems whenever I skip in the music, as the timer I've created so far doesn't support such action.
Have you tried concatenating the artist, album, title and duration in a String measure and using its OnChangeAction, like I mentioned earlier? As for the timer, if you're actually timing the interval since hitting play in the timer and you're referring to setting a different position when talking about skipping in the music, I think it's just a matter of resetting the timer to 0 and adding the position communicated by the (Web)NowPlaying plugin to that - of course, that would require you using some variable for the desired "timer" value, instead of the timer value itself. That being said, if Spotify / WebNowPlaying does indeed provide inaccurate time positions as you mentioned, then even doing so would be tricky since it would be just a gross estimation... :???:
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 »

I'm planning on storing the previous URL in a separate .ini file in the @Resources folder and comparing it with the currently playing song's URL. Is there something wrong with these?

Code: Select all

[Variables]
TrackChanged=0

[WriteCurrentTrack]
Measure=Calc
Formula=1
OnUpdateAction=[!WriteKeyValue "Track" "URL" "[URL]" "#@#PreviousTrack.ini"]
DynamicVariables=1

[PreviousTrack]
Measure=ReadIni
FileName=#@#PreviousTrack.ini
Section=Track
Key=URL
IfCondition=([URL] <> [PreviousTrack])
IfTrueAction=[!SetVariable TrackChanged 1][!WriteKeyValue "Track" "URL" "[URL]" "#@#PreviousTrack.ini"][!CommandMeasure FormattedPosition "Reset"]
DynamicVariables=1

[FormattedPosition]
Measure=Script
ScriptFile=#@#PositionFormatter.lua
UpdateDivider=1
DynamicVariables=1
IfCondition=(#TrackChanged#=1)
IfTrueAction=[!CommandMeasure "FormattedPosition" "Stop"][!CommandMeasure "FormattedPosition" "Start 0 0"]

[URL]
Meter=String
URL=https://lrclib.net/api/get?artist_name=[&Artist]&album_name=[&Album]&track_name=[&Title]&duration=[&Duration:]
DynamicVariables=1
Here's what it's returning in #@#PreviousTrack.ini:

Code: Select all

[Track]
URL=[URL]
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 10th, 2024, 3:57 pm Have you tried concatenating the artist, album, title and duration in a String measure and using its OnChangeAction, like I mentioned earlier? As for the timer, if you're actually timing the interval since hitting play in the timer and you're referring to setting a different position when talking about skipping in the music, I think it's just a matter of resetting the timer to 0 and adding the position communicated by the (Web)NowPlaying plugin to that - of course, that would require you using some variable for the desired "timer" value, instead of the timer value itself. That being said, if Spotify / WebNowPlaying does indeed provide inaccurate time positions as you mentioned, then even doing so would be tricky since it would be just a gross estimation... :???:
I actually tried concatenating it and using Lua to process it, but I got lost along the way. Now, I'm trying to replicate Simple Lyrics Display by storing the URL in a separate .ini file and comparing them.

As for the timer, that's actually a good suggestion. And yes, I think this entire skin will be a rough path, as it's based on gross estimation.
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 10th, 2024, 4:00 pmIs there something wrong with these?
Yes, there are several things wrong there:
- the order of sections (measures and meters) matter in a skin, so the 1st time when you write "[URL]" from the [WriteCurrentTrack] measure, [URL] doesn't yet have a value since the [URL] measure is after [WriteCurrentTrack] in the code
- in the [PreviousTrack] measure, Measure=ReadIni is invalid, since there's no "ReadIni" type of measure in Rainmeter; if I understand your intention correctly, what you're lokking for is the @include option (see the guide too, for a better understanding):
https://docs.rainmeter.net/manual/skins/include-option/
- in the [URL] measure, the URL option is invalid, since a String measure only has the String option:
https://docs.rainmeter.net/manual/measures/string/

So, if you really really want to physically write stuff on the disk (a slow operation, but useful when you need to store values between the loading sessions of a skin), instead of storing things as variables (a fast operation in memory, though values are lost when the skin is unloaded or refreshed), using @include and an .inc file where you define / write the URL variable in [Variables] would be more suited.

On the other hand, if you're ok with such a value being lost on unloading or refreshing the skin and want speed instead, you could just do it like:

Code: Select all

[URL]
Measure=String
String=...your URL or even just the concatenated [Artist] - [Album] - [Title] - [Duration:] here...
OnChangeAction=...do stuff when it changes...
DynamicVariables=1
Obviously, like alluded above, make sure your artist, album, title and duration measures are before this measure in the code, so that the latter doesn't have to wait for the next update to retrieve the former (essentially being one update behind with these values).
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 10th, 2024, 4:24 pmNow, I'm trying to replicate Simple Lyrics Display by storing the URL in a separate .ini file and comparing them.
One thing I forgot to mention when it comes to storing stuff physically on the "disk" (either in the same .ini or in a different .inc/.ini file) is that the main skin would have to be refreshed via the !Refresh bang if you want to "reload" / "reread" that URL value. Assuming, of course, that you don't also store the URL as a variable in memory, in which case there would be no need for such a refresh.
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 10th, 2024, 4:45 pm

Code: Select all

[URL]
Measure=String
String=...your URL or even just the concatenated [Artist] - [Album] - [Title] - [Duration:] here...
OnChangeAction=...do stuff when it changes...
DynamicVariables=1
Thanks for this. I'm now using it as a substitute for TrackChangeAction, as I don't necessarily need to write down the links.

I abandoned the "timer" idea because I noticed that Rainmeter sometimes can't process every millisecond accurately. Instead, I went with a more straightforward and less accurate method: rounding up or down the .xx in the timestamps provided by LRCLIB to match Spotify's [mm:ss] time format. I haven't tried it yet, and I'm not sure if it's possible using just Rainmeter, as I'm unsure what to put in RegExp / Substitute to make it work. :???:
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, 7:16 am Thanks for this. I'm now using it as a substitute for TrackChangeAction, as I don't necessarily need to write down the links.

I abandoned the "timer" idea because I noticed that Rainmeter sometimes can't process every millisecond accurately. Instead, I went with a more straightforward and less accurate method: rounding up or down the .xx in the timestamps provided by LRCLIB to match Spotify's [mm:ss] time format. I haven't tried it yet, and I'm not sure if it's possible using just Rainmeter, as I'm unsure what to put in RegExp / Substitute to make it work. :???:
You're welcome, glad it worked. As for rounding the time, I think you're overcomplicating this. Why don't you simply skip using the ms part in your regex (for both highlighting and scrolling), like I did in the sample I posted? I mean, sure, doing that would be equivalent to always rounding down to the integer part of the seconds, but this should be fine since it normally means that matching would happen faster and not slower.

Also, you keep mentioning the Spotify time format, but this mm:ss format is the same for every player not just Spotify, and is provided by the WebNowPlaying plugin in the skin, which acts as an intermediary between the player and the skin:
https://wnp.keifufu.dev/rainmeter/usage

Besides what's already in my sample, I won't be able to advice on what to use in your options if I don't see the code you have. And even then, I won't be able to actually test it on Spotify, since I don't use it. I can only test on stuff like YouTube and such. :confused:

P.S. You could even attach a screenshot of what you get, if by any chance it helps in illustrating the problem you have.
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, 9:41 am As for rounding the time, I think you're overcomplicating this. Why don't you simply skip using the ms part in your regex (for both highlighting and scrolling), like I did in the sample I posted? I mean, sure, doing that would be equivalent to always rounding down to the integer part of the seconds, but this should be fine since it normally means that matching would happen faster and not slower.
I'm actually redoing the entire setup, so I just restarted with the rudimentary code you sent. I think you made a really good point—even as a user, I would prefer seeing the lyrics first before listening to them. So, as per your suggestion, I skipped the milliseconds part (though I'm not sure if this is correct, as the highlighting and scrolling aren't working, so maybe not). :confused:

Code: Select all

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

[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)\[\d{2}:\d{2}\].+\R
IfMatchAction=[!SetOption LyricsText "InlineSetting" "Color | #KaraokeColor#"][!SetOption LyricsText "InlinePattern" "(?siU)\[\d{2}:\d{2}\].+\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)^(?|(.*)\[\d{2}:\d{2}\].+(?:\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
I added a substitute in [Position] since it was only showing a single digit in the minutes (e.g., "1:25" instead of "01:25"). I thought that might be the reason it wasn't matching with the timestamp in the lyrics.
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, 10:54 am I'm actually redoing the entire setup, so I just restarted with the rudimentary code you sent. I think you made a really good point—even as a user, I would prefer seeing the lyrics first before listening to them. So, as per your suggestion, I skipped the milliseconds part (though I'm not sure if this is correct, as the highlighting and scrolling aren't working, so maybe not). :confused:

Code: Select all

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

[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)\[\d{2}:\d{2}\].+\R
IfMatchAction=[!SetOption LyricsText "InlineSetting" "Color | #KaraokeColor#"][!SetOption LyricsText "InlinePattern" "(?siU)\[\d{2}:\d{2}\].+\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)^(?|(.*)\[\d{2}:\d{2}\].+(?:\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
I added a substitute in [Position] since it was only showing a single digit in the minutes (e.g., "1:25" instead of "01:25"). I thought that might be the reason it wasn't matching with the timestamp in the lyrics.
You did well with the Substitute in [Position], but why are you using \[\d{2}:\d{2}\] instead of \[\x005B][Position] (or something similar) in your code? That would match ANY timestamp instead of the CURRENT timestamp indicated by the (string) value of the [Position] measure...
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, 11:33 am You did well with the Substitute in [Position], but why are you using \[\d{2}:\d{2}\] instead of \[\x005B][Position] (or something similar) in your code? That would match ANY timestamp instead of the CURRENT timestamp indicated by the (string) value of the [Position] measure...
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
You do not have the required permissions to view the files attached to this post.