Mercurial > repos > other > import-rating-rhythmbox
view import-rating-rhythmbox.py @ 0:4fab77a9ac9d default tip
Initial commit of working script
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Sat, 11 Nov 2017 16:27:22 +0000 |
parents | |
children |
line wrap: on
line source
#! /usr/bin/env python3 from xml.dom.minidom import parse import sys from os import path from os.path import expanduser from urllib.parse import urlparse, unquote import mutagen ### Usage: python3 ./quodlibet-to-rhythmbox.py > output.xml; \ ### mv output.xml ~/.local/share/rhythmbox/rhythmdb.xml # List of sub-keys that we will take POPM ratings from # The order they are here is their priority - we take the first one we find TRANSFER_KEYS = [ 'quodlibet@lists.sacredchao.net', 'Banshee' ] DEBUG_LEVEL = 0 def _debug(message, level=1): if level <= DEBUG_LEVEL: print(message, file=sys.stderr) def _get_text(nodelist): content = [] for node in nodelist: if node.nodeType == node.TEXT_NODE: content.append(node.data) return ''.join(content) def _get_path_from_url(file_uri): parsed = urlparse(file_uri) return path.abspath(path.join(parsed.netloc, unquote(parsed.path))) def _normalise_rating(rating): # Take the Banshee approach to ratings, but assume that a rating of 5 # or below is an exact rating (normally a rogue Banshee rating) # https://git.gnome.org/browse/banshee/tree/src/Core/Banshee.Core/Banshee.Streaming/StreamRatingTagger.cs#n54 if rating <= 5: return rating elif rating < 64: return 1 elif rating < 128: return 2 elif rating < 192: return 3 elif rating < 255: return 4 else: return 5 def _set_rating(doc, entry, value): rating = _normalise_rating(value) _debug("Setting rating to {} based on value {}".format(rating, value)) rating_tag = doc.createElement("rating") rating_tag.appendChild(doc.createTextNode(str(rating))) entry.appendChild(rating_tag) def transfer_ratings(): """ Transfers the ratings from IDv3 POPM tags to Rhythmbox's XML database and prints the resulting XML to stdout """ home = expanduser("~") doc_path = path.join(home, '.local/share/rhythmbox/rhythmdb.xml') doc = parse(doc_path) if len(doc.childNodes) != 1: _debug("Invalid document structure", 0) exit(1) rhythmdb = doc.childNodes[0] if rhythmdb.nodeName != 'rhythmdb': _debug("Invalid document structure", 0) exit(1) for entry in rhythmdb.childNodes: if entry.nodeType == entry.TEXT_NODE or entry.getAttribute('type') != 'song': continue if len(entry.getElementsByTagName('rating')) > 0: continue locations = entry.getElementsByTagName('location') if len(locations) != 1: _debug("Song did not have one location", 0) continue location = locations[0] file_path = _get_path_from_url(_get_text(location.childNodes)) if not path.isfile(file_path): _debug("{} was not a file".format(file_path)) try: track = mutagen.File(file_path) for key_suffix in TRANSFER_KEYS: key = 'POPM:{}'.format(key_suffix) if key in track.tags: rating = track.tags[key].rating if rating > 0: _debug("Found rating from {} for {}".format(key_suffix, file_path)) _set_rating(doc, entry, track.tags[key].rating) break except mutagen.MutagenError as ex: _debug("Error processing {}: {}".format(file_path, ex), 0) print(doc.toxml()) if __name__ == '__main__': transfer_ratings()