After updating to Foobar2000 v2.0 I noticed that foo_playcount is now basically the "default" for storing ratings, so I thought it would be a good time to transfer the ratings from the metadata of all the audio files to a foo_playcount-compatible XML file that can be imported into Foobar.
Usage is really easy: just export your library as XML first (through Library --> Playback Statistics, make sure to check all fields so that it exports all the file paths). Run this script and re-import the resulting XML. Note: I give no guarantees, use at your own risk!
This script was written partly by ChatGPT, partly by me
import os
import xml.etree.ElementTree as ET
from mutagen import File
import numpy as np
def extract_rating(file_path):
"""
Extracts the rating from the metadata
"""
audio = File(file_path)
if 'rating' in audio:
R = int(float(audio['rating'][0]))
assert(0 <= R <= 5)
return R
return None
def calc_rating(rating):
"""
foo_playcount stores the 0-5 rating as 'RatingFriendly' and a different
integer as 'Rating', according to the equation below.
Source: https://hydrogenaud.io/index.php/topic,85309.msg733606.html#msg733606
"""
return int(np.round((63.75 + 42.5*(rating-1))))
def update_ratings(infile, outfile, folder_path):
"""
Scans a folder recursively for audio files, extracts ratings and updates
the XML data.
"""
tree = ET.parse(infile)
root = tree.getroot()
for entry in root.findall('./Entry'):
item = entry.find('Item')
file_path = item.get('Path')
if file_path:
file_path = os.path.normpath(file_path)
if any(file_path.lower().endswith(ext) for ext in ('.mp3', '.wav', '.flac', '.aac', '.mp4')):
print('Scanning {}...'.format(file_path))
rating = extract_rating(file_path)
if rating is not None:
entry.set('Rating', str(calc_rating(rating)))
entry.set('RatingFriendly', str(rating))
tree.write(outfile, encoding='utf-8', xml_declaration=False)
inxml = 'Library.xml'
outxml = 'Library_ratings.xml'
folder_to_scan = 'H:/MUSIC'
update_ratings(inxml, outxml, folder_to_scan)