Skip to content

Instantly share code, notes, and snippets.

@Teque5
Last active March 7, 2024 16:42
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Teque5/69d5ece2003e7ea1f3c29daf01b411a2 to your computer and use it in GitHub Desktop.
Save Teque5/69d5ece2003e7ea1f3c29daf01b411a2 to your computer and use it in GitHub Desktop.
This script adds ratings from flac and mp3 files to Rhythmbox format while preserving the existing database. Rhythmbox uses XML database to store its music files, together with rating. However, it does not read the ID3 rating frame of a music file if it exists, making it harder for people transferring rated music from other player to this one (f…
#!/usr/bin/env python3
"""
popm2rhythmBox
Winamp -> RhythmBox
inspired by https://github.com/shatterhand19/RhythmboxPOPM
"""
import os
from urllib.parse import unquote
import lxml.etree as etree
from blessings import Terminal
from mutagen.flac import FLAC
from mutagen.id3 import ID3
FLAC_MAP = {
"20": 1,
"40": 2,
"60": 3,
"80": 4,
"100": 5,
}
ID3_MAP = {
1: 1,
64: 2,
128: 3,
196: 4,
255: 5,
}
DATABASE = "~/.local/share/rhythmbox/rhythmdb.xml"
DATABASE = os.path.expanduser(DATABASE)
clean = lambda node: print(etree.tostring(node, pretty_print=True).decode())
def readID3(location: str) -> int:
"""return star count based on ID3 tag"""
tag = ID3(location)
raw = tag["POPM:rating@winamp.com"].rating
return ID3_MAP[raw]
def readFLAC(location: str) -> int:
"""return star count based on FLAC tag"""
tag = FLAC(location)
raw = tag["rating"][0]
return FLAC_MAP[raw]
if __name__ == "__main__":
"""
Read WINAMP compatible ratings stored to files into Rhythmbox XML library
Must have files in library first. Currently reads MP3s & FLAC;
TODO: Add OGG & M4A
"""
t = Terminal() # pretty colors
tree = etree.parse(DATABASE)
for song in tree.findall("entry"):
location = unquote(song.find("location").text).replace("file://", "")
filetype = location.rpartition(".")[-1]
# print(location)
if os.path.exists(location):
try:
if filetype == "mp3":
rating = readID3(location)
elif filetype == "flac":
rating = readFLAC(location)
color = "teal"
else:
# file type not recognized
rating = "F"
except KeyError:
rating = "N" # no rating in file
filename = location.rpartition("/")[-1]
if filetype == "mp3":
print(t.bold(str(rating)), t.cyan(filename))
elif filetype == "flac":
print(t.bold(str(rating)), t.magenta(filename))
if rating not in range(6):
continue
temp = etree.Element("rating")
temp.text = str(rating)
song.append(temp)
tree.write("derp.xml", pretty_print=True)
print("\nNow overwrite your {} with new derp.xml".format(DATABASE))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment