Moved to uv, not convinced. Added ConfigParser and Argparser
This commit is contained in:
parent
41b363bb37
commit
52e1bfbfed
4 changed files with 80 additions and 32 deletions
|
@ -1,16 +1,23 @@
|
||||||
[project]
|
[project]
|
||||||
name = "qobuz-dl-remote"
|
name = "qobuz-dl-remote"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
description = "Add your description here"
|
||||||
|
readme = "README.md"
|
||||||
authors = [
|
authors = [
|
||||||
{ name = "Christoph Stahl", email = "christoph.stahl@tu-dortmund.de" }
|
{ name = "Christoph Stahl", email = "christoph.stahl@tu-dortmund.de" }
|
||||||
]
|
]
|
||||||
description = "Add your description here"
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"music-tag>=0.4.3",
|
"musicbrainzngs>=0.7.1",
|
||||||
"mutagen>=1.47.0",
|
"mutagen>=1.47.0",
|
||||||
"pillow>=11.3.0",
|
"pillow>=11.3.0",
|
||||||
"requests>=2.32.4",
|
"requests>=2.32.4",
|
||||||
"tqdm>=4.67.1",
|
"tqdm>=4.67.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
qobuz-dl-remote = "qobuz_dl_remote.main:main"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["uv_build>=0.8.4,<0.9.0"]
|
||||||
|
build-backend = "uv_build"
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
#!/usr/bin/env python3
|
import datetime
|
||||||
import os
|
import os
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from io import BytesIO
|
||||||
from typing import Any, Literal
|
from typing import Any, Literal
|
||||||
|
from configparser import ConfigParser
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import tqdm
|
import tqdm
|
||||||
|
from mutagen.flac import FLAC, Picture
|
||||||
import music_tag
|
from PIL import Image
|
||||||
import sys
|
|
||||||
from dataclasses import dataclass
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
QOBUZ_API_BASE = "https://us.qobuz.squid.wtf/api"
|
|
||||||
QUALITY = 27
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -93,12 +92,12 @@ class Album:
|
||||||
|
|
||||||
|
|
||||||
class Qobuz:
|
class Qobuz:
|
||||||
def __init__(self, api_base=QOBUZ_API_BASE, quality: int = QUALITY) -> None:
|
def __init__(self, api_base, quality: int) -> None:
|
||||||
self.api_base = api_base
|
self.api_base = api_base
|
||||||
self.quality = quality
|
self.quality = quality
|
||||||
|
|
||||||
def get_download_url(self, track_id: str) -> str:
|
def get_download_url(self, track_id: str) -> str:
|
||||||
url = f"{QOBUZ_API_BASE}/download-music"
|
url = f"{self.api_base}/download-music"
|
||||||
result = requests.get(
|
result = requests.get(
|
||||||
url, params={"track_id": track_id, "quality": self.quality}
|
url, params={"track_id": track_id, "quality": self.quality}
|
||||||
)
|
)
|
||||||
|
@ -110,24 +109,35 @@ class Qobuz:
|
||||||
|
|
||||||
def download_track(self, track: Track, filename: str, dest: str) -> None:
|
def download_track(self, track: Track, filename: str, dest: str) -> None:
|
||||||
download_url = self.get_download_url(track.id)
|
download_url = self.get_download_url(track.id)
|
||||||
|
dest_path = os.path.join(dest, filename)
|
||||||
response = requests.get(download_url, stream=True)
|
response = requests.get(download_url, stream=True)
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
total_size = int(response.headers.get("content-length", 0))
|
total_size = int(response.headers.get("content-length", 0))
|
||||||
with tqdm.tqdm(
|
with tqdm.tqdm(
|
||||||
total=total_size, unit="B", unit_scale=True, desc=filename
|
total=total_size, unit="B", unit_scale=True, desc=filename
|
||||||
) as pbar:
|
) as pbar:
|
||||||
with open(os.path.join(dest, filename), "wb") as file:
|
with open(dest_path, "wb") as file:
|
||||||
for chunk in response.iter_content(chunk_size=8192):
|
for chunk in response.iter_content(chunk_size=8192):
|
||||||
file.write(chunk)
|
file.write(chunk)
|
||||||
pbar.update(len(chunk))
|
pbar.update(len(chunk))
|
||||||
# Set metadata using mutagen
|
# Set metadata using mutagen
|
||||||
audio = music_tag.load_file(filename)
|
audio = FLAC(dest_path)
|
||||||
audio["tracktitle"] = track.title
|
audio["title"] = track.title
|
||||||
audio["artist"] = track.album.artist
|
audio["artist"] = track.album.artist
|
||||||
audio["tracknumber"] = str(track.nr)
|
audio["tracknumber"] = str(track.nr)
|
||||||
audio["album"] = track.album.title
|
audio["album"] = track.album.title
|
||||||
audio["year"] = track.album.release_date.year
|
audio["release_date"] = track.album.release_date.isoformat()
|
||||||
audio["artwork"] = track.album.cover_data
|
if track.album.cover_data is not None:
|
||||||
|
picture = Picture()
|
||||||
|
pil_image = Image.open(BytesIO(track.album.cover_data))
|
||||||
|
picture.type = 3 # Front cover
|
||||||
|
picture.data = track.album.cover_data
|
||||||
|
picture.mime = pil_image.get_format_mimetype()
|
||||||
|
picture.desc = "Cover"
|
||||||
|
picture.width = pil_image.width
|
||||||
|
picture.height = pil_image.height
|
||||||
|
picture.depth = len(pil_image.getbands()) * 8
|
||||||
|
audio.add_picture(picture)
|
||||||
audio.save()
|
audio.save()
|
||||||
|
|
||||||
print(f"Downloaded {filename}")
|
print(f"Downloaded {filename}")
|
||||||
|
@ -167,11 +177,42 @@ class Qobuz:
|
||||||
self.download_album(album, f"{album.artist} - {album.title}")
|
self.download_album(album, f"{album.artist} - {album.title}")
|
||||||
|
|
||||||
|
|
||||||
|
def get_config() -> ConfigParser:
|
||||||
|
config = ConfigParser()
|
||||||
|
if os.path.exists("config.ini"):
|
||||||
|
config_file = "config.ini"
|
||||||
|
else:
|
||||||
|
config_file = os.path.expanduser("~/.config/qobuz_dl_remote/config.ini")
|
||||||
|
if not os.path.exists(config_file):
|
||||||
|
raise FileNotFoundError(f"Config file not found: {config_file}")
|
||||||
|
config.read(config_file)
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
# trackid = sys.argv[1]
|
config = get_config()
|
||||||
# filename = sys.argv[2]
|
base_url = config.get("qobuz", "api_base")
|
||||||
query = sys.argv[1]
|
if not base_url:
|
||||||
qb = Qobuz()
|
print("No API base URL configured, please set api_base under [qobuz].")
|
||||||
|
quality = config.getint("qobuz", "quality", fallback=27)
|
||||||
|
|
||||||
|
parser = ArgumentParser(description="Qobuz Remote Downloader")
|
||||||
|
parser.add_argument(
|
||||||
|
"--type",
|
||||||
|
"-t",
|
||||||
|
type=str,
|
||||||
|
choices=["album", "discography"],
|
||||||
|
default="album",
|
||||||
|
help="Type of search to perform",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"query", type=str, help="Search query for the album to download"
|
||||||
|
)
|
||||||
|
parser.add_argument("--beet", "-b", action="store_true", help="Import into Beet")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
query = args.query
|
||||||
|
qb = Qobuz(api_base=base_url, quality=quality)
|
||||||
print(qb.search_and_download(query))
|
print(qb.search_and_download(query))
|
||||||
|
|
||||||
|
|
16
uv.lock
generated
16
uv.lock
generated
|
@ -94,13 +94,13 @@ wheels = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "music-tag"
|
name = "musicbrainzngs"
|
||||||
version = "0.4.3"
|
version = "0.7.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
sdist = { url = "https://files.pythonhosted.org/packages/0a/67/3e74ae93d90ceeba72ed1a266dd3ca9abd625f315f0afd35f9b034acedd1/musicbrainzngs-0.7.1.tar.gz", hash = "sha256:ab1c0100fd0b305852e65f2ed4113c6de12e68afd55186987b8ed97e0f98e627", size = 117469, upload-time = "2020-01-11T17:38:47.581Z" }
|
||||||
{ name = "mutagen" },
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6d/fd/cef7b2580436910ccd2f8d3deec0f3c81743e15c0eb5b97dde3fbf33c0c8/musicbrainzngs-0.7.1-py2.py3-none-any.whl", hash = "sha256:e841a8f975104c0a72290b09f59326050194081a5ae62ee512f41915090e1a10", size = 25289, upload-time = "2020-01-11T17:38:45.469Z" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/fc/f4/ebcdd2fc9bfaf569b795250090e4f4088dc65a5a3e32c53baa9bfc3fc296/music-tag-0.4.3.tar.gz", hash = "sha256:0aab6e6eeda8df0f5316ec2d2190bd74561b7e03562ab091ce8d5687cdbcfff6", size = 23153, upload-time = "2021-06-05T17:20:23.552Z" }
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mutagen"
|
name = "mutagen"
|
||||||
|
@ -216,9 +216,9 @@ wheels = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "qobuz-dl-remote"
|
name = "qobuz-dl-remote"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = { virtual = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "music-tag" },
|
{ name = "musicbrainzngs" },
|
||||||
{ name = "mutagen" },
|
{ name = "mutagen" },
|
||||||
{ name = "pillow" },
|
{ name = "pillow" },
|
||||||
{ name = "requests" },
|
{ name = "requests" },
|
||||||
|
@ -227,7 +227,7 @@ dependencies = [
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "music-tag", specifier = ">=0.4.3" },
|
{ name = "musicbrainzngs", specifier = ">=0.7.1" },
|
||||||
{ name = "mutagen", specifier = ">=1.47.0" },
|
{ name = "mutagen", specifier = ">=1.47.0" },
|
||||||
{ name = "pillow", specifier = ">=11.3.0" },
|
{ name = "pillow", specifier = ">=11.3.0" },
|
||||||
{ name = "requests", specifier = ">=2.32.4" },
|
{ name = "requests", specifier = ">=2.32.4" },
|
||||||
|
|
Loading…
Add table
Reference in a new issue