Skip to content

Instantly share code, notes, and snippets.

@Maxr1998
Last active October 27, 2024 23:49
Show Gist options
  • Save Maxr1998/7753d52333f5479ff2d95fa35db01268 to your computer and use it in GitHub Desktop.
Save Maxr1998/7753d52333f5479ff2d95fa35db01268 to your computer and use it in GitHub Desktop.
Handles qbzdl:// URLs on Linux (which are otherwise handled by the official Qobuz downloader application on Windows) and generates an aria2 input file to download your purchased tracks.
#!/usr/bin/env python3
import argparse
import mimetypes
import os
import subprocess
import requests
# Configuration
SCHEME = "qbzdl"
API_URL = "https://qobuz.com/v4/downloader/info?token%5B%5D="
DOWNLOAD_CONFIG = "~/qobuz.aria2"
def register_url_handler():
desktop_entry = f"""\
[Desktop Entry]
Name=Qobuz Downloader
Exec=qbzdl handle %u
Type=Application
NoDisplay=true
MimeType=x-scheme-handler/{SCHEME};
"""
desktop_path = os.path.expanduser(f"~/.local/share/applications/{SCHEME}-handler.desktop")
with open(desktop_path, "w") as f:
f.write(desktop_entry)
subprocess.run(["xdg-mime", "default", f"{SCHEME}-handler.desktop", f"x-scheme-handler/{SCHEME}"])
print(f"URL handler for {SCHEME} registered.")
def init_mime():
mimetypes.init()
mimetypes.add_type("audio/flac", ".flac", strict=True)
mimetypes.add_type("audio/mpeg", ".mp3", strict=True)
def handle_url(url):
init_mime()
query = url.split(f"{SCHEME}://")[1]
response = requests.get(f"{API_URL}{query}").json()
try:
data = response[0]
albums = {album["id"]: album for album in data["metadata"]["albums"]}
tracks = {track["id"]: track for track in data["metadata"]["tracks"]}
audios = []
for audio in data["audios"]:
track_id = audio["track_id"]
track = tracks.get(track_id)
if not track:
print(f"Skipping track [{track_id}] missing from metadata")
continue
track_position = track["track_position"]
title = track["title"]
album_id = track["album"]["id"]
album = albums.get(album_id)
if not album:
print(f'Skipping track "{title}" due to album [{album_id}] missing from metadata')
continue
extension = mimetypes.guess_extension(audio.get("mime_type") or "audio/flac")
audios.append(
{
"title": f"{track_position:02d} {title}{extension}",
"album": album["title"],
"url": audio["url"],
}
)
with open(os.path.expanduser(DOWNLOAD_CONFIG), "w") as f:
f.write("# Generated by qbzdl\n\n")
for audio in audios:
f.write(audio["url"] + "\n")
out_path = os.path.join("albums", audio["album"], audio['title'])
f.write(f" out={out_path}\n")
subprocess.run(["notify-send", f"Download configuration written to {DOWNLOAD_CONFIG}"])
except KeyError as e:
print(f"Error processing data: Missing key {e}")
def main():
parser = argparse.ArgumentParser(description="Qobuz Downloader")
subparsers = parser.add_subparsers()
parser_register = subparsers.add_parser("register", help="Register the qbzdl URL handler")
parser_register.set_defaults(action="register")
parser_handle_url = subparsers.add_parser("handle", help="Handle a qbzdl:// URL")
parser_handle_url.set_defaults(action="handle-url")
parser_handle_url.add_argument("url", help="The qbzdl:// URL to handle")
args = parser.parse_args()
if args.action == "register":
register_url_handler()
elif args.action == "handle-url":
assert args.url
handle_url(args.url)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment