# Embedded lyrics and which tags to use?

**URL:** https://community.mp3tag.de/t/embedded-lyrics-and-which-tags-to-use/64698
**Category:** General Discussion
**Created:** [May 17, 2024, 8:35pm UTC](https://community.mp3tag.de/t/embedded-lyrics-and-which-tags-to-use/64698 "2024-05-17T20:35:06Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![Casual\_Tea](https://community.mp3tag.de/user_avatar/community.mp3tag.de/casual_tea/32/18886_2.png) [@Casual\_Tea](https://community.mp3tag.de/u/Casual_Tea)
#### Post date: [May 17, 2024, 8:35pm UTC](https://community.mp3tag.de/t/embedded-lyrics-and-which-tags-to-use/64698/1 "2024-05-17T20:35:06Z")

</div>

Over the last couple of weeks I've refined a python script I have used in the past to find all .lrc files in my collection that don't have a corresponding song with the same name (which, prior to [mp3tag renaming .lrc files with the songs](https://community.mp3tag.de/t/lrc-dateien-zusammen-mit-songs-umbenennen-verschieben/59189), happened quite a few times).

In its current state my script recursively scans a given directory for .lrc and .txt files, tries to find matching songs (it searches .flac and .mp3 per default but a list of extensions can be supplied as an argument), logs the paths of .lrc and .txt files that do not have matching songs and it can open the songs that do have matching .lrc or .txt files in mp3tag via the mp3tag cli.

It also optionally creates actions for mp3tag to backup existing embedded lrics, import them (inspired by [this post](https://community.mp3tag.de/t/embed-lrc-in-flac/53579/2)) and delete previously created backups of existing embedded lyrics.

## 

**Now to my question:**  
If you embed lyrics in your songs, which tags do you use and which software supports them?  
Both for synced and unsynced lyrics and also which tag for which file format?  
I know of SYLT and USLT frames for mp3 and LYRICS and UNSYNCEDLYRICS vorbis tags for flac.

## 

Upon testing I learned that mp3tag for example does not support the SYLT frame used in mp3 files.  
[This](https://community.mp3tag.de/t/synchronized-lyrics-sylt-support/45696/7) is the latest post I found concerning SYLT tags, which states that support is not planned.  
However what I have not found yet is a reason for that decision.

Has the SYLT tag limitations I'm not aware of and should be avoided?

I could use the cli of [kid3](https://kid3.kde.org/) instead of mp3tag to embed lyrics in my script as that supports the SYLT frame but I'd prefer not to.  
Being able to review all files that will be affected by an import prior to importing is a neat feature of my current solution with mp3tag.

Here's a quick [example usage](https://i.ibb.co/m6x7NKK/lyricstest.gif) of the current version of the script to get an idea of what I aim for. I deleted the existing mp3tag actions prior to running it to show how they are created, if they already exist, creation is skipped.  
As it's a fullscreen capture, if you want to see it sharp, download the gif or display it fullscreen if you have a 1080p monitor or bigger.

The script can also import .txt files, export LYRICS to .lrc and UNSYNCEDLYRICS to .txt (via ffprobe), standardize synced lyrics timestamp formatting, log results to disk etc. but I wanted to get the tag question out of the way before writing documentation and putting it on github so others can use it too.

---

<div class="post-metadata">

### Author: ![LyricsLover](https://community.mp3tag.de/letter_avatar_proxy/v4/letter/l/c6cbf5/32.png) [@LyricsLover](https://community.mp3tag.de/u/LyricsLover)
#### Post date: [May 17, 2024, 10:16pm UTC](https://community.mp3tag.de/t/embedded-lyrics-and-which-tags-to-use/64698/2 "2024-05-17T22:16:39Z")

</div>

> [@Casual\_Tea](#):
>
> If you embed lyrics in your songs, which tags do you use and which software supports them?

I use UNSYNCEDLYRICS only.  
The reason is easy: There are more online sources for this format (song text without timestamps).

The other reason: I never use Karaoke.  
Synchronized Lyrics are cool if you want to sing (& dance 😉) to a music track or -video and see the lyrics matching the song.

* * *

Technical answer:

According the [specification](https://id3.org/d3v2.3.0) for ID3 the tags are USLT  
for unsynchronised lyrics - Mp3tag is using [UNSYNCEDLYRICS](https://docs.mp3tag.de/mapping/#unsyncedlyrics)

 ![image](https://community.mp3tag.de/uploads/default/original/3X/a/b/ab08d97a5ea30884dfa2363585b5643cc5c63764.png)

and SYLT  
for the synchronised lyrics - Mp3tag does currently NOT support SYLT

 ![image](https://community.mp3tag.de/uploads/default/original/3X/b/a/bab462a315261ebc037e3c2a97860914c1aee402.png)

* * *

> [@Casual\_Tea](#):
>
> ...concerning SYLT tags, which states that support is not planned...  
> However what I have not found yet is a reason for that decision.

This can only be answered by the developer of Mp3tag.

---

<div class="post-metadata">

### Author: ![Doug\_Mackie](https://community.mp3tag.de/user_avatar/community.mp3tag.de/doug_mackie/32/279_2.png) [@Doug\_Mackie](https://community.mp3tag.de/u/Doug_Mackie)
#### Post date: [May 18, 2024, 12:24am UTC](https://community.mp3tag.de/t/embedded-lyrics-and-which-tags-to-use/64698/3 "2024-05-18T00:24:45Z")

</div>

> [@Casual\_Tea](#):
>
> However what I have not found yet is a reason for that decision.

The developer does not have to give a reason. Better to simply accept that and move on. Let's be grateful for all that he has given us..

---

<div class="post-metadata">

### Author: ![Florian](https://community.mp3tag.de/user_avatar/community.mp3tag.de/florian/32/5759_2.png) [@Florian](https://community.mp3tag.de/u/Florian)
#### Post date: [May 18, 2024, 5:41am UTC](https://community.mp3tag.de/t/embedded-lyrics-and-which-tags-to-use/64698/4 "2024-05-18T05:41:58Z")

</div>

> [@Casual\_Tea](#):
>
> However what I have not found yet is a reason for that decision.

The main reason is, that it would require dedicated UI to enter timestamp/lyrics and that this would only be available for ID3v2-tagged files.

Another reason is the relatively complex format of the synced lyrics ID3v2 frame, which makes is difficult (but I guess not impossible) to create a textual representation that can then be used with all other operations Mp3tag has to offer.

---

<div class="post-metadata">

### Author: ![Florian](https://community.mp3tag.de/user_avatar/community.mp3tag.de/florian/32/5759_2.png) [@Florian](https://community.mp3tag.de/u/Florian)
#### Post date: [May 18, 2024, 5:47am UTC](https://community.mp3tag.de/t/embedded-lyrics-and-which-tags-to-use/64698/5 "2024-05-18T05:47:54Z")

</div>

Thanks, Doug. I've answered anyway, mainly because of this question:

> [@Casual\_Tea](#):
>
> Has the SYLT tag limitations I'm not aware of and should be avoided?

Simply to clarify that it's not the SYLT frame per se, but all the implementation effort and the resulting inconsistencies in Mp3tag's UI and internals that motivate this decision.

---

<div class="post-metadata">

### Author: ![Casual\_Tea](https://community.mp3tag.de/user_avatar/community.mp3tag.de/casual_tea/32/18886_2.png) [@Casual\_Tea](https://community.mp3tag.de/u/Casual_Tea)
#### Post date: [May 18, 2024, 5:09pm UTC](https://community.mp3tag.de/t/embedded-lyrics-and-which-tags-to-use/64698/6 "2024-05-18T17:09:57Z")

</div>

> [@LyricsLover](#):
>
> for unsynchronised lyrics - Mp3tag is using [UNSYNCEDLYRICS](https://docs.mp3tag.de/mapping/#unsyncedlyrics)

That's useful information. I was not aware of that mapping, thanks.

> [@Florian](#):
>
> Another reason is the relatively complex format of the synced lyrics ID3v2 frame, which makes is difficult (but I guess not impossible) to create a textual representation that can then be used with all other operations Mp3tag has to offer.

Thank you for going into detail. After spending a few more hours on this today I have to agree with you. The SYLT frame seems more complicated and strict than it needs to be (all times in ms, no support for tags in [xxx:yyy] format etc.).

At this point I have to say that internal mappings are often quite painful for scripting.

My initial approach was using ffprobe to extract the lyrics like this (I reduced the lyrics to 2 lines to avoid spam):

**ffprobe**

synced:

```auto
ffprobe -v quiet -print_format json -show_entries format_tags=LYRICS "01 24‐25.flac"
{
    "format": {
        "tags": {
            "LYRICS": "[0:17.576]She'll be gone soon\r\n[0:19.127]You can have me for yourself\r\n"
        }
    }
}

```

unsynced:

```auto
ffprobe -v quiet -print_format json -show_entries format_tags=UNSYNCEDLYRICS "01 24‐25.flac"
{
    "format": {
        "tags": {
            "UNSYNCEDLYRICS": "She'll be gone soon\r\nYou can have me for yourself\r\n"
        }
    }
}

```

That works perfectly for flac files with vorbis tags (I fixed the linebreaks (\r\n) while parsing the JSON response before writing .lrc/.txt files).

When used with mp3 files however, only LYRICS works:

```auto
ffprobe -v quiet -print_format json -show_entries format_tags=LYRICS "01 24‐25.mp3"
{
    "format": {
        "tags": {
            "LYRICS": "[0:17.576]She'll be gone soon\r\n[0:19.127]You can have me for yourself\r\n"
        }
    }
}

```

UNSYNCEDLYRICS does not:

```auto
ffprobe -v quiet -print_format json -show_entries format_tags=UNSYNCEDLYRICS "01 24‐25.mp3"
{
    "format": {
        "tags": {

        }
    }
}

```

Neither does USLT, which is the frame mp3tag writes for mp3 files:

```auto
ffprobe -v quiet -print_format json -show_entries format_tags=USLT "01 24‐25.mp3"
{
    "format": {
        "tags": {

        }
    }
}

```

Turns out ffprobe maps the USLT tag internally to "lyrics-" + whatever language is stored in the frame:

> Syntax: `xxx||Lyrics` where xxx = Language of the lyrics, abbreviated by 3 characters according to ISO-639-2.

Which is why this works.

```auto
ffprobe -v quiet -print_format json -show_entries format_tags=lyrics-eng "01 24‐25.mp3"
{
    "format": {
        "tags": {
            "lyrics-eng": "She'll be gone soon\r\nYou can have me for yourself\r\n"
        }
    }
}

```

Since that depends on this mp3tag setting (at least when embedding the lyrics through mp3tag):  
 ![eng](https://community.mp3tag.de/uploads/default/original/3X/0/b/0b3616857f907b00e3356e6bb4876ba1787ef9c9.jpeg)

That makes it pretty much useless for scripting as I don't have a way to check what language is set.

**kid3-cli**

As an alternative I tried using kid3-cli to achieve the same.  
Which once again works for flac files:

Synced:

```auto
kid3-cli -c "get LYRICS" "01 24‐25.flac"
[0:17.576]She'll be gone soon
[0:19.127]You can have me for yourself

```

Unsynced:

```auto
kid3-cli -c "get UNSYNCEDLYRICS" "01 24‐25.flac"
She'll be gone soon
You can have me for yourself

```

But for mp3 files it returns unsynced lyrics when called with LYRICS:

```auto
kid3-cli -c "get LYRICS" "01 24‐25.mp3"
She'll be gone soon
You can have me for yourself

```

Nothing for UNSYNCEDLYRICS.

```auto
kid3-cli -c "get UNSYNCEDLYRICS" "01 24‐25.mp3"

```

And once again unsynced lyrics when called with USLT:

```auto
kid3-cli -c "get USLT" "01 24‐25.mp3"
She'll be gone soon
You can have me for yourself

```

Turns out kid3-cli maps USLT to "Lyrics" internally and the vorbis tag LYRICS to "LYRICS", since it is not case sensitive tho, I have not found a way to make it return the TXXX LYRICS tag instead of USLT.

When using SYLT instead of LYRICS for mp3 files, kid3-cli would work, however I'd like to avoid using that frame as mp3tag does not support it and I dislike how restrictive it is.

I guess I could use ffprobe to extract the vorbis tags for flac files and the synced lyrics for mp3 files and then use kid3-cli to get the USLT frame from mp3 files, but that adds one more dependency and feels quite hacky.

So if anyone knows a cli program that can reliably return the vorbis tags LYRICS and UNSYNCEDLYRICS as well as the id3 tags for SYLT and USLT (I do want to support exporting the SYLT frame to .lrc so people can get rid of it), please let me know.

---

<div class="post-metadata">

### Author: ![LyricsLover](https://community.mp3tag.de/letter_avatar_proxy/v4/letter/l/c6cbf5/32.png) [@LyricsLover](https://community.mp3tag.de/u/LyricsLover)
#### Post date: [May 18, 2024, 6:34pm UTC](https://community.mp3tag.de/t/embedded-lyrics-and-which-tags-to-use/64698/7 "2024-05-18T18:34:06Z")

</div>

Thanks for the interesting information you have shared with us.

I could have a look if you can provide your 4 test files (2 x mp3 and 2 x FLAC).  
Please let me know in a PM, where I can DL those files.  
(Maybe you can use some service like "WeTransfer" or similar?)

---

<div class="post-metadata">

### Author: ![Casual\_Tea](https://community.mp3tag.de/user_avatar/community.mp3tag.de/casual_tea/32/18886_2.png) [@Casual\_Tea](https://community.mp3tag.de/u/Casual_Tea)
#### Post date: [May 22, 2024, 9:29pm UTC](https://community.mp3tag.de/t/embedded-lyrics-and-which-tags-to-use/64698/8 "2024-05-22T21:29:55Z")

</div>

Thanks for your help.

As it turns out, [mutagen](https://mutagen.readthedocs.io/en/latest/) offers everything I needed.

I've added some more functions to the script, now it has 4 modes:  
test, mp3tag, import, export

I've called the final script lyrict, short for lyrictest or lyrictool.  
If anyone wants to test it and/or give me feedback, here's the link to the [github repo](https://github.com/AverageHoarder/lyrict) with detailed instructions on how to install and use it (perhaps too detailed).  
When in doubt, skip to the [Common examples](https://github.com/AverageHoarder/lyrict?tab=readme-ov-file#common-examples) to get a running start.

**However** , I strongly suggest that you only use this on test files or when you have an up-to-date backup of your library. 😉

---

<div class="post-metadata">

### Author: ![Casual\_Tea](https://community.mp3tag.de/user_avatar/community.mp3tag.de/casual_tea/32/18886_2.png) [@Casual\_Tea](https://community.mp3tag.de/u/Casual_Tea)
#### Post date: [November 1, 2024, 11:51am UTC](https://community.mp3tag.de/t/embedded-lyrics-and-which-tags-to-use/64698/9 "2024-11-01T11:51:17Z")

</div>

Thought I'd update this since I've put some more work into my script in the meantime.  
Now it supports a wider range of timestamps and also fixes nonsensical timestamps with more than 59 minutes or seconds:  
`[hh:mm:ss.xxx]` `[mm:ss.xxx]` `[mm:ss]` `[hh:mm:ss.xx]` `[mm:ss.xx]`  
I've also added a 5th mode "tag\_external" which allows to tag external lyrics files based on existing tags and tags from linked mp3/flac files.

Example:  
`01 24‐25.flac` is tagged like this:  
 ![grafik](https://community.mp3tag.de/uploads/default/original/3X/d/c/dc81e43a5955dcd51de40c92296f3a2fc45560dc.png)  
`01 24‐25.lrc` contains these lyrics:

```auto
[00:17.576]She'll be gone soon
[00:19.127]You can have me for yourself
[00:25.307]She'll be gone soon
[00:26.807]You can have me for yourself
[00:31.607]But do give
[00:35.927]Just give me today
[00:39.287]Or you will just scare me away
[00:47.131]
[01:04.014]What we built is bigger
...

```

Running `lyrict.py -m tag_external` in that folder changes the .lrc file to:

```auto
[ar:Kings of Convenience]
[al:Declaration of Dependence]
[ti:24-25]
[au:Eirik Glambek Bøe; Erlend Øye]
[length:03:38]
[00:17.576]She'll be gone soon
[00:19.127]You can have me for yourself
[00:25.307]She'll be gone soon
[00:26.807]You can have me for yourself
[00:31.607]But do give
[00:35.927]Just give me today
[00:39.287]Or you will just scare me away
[00:47.131]
[01:04.014]What we built is bigger
...

```

These are the tags/properties it currently extracts from mp3 and flac files.  
It also updates existing tags, so if the .lrc file starts out like this:

```auto
[al:garbage]
[ar:garbage]
[ti:garbage]
[la:eng]
[by:Casual_Tea]
[offset:+0]
[re:MusicBee]
[tool:MusicBee]
[ve:3.5.8698P]
[00:17.576]She'll be gone soon
[00:19.127]You can have me for yourself
[00:25.307]She'll be gone soon
[00:26.807]You can have me for yourself
[00:31.607]But do give
[00:35.927]Just give me today
[00:39.287]Or you will just scare me away
[00:47.131]
[01:04.014]What we built is bigger
...

```

running the same command changes the order and updates the garbage tags to:

```auto
[ar:Kings of Convenience]
[al:Declaration of Dependence]
[ti:24-25]
[au:Eirik Glambek Bøe; Erlend Øye]
[length:03:38]
[la:eng]
[offset:+0]
[by:Casual_Tea]
[re:MusicBee]
[ve:3.5.8698P]
[00:17.576]She'll be gone soon
[00:19.127]You can have me for yourself
[00:25.307]She'll be gone soon
[00:26.807]You can have me for yourself
[00:31.607]But do give
[00:35.927]Just give me today
[00:39.287]Or you will just scare me away
[00:47.131]
[01:04.014]What we built is bigger
...

```

I've also overhauled the `--standardize` argument, it now has 3 modes to either preserve existing timestamp formatting (but still fixing errors) or to force all timestamps into one of 2 patterns.  
The default behavior is to keep the timestamp formats as they are, so a source .lrc file containing.

```auto
[00:01]text
[00:02.34]text
[00:03.456]text

```

will not be changed (unless there's more than 59 minutes or 59 seconds in the timestamp):  
`[00:62.123]text` would become `[01:02.123]text` and  
`[68:05.234]text` would become `[01:08:05.234]text`

The other 2 modes allow enforcing a strict timestamp format:  
Source:

```auto
[00:01]text
[00:02.34]text
[00:03.456]text

```

using `lyrict.py -m tag_external --standardize force.xx` on this would yield:  
Result 1:

```auto
[00:01.00]text
[00:02.34]text
[00:03.45]text

```

and using `lyrict.py -m tag_external --standardize force.xxx` would yield:  
Result 2:

```auto
[00:01.000]text
[00:02.340]text
[00:03.456]text

```

The tag\_external mode also reduces consecutive empty lines to 1 empty line and removes spaces following timestamps, so:

```auto
[00:17.576] She'll be gone soon

[00:19.127]You can have me for yourself
[00:25.307] She'll be gone soon

[00:26.807]You can have me for yourself

```

would become:

```auto
[00:17.576]She'll be gone soon

[00:19.127]You can have me for yourself
[00:25.307]She'll be gone soon

[00:26.807]You can have me for yourself

```

Let me know if you find it useful (or if you encounter errors). 😀
