Last active
March 7, 2024 16:42
-
-
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…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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