[Release] Import Clementine Ratings

What?

Hello everyone, you may know me from films such as… Kidding. But hello nonetheless, today I’m releasing the culmination of all of my recent sleepless nights.

This simple script scans the location of your Navidrome music collection, pulls the embedded rating and then adds that rating to your Navidrome account

Code

v 0.3: Not only was the last version hideous, it was inconsistent. Stuff that worked in single directory mode never worked in full mode. Also removed some print statements, cleaned up some others.


<span style="color:#323232;">import os
</span><span style="color:#323232;">import mutagen
</span><span style="color:#323232;">import requests
</span><span style="color:#323232;">import urllib.parse
</span><span style="color:#323232;">import json
</span><span style="color:#323232;">import sys
</span><span style="color:#323232;">import glob
</span><span style="color:#323232;">from mutagen.id3 import ID3
</span><span style="color:#323232;">global rating
</span><span style="color:#323232;">global track_id
</span><span style="color:#323232;">
</span><span style="color:#323232;"># Navidrome credentials
</span><span style="color:#323232;">script_name = "ImportClementineRatings"
</span><span style="color:#323232;">navidrome_url = "your-navidrome-server:port"
</span><span style="color:#323232;">navidrome_username = "your-navidrome-username"
</span><span style="color:#323232;">navidrome_password = "your-navidrome-password"
</span><span style="color:#323232;">headers = None
</span><span style="color:#323232;">
</span><span style="color:#323232;"># Directory containing MP3 files
</span><span style="color:#323232;">mp3_directory = "your-collection-relative-to-this-script"
</span><span style="color:#323232;">
</span><span style="color:#323232;"># Single Directory Mode
</span><span style="color:#323232;">if len(sys.argv) > 1:
</span><span style="color:#323232;">  for arg in sys.argv:
</span><span style="color:#323232;">    #print(arg)
</span><span style="color:#323232;">    #if arg != "import_ratings.py":
</span><span style="color:#323232;">    if arg != os.path.basename(__file__):
</span><span style="color:#323232;">      mp3_directory = "/".join([mp3_directory,"Collection",arg])
</span><span style="color:#323232;">
</span><span style="color:#323232;">def extract_rating(mp3_file):
</span><span style="color:#323232;">    audio = mutagen.File(mp3_file)
</span><span style="color:#323232;">    tags = ID3(mp3_file)
</span><span style="color:#323232;">    if "TXXX:FMPS_Rating_Amarok_Score" in tags:
</span><span style="color:#323232;">      rating = tags["TXXX:FMPS_Rating_Amarok_Score"]
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">      print(" ".join(["No rating exists for",mp3_file,"this song"]))
</span><span style="color:#323232;">      rating = None
</span><span style="color:#323232;">
</span><span style="color:#323232;">    if (rating != None):
</span><span style="color:#323232;">      sanerating = float(str(rating))
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">      sanerating = float(0)
</span><span style="color:#323232;">
</span><span style="color:#323232;">    if sanerating >= 1.0:
</span><span style="color:#323232;">      return 5
</span><span style="color:#323232;">    elif sanerating >= 0.8:
</span><span style="color:#323232;">      return 4
</span><span style="color:#323232;">    elif sanerating >= 0.6:
</span><span style="color:#323232;">      return 3
</span><span style="color:#323232;">    elif sanerating >= 0.4:
</span><span style="color:#323232;">      return 2
</span><span style="color:#323232;">    elif sanerating >= 0.2:
</span><span style="color:#323232;">      return 1
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">      return 0
</span><span style="color:#323232;">
</span><span style="color:#323232;">def update_rating_on_navidrome(track_id, rating):
</span><span style="color:#323232;">    hex_encoded_pass = navidrome_password.encode().hex()
</span><span style="color:#323232;">    #print(rating)
</span><span style="color:#323232;">    if rating != 0:
</span><span style="color:#323232;">      url = f"{navidrome_url}/rest/setRating?id={track_id}&u={navidrome_username}&p=enc:{hex_encoded_pass}&v=1.12.0&rating={rating}&c={script_name}"
</span><span style="color:#323232;">      response = requests.get(url)
</span><span style="color:#323232;">      print(f"Success!")
</span><span style="color:#323232;">
</span><span style="color:#323232;">def find_track_id_on_navidrome(mp3_file):
</span><span style="color:#323232;">    track_id = None
</span><span style="color:#323232;">
</span><span style="color:#323232;">    # Remove File Extension
</span><span style="color:#323232;">    song = mp3_file.rsplit(".",1)[0]
</span><span style="color:#323232;">
</span><span style="color:#323232;">    # Fetch Song Artist From Filename
</span><span style="color:#323232;">    songartist = song.split(" - ")[0]
</span><span style="color:#323232;">    songartist = songartist.split("/")[-1]
</span><span style="color:#323232;">
</span><span style="color:#323232;">    # Fetch Song Title From Filename
</span><span style="color:#323232;">    index_var = 1
</span><span style="color:#323232;">    if 0 <= index_var < len(song.split(" - ")):
</span><span style="color:#323232;">      songtitle = song.split(" - ")[1]
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">      return None
</span><span style="color:#323232;">      
</span><span style="color:#323232;">    #songtitle = urllib.parse.quote(songtitle)
</span><span style="color:#323232;">    hex_encoded_pass = navidrome_password.encode().hex()
</span><span style="color:#323232;">
</span><span style="color:#323232;">    if len(songtitle) < 2:
</span><span style="color:#323232;">      return None
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">      #print(songtitle)
</span><span style="color:#323232;">      songtitle = song.split(" - ")[1]
</span><span style="color:#323232;">      songtitle = urllib.parse.quote(songtitle)
</span><span style="color:#323232;">
</span><span style="color:#323232;">    url = f"{navidrome_url}/rest/search3?query={songtitle}&u={navidrome_username}&p=enc:{hex_encoded_pass}&v=1.12.0&c={script_name}&f=json"
</span><span style="color:#323232;">    data = None
</span><span style="color:#323232;">
</span><span style="color:#323232;">    response = requests.get(url)
</span><span style="color:#323232;">    parsed = json.loads(response.content)
</span><span style="color:#323232;">    print(f"Debug URL: {url}")
</span><span style="color:#323232;">    if "subsonic-response" in parsed:
</span><span style="color:#323232;">      parsed = parsed["subsonic-response"]
</span><span style="color:#323232;">      if "searchResult3" in parsed:
</span><span style="color:#323232;">        parsed = parsed["searchResult3"]
</span><span style="color:#323232;">        if "song" in parsed:
</span><span style="color:#323232;">           for match in parsed["song"]:
</span><span style="color:#323232;">             special_characters = ":?*"
</span><span style="color:#323232;">             if any(character in special_characters for character in  match["artist"]):
</span><span style="color:#323232;">                match["artist"] = match["artist"].translate({ord(c): "_" for c in special_characters})
</span><span style="color:#323232;">
</span><span style="color:#323232;">             if (match["artist"] == songartist):
</span><span style="color:#323232;">               parsed = match
</span><span style="color:#323232;">               track_id = match["id"]
</span><span style="color:#323232;">
</span><span style="color:#323232;">    songtitle = urllib.parse.unquote(songtitle)
</span><span style="color:#323232;">    if response.status_code == 200:
</span><span style="color:#323232;">        if track_id:
</span><span style="color:#323232;">          print(f"Track successfully identified: {songtitle}: {track_id}")
</span><span style="color:#323232;">          return track_id
</span><span style="color:#323232;">        else:
</span><span style="color:#323232;">          print(f"Could not find {songtitle} track") 
</span><span style="color:#323232;">          return None
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">        print(f"Failed to identify track {songtitle}: {response.text}")
</span><span style="color:#323232;">        return None
</span><span style="color:#323232;">
</span><span style="color:#323232;">def process_file(mp3_file, folder):
</span><span style="color:#323232;">  track_id = "fail"
</span><span style="color:#323232;">
</span><span style="color:#323232;">  mp3_file = "/".join([folder, mp3_file])
</span><span style="color:#323232;">  rating = extract_rating(mp3_file)
</span><span style="color:#323232;">  track_id = find_track_id_on_navidrome(mp3_file)
</span><span style="color:#323232;">
</span><span style="color:#323232;">  if track_id != "fail":
</span><span style="color:#323232;">    try:
</span><span style="color:#323232;">      update_rating_on_navidrome(track_id, rating)
</span><span style="color:#323232;">    except:
</span><span style="color:#323232;">      print(f"Failed to set rating for {file}")
</span><span style="color:#323232;">
</span><span style="color:#323232;">notmusicext = ("DS_Store","jpg", ".JPG", ".jpeg", ".JPEG", ".mood", ".m3u", ".nfo", ".png", ".PNG", ".sfv", ".url")
</span><span style="color:#323232;">
</span><span style="color:#323232;">for foldername in os.listdir(mp3_directory):
</span><span style="color:#323232;">  if foldername.endswith(".mp3"):
</span><span style="color:#323232;">    process_file(foldername, mp3_directory)
</span><span style="color:#323232;">    folderpath = mp3_directory
</span><span style="color:#323232;">  elif foldername.endswith(notmusicext):
</span><span style="color:#323232;">    print(f"Skipping: {foldername}")
</span><span style="color:#323232;">  else:
</span><span style="color:#323232;">    folderpath = "/".join([mp3_directory, foldername])
</span><span style="color:#323232;">  #for filename in glob.iglob(mp3_directory + "*.mp3", recursive=True):
</span><span style="color:#323232;">  #can't get this to work
</span><span style="color:#323232;">    #would do stuff here
</span><span style="color:#323232;">    print(f" Debug: folderpath")
</span><span style="color:#323232;">
</span><span style="color:#323232;">    for filename in os.listdir(folderpath):
</span><span style="color:#323232;">      if filename.endswith(".mp3"):
</span><span style="color:#323232;">        process_file(filename, folderpath)
</span><span style="color:#323232;">      elif filename.endswith(notmusicext):
</span><span style="color:#323232;">        print(f"Skipping: {filename}")
</span><span style="color:#323232;">      else:
</span><span style="color:#323232;">        foldername2 = "/".join([folderpath,filename])
</span><span style="color:#323232;">        for filename2 in os.listdir(foldername2):
</span><span style="color:#323232;">          if filename2.endswith(".mp3"):
</span><span style="color:#323232;">            if filename2.startswith("A") == False:
</span><span style="color:#323232;">              process_file(filename2, foldername2)
</span><span style="color:#323232;">          elif filename2.endswith(notmusicext):
</span><span style="color:#323232;">            print(f"Skipping: {filename2}")
</span><span style="color:#323232;">          else:
</span><span style="color:#323232;">            print(f"What is: {filename2}")
</span><span style="color:#323232;">
</span><span style="color:#323232;">print("Done!")
</span>

Usage

Copy the code block, create a Python script in your chosen directory and then run it.

Thanks

This truly would not be possible without the Fediverse community, especially the Lemmy community. So thank you everyone but especially

@Deebster @ggwithgg @jnovinger @ishanpage @rglullis @oscar @TootSweet @sabret00the @amcewen @oblomov @mdylanbell @mborous @cohomologyisFUN @eichin @mdione

For some of you what you did seemed so small, but it was massive to me and I’m incredibly grateful for your kindness.

The Lore

One day, one man decided that enough was enough, it was time to move to the modern age, but to get there he needed his music collection. However it wasn’t enough to just have the music, he needed the ratings too. First world problems, I know! So with nothing but hope, he said out in search of the ring! I mean the script! He couldn’t find the script, but Deebster offered to help and so the two of them embarked on a journey whereby I kept pasting stuff to Desbster and he was like “no” but under his guidance, my script born from the embers of Bard, started taking shape. Now, for me with zero Python experience, you can imagine that the guidance I required was a lot, but Deebster earned his Scout badge in guidance. And as I got closer and closer, I kept cutting my sleep short so that I could spend some extra time trying to figure it out. Also huge thanks to Minz from the Navidrome discord as they came in clutch with some API advice. Anyway, I got a working script and I’m paying it forward by sharing it. Thank you all again.

Anything Else

If you can see how I should improve this, please let me know. Thank you all again.

sabreW4K3, (edited )
@sabreW4K3@lemmy.tf avatar

Archive

v0.1: Initial release was tested with a few directories and quickly had issues when I tried it against my real thing. I quickly ended up cursing Big Python and then decided to fix the issues.


<span style="color:#323232;">import os
</span><span style="color:#323232;">import mutagen
</span><span style="color:#323232;">import requests
</span><span style="color:#323232;">import urllib.parse
</span><span style="color:#323232;">import json
</span><span style="color:#323232;">from mutagen.easyid3 import EasyID3
</span><span style="color:#323232;">from mutagen.id3 import ID3
</span><span style="color:#323232;">from pprint import pprint
</span><span style="color:#323232;">global rating
</span><span style="color:#323232;">global track_id
</span><span style="color:#323232;">
</span><span style="color:#323232;"># Navidrome credentials
</span><span style="color:#323232;">script_name = "ImportClementineRatings"
</span><span style="color:#323232;">navidrome_url = "http://your-navidrome-server-location:4533"
</span><span style="color:#323232;">navidrome_username = "your-username"
</span><span style="color:#323232;">navidrome_password = "your-password"
</span><span style="color:#323232;">headers = None
</span><span style="color:#323232;">
</span><span style="color:#323232;"># Directory containing MP3 files
</span><span style="color:#323232;">mp3_directory = "the-location-of-your-music-directory-relative-to-where-this-script-will-be"
</span><span style="color:#323232;">
</span><span style="color:#323232;">def extract_rating(mp3_file):
</span><span style="color:#323232;">    audio = mutagen.File(mp3_file)
</span><span style="color:#323232;">    tags = ID3(mp3_file)
</span><span style="color:#323232;">    if "TXXX:FMPS_Rating_Amarok_Score" in tags:
</span><span style="color:#323232;">      rating = tags["TXXX:FMPS_Rating_Amarok_Score"]
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">      print(" ".join(["No rating exists for",mp3_file,"this song"]))
</span><span style="color:#323232;">      rating = None
</span><span style="color:#323232;">
</span><span style="color:#323232;">    if (rating != None):
</span><span style="color:#323232;">      sanerating = float(str(rating))
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">      sanerating = float(0)
</span><span style="color:#323232;">
</span><span style="color:#323232;">    if sanerating >= 1.0:
</span><span style="color:#323232;">      return 5
</span><span style="color:#323232;">    elif sanerating >= 0.8:
</span><span style="color:#323232;">      return 4
</span><span style="color:#323232;">    elif sanerating >= 0.6:
</span><span style="color:#323232;">      return 3
</span><span style="color:#323232;">    elif sanerating >= 0.4:
</span><span style="color:#323232;">      return 2
</span><span style="color:#323232;">    elif sanerating >= 0.2:
</span><span style="color:#323232;">      return 1
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">      return 0
</span><span style="color:#323232;">
</span><span style="color:#323232;">def update_rating_on_navidrome(track_id, rating):
</span><span style="color:#323232;">    hex_encoded_pass = navidrome_password.encode().hex()
</span><span style="color:#323232;">    url = f"{navidrome_url}/rest/setRating?id={track_id}&u={navidrome_username}&p=enc:{hex_encoded_pass}&v=1.12.0&rating={rating}&c={script_name}"
</span><span style="color:#323232;">    response = requests.get(url)
</span><span style="color:#323232;">
</span><span style="color:#323232;">def find_track_id_on_navidrome(mp3_file):
</span><span style="color:#323232;">    # Remove File Extension
</span><span style="color:#323232;">    song = mp3_file.rsplit(".",1)[0]
</span><span style="color:#323232;">
</span><span style="color:#323232;">    # Fetch Song Artist From Filename
</span><span style="color:#323232;">    songartist = song.split(" - ")[0]
</span><span style="color:#323232;">    songtitle = song.split(" - ")[1]
</span><span style="color:#323232;">
</span><span style="color:#323232;">    songtitle = urllib.parse.quote(songtitle)
</span><span style="color:#323232;">    hex_encoded_pass = navidrome_password.encode().hex()
</span><span style="color:#323232;">
</span><span style="color:#323232;">    if len(songtitle) < 2:
</span><span style="color:#323232;">      return None
</span><span style="color:#323232;">
</span><span style="color:#323232;">    url = f"{navidrome_url}/rest/search3?query={songtitle}&u={navidrome_username}&p=enc:{hex_encoded_pass}&v=1.12.0&c={script_name}&f=json"
</span><span style="color:#323232;">    data = None
</span><span style="color:#323232;">
</span><span style="color:#323232;">    response = requests.get(url)
</span><span style="color:#323232;">    parsed = json.loads(response.content)
</span><span style="color:#323232;">    print(url)
</span><span style="color:#323232;">    if "subsonic-response" in parsed:
</span><span style="color:#323232;">      parsed = parsed["subsonic-response"]
</span><span style="color:#323232;">      if "searchResult3" in parsed:
</span><span style="color:#323232;">        parsed = parsed["searchResult3"]
</span><span style="color:#323232;">        if "song" in parsed:
</span><span style="color:#323232;">           for match in parsed["song"]:
</span><span style="color:#323232;">             special_characters = ":?"
</span><span style="color:#323232;">             if any(character in special_characters for character in  match["artist"]):
</span><span style="color:#323232;">                match["artist"] = match["artist"].translate({ord(c): "_" for c in special_characters})
</span><span style="color:#323232;">
</span><span style="color:#323232;">             if (match["artist"] == songartist):
</span><span style="color:#323232;">               parsed = match
</span><span style="color:#323232;">               track_id = match["id"]
</span><span style="color:#323232;">
</span><span style="color:#323232;">    songtitle = urllib.parse.unquote(songtitle)
</span><span style="color:#323232;">    if response.status_code == 200:
</span><span style="color:#323232;">        if track_id:
</span><span style="color:#323232;">          print(f"Track successfully identified: {songtitle}: {track_id}")
</span><span style="color:#323232;">          return track_id
</span><span style="color:#323232;">        else:
</span><span style="color:#323232;">          print(f"Could not find a track") 
</span><span style="color:#323232;">          return None
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">        print(f"Failed to identify track {songtitle}: {response.text}")
</span><span style="color:#323232;">        return None
</span><span style="color:#323232;">
</span><span style="color:#323232;">for foldername in os.listdir(mp3_directory):
</span><span style="color:#323232;">  folderpath = "/".join([mp3_directory, foldername])
</span><span style="color:#323232;">  for filename in os.listdir(folderpath):
</span><span style="color:#323232;">
</span><span style="color:#323232;">    if filename.endswith(".mp3"):
</span><span style="color:#323232;">        mp3_file = "/".join([folderpath, filename])
</span><span style="color:#323232;">        rating = extract_rating(mp3_file)
</span><span style="color:#323232;">        print(filename)
</span><span style="color:#323232;">        track_id = find_track_id_on_navidrome(filename)
</span><span style="color:#323232;">
</span><span style="color:#323232;">        if track_id:
</span><span style="color:#323232;">            update_rating_on_navidrome(track_id, rating)
</span>
sabreW4K3,
@sabreW4K3@lemmy.tf avatar

v0.2: This version is a lot uglier, but allows you to feed a single directory to the command line and also doesn’t die when seeing common files in your music directories.


<span style="color:#323232;">import os
</span><span style="color:#323232;">import mutagen
</span><span style="color:#323232;">import requests
</span><span style="color:#323232;">import urllib.parse
</span><span style="color:#323232;">import json
</span><span style="color:#323232;">import sys
</span><span style="color:#323232;">import glob
</span><span style="color:#323232;">from mutagen.id3 import ID3
</span><span style="color:#323232;">global rating
</span><span style="color:#323232;">global track_id
</span><span style="color:#323232;">
</span><span style="color:#323232;"># Navidrome credentials
</span><span style="color:#323232;">script_name = "ImportClementineRatings"
</span><span style="color:#323232;">navidrome_url = "navidrome-server:port"
</span><span style="color:#323232;">navidrome_username = "navidrome-username"
</span><span style="color:#323232;">navidrome_password = "navidrome-password"
</span><span style="color:#323232;">headers = None
</span><span style="color:#323232;">
</span><span style="color:#323232;"># Directory containing MP3 files
</span><span style="color:#323232;">mp3_directory = "relative-location-of-your-music-collection"
</span><span style="color:#323232;">
</span><span style="color:#323232;"># Single Directory Mode
</span><span style="color:#323232;">if len(sys.argv) > 1:
</span><span style="color:#323232;">  for arg in sys.argv:
</span><span style="color:#323232;">    #print(arg)
</span><span style="color:#323232;">    #if arg != "import_ratings.py":
</span><span style="color:#323232;">    if arg != os.path.basename(__file__):
</span><span style="color:#323232;">      mp3_directory = "/".join([mp3_directory,"Collection",arg])
</span><span style="color:#323232;">
</span><span style="color:#323232;">def extract_rating(mp3_file):
</span><span style="color:#323232;">    audio = mutagen.File(mp3_file)
</span><span style="color:#323232;">    tags = ID3(mp3_file)
</span><span style="color:#323232;">    if "TXXX:FMPS_Rating_Amarok_Score" in tags:
</span><span style="color:#323232;">      rating = tags["TXXX:FMPS_Rating_Amarok_Score"]
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">      print(" ".join(["No rating exists for",mp3_file,"this song"]))
</span><span style="color:#323232;">      rating = None
</span><span style="color:#323232;">
</span><span style="color:#323232;">    if (rating != None):
</span><span style="color:#323232;">      sanerating = float(str(rating))
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">      sanerating = float(0)
</span><span style="color:#323232;">
</span><span style="color:#323232;">    if sanerating >= 1.0:
</span><span style="color:#323232;">      return 5
</span><span style="color:#323232;">    elif sanerating >= 0.8:
</span><span style="color:#323232;">      return 4
</span><span style="color:#323232;">    elif sanerating >= 0.6:
</span><span style="color:#323232;">      return 3
</span><span style="color:#323232;">    elif sanerating >= 0.4:
</span><span style="color:#323232;">      return 2
</span><span style="color:#323232;">    elif sanerating >= 0.2:
</span><span style="color:#323232;">      return 1
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">      return 0
</span><span style="color:#323232;">
</span><span style="color:#323232;">def update_rating_on_navidrome(track_id, rating):
</span><span style="color:#323232;">    hex_encoded_pass = navidrome_password.encode().hex()
</span><span style="color:#323232;">    print(rating)
</span><span style="color:#323232;">    if rating != 0:
</span><span style="color:#323232;">      url = f"{navidrome_url}/rest/setRating?id={track_id}&u={navidrome_username}&p=enc:{hex_encoded_pass}&v=1.12.0&rating={rating}&c={script_name}"
</span><span style="color:#323232;">      response = requests.get(url)
</span><span style="color:#323232;">      print(f"Rating: {rating}")
</span><span style="color:#323232;">
</span><span style="color:#323232;">def find_track_id_on_navidrome(mp3_file):
</span><span style="color:#323232;">    track_id = None
</span><span style="color:#323232;">
</span><span style="color:#323232;">    # Remove File Extension
</span><span style="color:#323232;">    song = mp3_file.rsplit(".",1)[0]
</span><span style="color:#323232;">
</span><span style="color:#323232;">    # Fetch Song Artist From Filename
</span><span style="color:#323232;">    songartist = song.split(" - ")[0]
</span><span style="color:#323232;">    songartist = songartist.split("/")[-1]
</span><span style="color:#323232;">
</span><span style="color:#323232;">    # Fetch Song Title From Filename
</span><span style="color:#323232;">    songtitle = song.split(" - ")[1]
</span><span style="color:#323232;">    songtitle = urllib.parse.quote(songtitle)
</span><span style="color:#323232;">    hex_encoded_pass = navidrome_password.encode().hex()
</span><span style="color:#323232;">
</span><span style="color:#323232;">    if len(songtitle) < 2:
</span><span style="color:#323232;">      return None
</span><span style="color:#323232;">
</span><span style="color:#323232;">    url = f"{navidrome_url}/rest/search3?query={songtitle}&u={navidrome_username}&p=enc:{hex_encoded_pass}&v=1.12.0&c={script_name}&f=json"
</span><span style="color:#323232;">    data = None
</span><span style="color:#323232;">
</span><span style="color:#323232;">    response = requests.get(url)
</span><span style="color:#323232;">    parsed = json.loads(response.content)
</span><span style="color:#323232;">    print(url)
</span><span style="color:#323232;">    if "subsonic-response" in parsed:
</span><span style="color:#323232;">      parsed = parsed["subsonic-response"]
</span><span style="color:#323232;">      if "searchResult3" in parsed:
</span><span style="color:#323232;">        parsed = parsed["searchResult3"]
</span><span style="color:#323232;">        if "song" in parsed:
</span><span style="color:#323232;">           for match in parsed["song"]:
</span><span style="color:#323232;">             special_characters = ":?*"
</span><span style="color:#323232;">             if any(character in special_characters for character in  match["artist"]):
</span><span style="color:#323232;">                match["artist"] = match["artist"].translate({ord(c): "_" for c in special_characters})
</span><span style="color:#323232;">
</span><span style="color:#323232;">             if (match["artist"] == songartist):
</span><span style="color:#323232;">               parsed = match
</span><span style="color:#323232;">               track_id = match["id"]
</span><span style="color:#323232;">
</span><span style="color:#323232;">    songtitle = urllib.parse.unquote(songtitle)
</span><span style="color:#323232;">    if response.status_code == 200:
</span><span style="color:#323232;">        if track_id:
</span><span style="color:#323232;">          print(f"Track successfully identified: {songtitle}: {track_id}")
</span><span style="color:#323232;">          return track_id
</span><span style="color:#323232;">        else:
</span><span style="color:#323232;">          print(f"Could not find {songtitle} track") 
</span><span style="color:#323232;">          return None
</span><span style="color:#323232;">    else:
</span><span style="color:#323232;">        print(f"Failed to identify track {songtitle}: {response.text}")
</span><span style="color:#323232;">        return None
</span><span style="color:#323232;">def process_file(mp3_file, folder):
</span><span style="color:#323232;">  track_id = "fail"
</span><span style="color:#323232;">
</span><span style="color:#323232;">  mp3_file = "/".join([folder, mp3_file])
</span><span style="color:#323232;">  rating = extract_rating(mp3_file)
</span><span style="color:#323232;">  #print(f"Rating1: {rating}")
</span><span style="color:#323232;">  #print(mp3_file)
</span><span style="color:#323232;">  track_id = find_track_id_on_navidrome(mp3_file)
</span><span style="color:#323232;">
</span><span style="color:#323232;">  if track_id != "fail":
</span><span style="color:#323232;">    try:
</span><span style="color:#323232;">      update_rating_on_navidrome(track_id, rating)
</span><span style="color:#323232;">    except:
</span><span style="color:#323232;">      print(f"Failed to set rating for {file}")
</span><span style="color:#323232;">
</span><span style="color:#323232;">for foldername in os.listdir(mp3_directory):
</span><span style="color:#323232;">  if foldername.endswith(".mp3"):
</span><span style="color:#323232;">    #process_file(foldername, mp3_directory)
</span><span style="color:#323232;">    folderpath = mp3_directory
</span><span style="color:#323232;">  elif foldername.endswith(".DS_Store"):
</span><span style="color:#323232;">    print(f"Skipping: {foldername}")
</span><span style="color:#323232;">  elif foldername.endswith(".jpg"):
</span><span style="color:#323232;">    print(f"Skipping: {foldername}")
</span><span style="color:#323232;">  elif foldername.endswith(".JPG"):
</span><span style="color:#323232;">    print(f"Skipping: {foldername}")
</span><span style="color:#323232;">  elif foldername.endswith(".jpeg"):
</span><span style="color:#323232;">    print(f"Skipping: {foldername}")
</span><span style="color:#323232;">  elif foldername.endswith(".JPEG"):
</span><span style="color:#323232;">    print(f"Skipping: {foldername}")
</span><span style="color:#323232;">  elif foldername.endswith(".mood"):
</span><span style="color:#323232;">    print(f"Skipping: {foldername}")
</span><span style="color:#323232;">  elif foldername.endswith(".m3u"):
</span><span style="color:#323232;">    print(f"Skipping: {foldername}")
</span><span style="color:#323232;">  elif foldername.endswith(".nfo"):
</span><span style="color:#323232;">    print(f"Skipping: {foldername}")
</span><span style="color:#323232;">  elif foldername.endswith(".png"):
</span><span style="color:#323232;">    print(f"Skipping: {foldername}")
</span><span style="color:#323232;">  elif foldername.endswith(".PNG"):
</span><span style="color:#323232;">    print(f"Skipping: {foldername}")
</span><span style="color:#323232;">  elif foldername.endswith(".sfv"):
</span><span style="color:#323232;">    print(f"Skipping: {foldername}")
</span><span style="color:#323232;">  elif foldername.endswith(".url"):
</span><span style="color:#323232;">    print(f"Skipping: {foldername}")
</span><span style="color:#323232;">  else:
</span><span style="color:#323232;">    folderpath = "/".join([mp3_directory, foldername])
</span><span style="color:#323232;">    print(folderpath)
</span><span style="color:#323232;">
</span><span style="color:#323232;">    for filename in os.listdir(folderpath):
</span><span style="color:#323232;">      if filename.endswith(".mp3"):
</span><span style="color:#323232;">        process_file(filename, folderpath)
</span><span style="color:#323232;">      elif filename.endswith(".DS_Store"):
</span><span style="color:#323232;">        print(f"Skipping: {filename}")
</span><span style="color:#323232;">      elif filename.endswith(".jpg"):
</span><span style="color:#323232;">        print(f"Skipping: {filename}")
</span><span style="color:#323232;">      elif filename.endswith(".JPG"):
</span><span style="color:#323232;">        print(f"Skipping: {filename}")
</span><span style="color:#323232;">      elif filename.endswith(".jpeg"):
</span><span style="color:#323232;">        print(f"Skipping: {filename}")
</span><span style="color:#323232;">      elif filename.endswith(".JPEG"):
</span><span style="color:#323232;">        print(f"Skipping: {filename}")
</span><span style="color:#323232;">      elif filename.endswith(".mood"):
</span><span style="color:#323232;">        print(f"Skipping: {filename}")
</span><span style="color:#323232;">      elif filename.endswith(".m3u"):
</span><span style="color:#323232;">        print(f"Skipping: {filename}")
</span><span style="color:#323232;">      elif filename.endswith(".nfo"):
</span><span style="color:#323232;">        print(f"Skipping: {filename}")
</span><span style="color:#323232;">      elif filename.endswith(".png"):
</span><span style="color:#323232;">        print(f"Skipping: {filename}")
</span><span style="color:#323232;">      elif filename.endswith(".PNG"):
</span><span style="color:#323232;">        print(f"Skipping: {filename}")
</span><span style="color:#323232;">      elif filename.endswith(".sfv"):
</span><span style="color:#323232;">        print(f"Skipping: {filename}")
</span><span style="color:#323232;">      elif filename.endswith(".url"):
</span><span style="color:#323232;">        print(f"Skipping: {filename}")
</span><span style="color:#323232;">      else:
</span><span style="color:#323232;">        foldername2 = "/".join([folderpath,filename])
</span><span style="color:#323232;">        for filename2 in os.listdir(foldername2):
</span><span style="color:#323232;">          if filename2.endswith(".mp3"):
</span><span style="color:#323232;">            if filename2.startswith("A") == False:
</span><span style="color:#323232;">              process_file(filename2, foldername2)
</span><span style="color:#323232;">          elif filename2.endswith(".DS_Store"):
</span><span style="color:#323232;">            print(f"Skipping: {filename2}")
</span><span style="color:#323232;">          elif filename2.endswith(".jpg"):
</span><span style="color:#323232;">            print(f"Skipping: {filename2}")
</span><span style="color:#323232;">          elif filename2.endswith(".JPG"):
</span><span style="color:#323232;">            print(f"Skipping: {filename2}")
</span><span style="color:#323232;">          elif filename2.endswith(".jpeg"):
</span><span style="color:#323232;">            print(f"Skipping: {filename2}")
</span><span style="color:#323232;">          elif filename2.endswith(".JPEG"):
</span><span style="color:#323232;">            print(f"Skipping: {filename2}")
</span><span style="color:#323232;">          elif filename2.endswith(".mood"):
</span><span style="color:#323232;">            print(f"Skipping: {filename2}")
</span><span style="color:#323232;">          elif filename2.endswith(".m3u"):
</span><span style="color:#323232;">            print(f"Skipping: {filename2}")
</span><span style="color:#323232;">          elif filename2.endswith(".nfo"):
</span><span style="color:#323232;">            print(f"Skipping: {filename2}")
</span><span style="color:#323232;">          elif filename2.endswith(".png"):
</span><span style="color:#323232;">            print(f"Skipping: {filename2}")
</span><span style="color:#323232;">          elif filename2.endswith(".PNG"):
</span><span style="color:#323232;">            print(f"Skipping: {filename2}")
</span><span style="color:#323232;">          elif filename2.endswith(".sfv"):
</span><span style="color:#323232;">            print(f"Skipping: {filename2}")
</span><span style="color:#323232;">          elif filename2.endswith(".url"):
</span><span style="color:#323232;">            print(f"Skipping: {filename2}")
</span><span style="color:#323232;">          else:
</span><span style="color:#323232;">            print(f"What is: {filename2}")
</span><span style="color:#323232;">print("Done!")
</span>
ryan_harg,
@ryan_harg@discuss.tchncs.de avatar

Congratulations! Especially with zero experience, this is a big achievement, even with help! Thanks for giving the result back to the community!

sabreW4K3,
@sabreW4K3@lemmy.tf avatar

Thank you so much. I’m low-key super proud of myself.

Deebster,
@Deebster@programming.dev avatar

Congratulations on finishing! And I’m glad you’re sharing this for the next person who wants to do similar.

I see you’re doing a listdir on a listdir - did my for filename in glob.iglob(mp3_directory + ‘/**/*.mp3’, recursive=True): suggestion not work for you?

btw, I didn’t get a notification from the mention, I wonder if you added too many and it ignored them as an anti-spam thing?

sabreW4K3,
@sabreW4K3@lemmy.tf avatar

I had problems because my mp3 directory isn’t set up properly. Before I moved everything over, I had some files in a sleepers folder and another bunch in artist folders. But now that I’m getting everything in place properly, I should switch to your more sane method.

And whaaaa? Bummer! I have no idea why. Maybe a bug with 0.19.x?

  • All
  • Subscribed
  • Moderated
  • Favorites
  • navidrome@discuss.tchncs.de
  • kavyap
  • DreamBathrooms
  • cisconetworking
  • osvaldo12
  • ngwrru68w68
  • magazineikmin
  • thenastyranch
  • Youngstown
  • ethstaker
  • rosin
  • slotface
  • mdbf
  • tacticalgear
  • InstantRegret
  • JUstTest
  • Durango
  • tester
  • everett
  • cubers
  • GTA5RPClips
  • khanakhh
  • provamag3
  • modclub
  • Leos
  • normalnudes
  • megavids
  • anitta
  • lostlight
  • All magazines