Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.lrc lyrics? #371

Open
duckfromdiscord opened this issue Sep 12, 2023 · 25 comments
Open

.lrc lyrics? #371

duckfromdiscord opened this issue Sep 12, 2023 · 25 comments

Comments

@duckfromdiscord
Copy link

duckfromdiscord commented Sep 12, 2023

I've noticed the Subsonic protocol supports lyrics. I have a couple .lrc files lying around that I'd like to add to gonic to complete my music collection, especially with certain streaming services considering paywalling lyrics. My suggestion is to have the .lrc file have the same name as the audio file, minus its extension and plus .lrc. An example using the folder structure in the README:

music
├── drum and bass
│   └── Photek
│       └── (1997) Modus Operandi
│           ├── 01.10 The Hidden Camera.flac
│           ├── 01.10 The Hidden Camera.lrc
│           ├── 02.10 Smoke Rings.flac
│           ├── 02.10 Smoke Rings.lrc
│           ├── 03.10 Minotaur.flac
│           ├── 03.10 Minotaur.lrc
│           └── folder.jpg

The .lrc format is super easy to deal with, it's just plaintext with timestamps. There are some optional tags at the beginning of lyric files, check out the Wikipedia page for a good list.

[00:01.099]Hello world
@sentriz
Copy link
Owner

sentriz commented Sep 12, 2023

are there any subsonic clients that support lyrics?

@duckfromdiscord
Copy link
Author

are there any subsonic clients that support lyrics?

I use iSub and it has a lyrics window, that's how I found out about it.

I wish Subsonic had a time-synced lyrics thing as well so I could truly push those .lrc files to their limits, but that's a question for Subsonic, not this repo 😂

@dweymouth
Copy link

are there any subsonic clients that support lyrics?

I am planning on adding it to Supersonic in the near- to mid-future. Feishin (Sonixd's successor) supports lyrics but not the Subsonic API yet, I think it's waiting for OpenSubsonic

@Tolriq
Copy link

Tolriq commented Oct 10, 2023

Just seeing this, Symfonium support them too, We need to extend OpenSubsonic API to support songId to getLyrics to have this properly added to Subsonic. Will make the API request later.

@Tolriq
Copy link

Tolriq commented Oct 10, 2023

@duckfromdiscord
Copy link
Author

This OpenSubsonic thing is cool! I wonder if I could ask about timed lyrics there.

@Tolriq
Copy link

Tolriq commented Oct 10, 2023

The lyrics are returned as is, so if they have the offsets they will be synced on the clients if they support it.

@duckfromdiscord
Copy link
Author

Perhaps the timings like [00:00.00] should be removed by the server if the lyrics are being sent to a client that doesn't support them

@duckfromdiscord
Copy link
Author

I could go through each of my .lrc files with a regex that removes them, and output them as .txt files, seeing as my client obviously doesn't support the timings anyway.

@dweymouth
Copy link

OpenSubsonic RfC for lyrics API improvements is up opensubsonic/open-subsonic-api#60

@duckfromdiscord
Copy link
Author

This is amazing news!

@TorchedSammy
Copy link

I see the lyrics API has the label "In production" which means this can be worked on now?

@duckfromdiscord
Copy link
Author

duckfromdiscord commented Dec 20, 2023

Is there a .lrc parser for Go?

@duckfromdiscord
Copy link
Author

@bytebone
Copy link

while I'm in no way proficient with go, I might just know enough to attempt an implementation on this. Maybe someone more experienced can provide me with some rough pointers where one should start with this, what things to consider? Then I could try getting my hands dirty.

@duckfromdiscord
Copy link
Author

We're in the same boat. I have no experience with Go, I'm better with Rust. I do know that you should use a lrc parsing library like the one I posted. Wait for someone more experienced than me to provide some more pointers.

@bytebone
Copy link

bytebone commented Jan 26, 2024

While I assume that the main contributers would already be on top of the situation, let me just quickly sum up some relevant links for this lyrics spec for the curious:

gonic already implements the getLyrics endpoint, which should be able to share unsynced lyrics. But looking at the code, I don't think it does anything.

Just looking at the simple ServeGetSong function provides lots of info how the requests are handled and transformed into responses. You could probably also draw inspiration from the function that serves the cover art regarding file system interaction.

Most importantly, Navidrome seems to already have lyrics support and is also written in go: https://github.com/navidrome/navidrome/blob/master/model/lyrics.go. They don't use any parsing libraries, rather opting for simple regex (which imho is completely sufficient). This may be rather straightforward to apply to gonic.

@sentriz
Copy link
Owner

sentriz commented Jan 26, 2024

would we also support lyrics in audio metadata? and what would the priority be over .lrc files? also, is there any software such as beets or picard that can find and embed/store lyrics?

@bytebone
Copy link

bytebone commented Jan 26, 2024

If its possible to implement reading from the tag with audiotags, I see no harm in supporting both sources. The OSS spec supports multiple lyrics per individual song, so no problem there.

Edit: TagLib appears to support both SynchronizedLyricsFrame and UnsynchronizedLyricsFrame. I assume that this therefor also applies to audiotags.

Prioritization seems more like a client issue to me; if a client supports the getLyricsBySongId endpoint it should by default handle multiple lyric lists. Where the question is more relevant is the Subsonic getLyrics endpoint, which only supports one unsynced lyrics string. In that case, priority should (imo) be granted to a .lrc file, since that would be placed there with more intent than lyrics from a tag.

For lyric clients, I found this from a quick search: https://lrclib.net/. Note the API and the available client. Or if you want something in go, maybe this is to your liking: https://github.com/fashni/MxLRC-Go.

On another note, does the server need to broadcast the fact that a song has lyrics? I checked my gonic HTTP logs when playing music with Synfonium, and it does not by default query any lyrics endpoints. I see that navidrome has lyrics as part of their song object, but cannot figure out if they broadcast it to clients automatically. And the OSS spec doesn't specify the contents of songs at all.

@duckfromdiscord
Copy link
Author

So I take it we will have to fix the existing stubbed getLyrics and also add the getLyrics2 from the RFC?

@bytebone
Copy link

bytebone commented Jan 27, 2024

So I take it we will have to fix the existing stubbed getLyrics and also add the getLyrics2 from the RFC?

/getLyrics2 is not an endpoint that was implemented. The discussion you linked resulted in the getLyricsBySongId endpoint, which is exclusive to OSS and able to provide multiple (un)synced lyrics per track. That's what would need to be implemented, in addition to "fixing" the /getLyrics stub to actually function and offer one of the available lyrics (for compat with the subsonic spec)

@dweymouth
Copy link

FYI lyrics support is being built in Supersonic now and will be in the next release - so it would be a good time for someone to pick up this ticket and do a PR :)

@TorchedSammy
Copy link

I've decided to work on both lyric endpoints, currently only fetching from the .lrc files. Does anyone know of any clients that support the new endpoint for synced lyrics? Tempo on android has it on a WIP branch I presume, otherwise it's a debug build.

FYI lyrics support is being built in Supersonic now and will be in the next release - so it would be a good time for someone to pick up this ticket and do a PR :)

I tried it out, make sure to also support the synced lyrics.

@Tolriq
Copy link

Tolriq commented Mar 24, 2024

Symfonium fully support it.

@xxxserxxx
Copy link
Contributor

I've been contributing to Spezifisch's hard fork of stmp (called stmps), and synced lyrics is something I'd like to add support for.

I've also submitted PRs to gonic, and one thing I've learned is that the core team needs to be on-board with the implementation approach, or else there's a bunch of back-and-forth and code rewrites. Can we get a ruling here about what the core developers would like to see in an implementation? For example, whether or not there are database changes for on-disk assets causes a lot of churn, and .lrc files would fall into this category. @TorchedSammy , if you're working on a gonic patch, I'd rather leave that to you and focus on the client side.

@TorchedSammy -- there's a chicken/egg issue here. I haven't added lyrics support to stmps yet because neither of the servers I use (gonic, mainly, but I also test stmps changes against Navidrome) support synced lyrics. Would you like to coordinate on development of this? What I'd need is an endpoint that returns (one or more) synced lyrics from an .lrc file. The consensus appears to be that the LYRICS tag is only for storing unsynced lyrics, and at least Navidrome strips syncing data out of results returned by the getLyrics endpoint.

So, for your implementation:

  1. which endpoint will return synced lyrics?
  2. what's the schema that will be returned?
  3. how are synced lyrics stored?
  4. which branch holds your changes?

If I can get these answers, I'll do my stmps work based on your branch and send you information so you can see it work in a client.

I do recommend getting sign-off on your design from the gonic team first; of course I'm mainly concerned about API changes, but I'd also feel better if I knew there's a good chance of the patch being merged into mainline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants