mirror of
https://github.com/glomatico/gamdl.git
synced 2026-06-13 20:25:13 +03:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2001b19d8f | |||
| 14814dd2da | |||
| 6fad41467f | |||
| 0868f1c28c | |||
| a964011507 | |||
| 3a943d0154 | |||
| 84bf0a3c2b | |||
| 93dda6889c |
@@ -11,7 +11,7 @@ A Python CLI app for downloading Apple Music songs, music videos and post videos
|
||||
* **Highly Customizable**: Extensive configuration options for advanced users.
|
||||
|
||||
## Prerequisites
|
||||
* **Python 3.8 or higher** installed on your system.
|
||||
* **Python 3.9 or higher** installed on your system.
|
||||
* The **cookies file** of your Apple Music browser session in Netscape format (requires an active subscription).
|
||||
* **Firefox**: Use the [Export Cookies](https://addons.mozilla.org/addon/export-cookies-txt) extension.
|
||||
* **Chromium-based Browsers**: Use the [Open Cookies.txt](https://chromewebstore.google.com/detail/open-cookiestxt/gdocmgbfkjnnpapoeobnolbbkoibbcif) extension.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__ = "2.3.9"
|
||||
__version__ = "2.4"
|
||||
|
||||
@@ -37,6 +37,9 @@ class AppleMusicApi:
|
||||
cookies.load(ignore_discard=True, ignore_expires=True)
|
||||
self.session.cookies.update(cookies)
|
||||
self.storefront = self.session.cookies.get_dict()["itua"]
|
||||
media_user_token = self.session.cookies.get_dict()["media-user-token"]
|
||||
else:
|
||||
media_user_token = ""
|
||||
self.session.headers.update(
|
||||
{
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0",
|
||||
@@ -44,9 +47,7 @@ class AppleMusicApi:
|
||||
"Accept-Language": "en-US,en;q=0.5",
|
||||
"Accept-Encoding": "gzip, deflate, br",
|
||||
"content-type": "application/json",
|
||||
"Media-User-Token": self.session.cookies.get_dict().get(
|
||||
"media-user-token", ""
|
||||
),
|
||||
"Media-User-Token": media_user_token,
|
||||
"x-apple-renewal": "true",
|
||||
"DNT": "1",
|
||||
"Connection": "keep-alive",
|
||||
|
||||
+18
-9
@@ -7,10 +7,12 @@ from enum import Enum
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
from termcolor import colored
|
||||
|
||||
from . import __version__
|
||||
from .apple_music_api import AppleMusicApi
|
||||
from .constants import *
|
||||
from .custom_formatter import CustomFormatter
|
||||
from .downloader import Downloader
|
||||
from .downloader_music_video import DownloaderMusicVideo
|
||||
from .downloader_post import DownloaderPost
|
||||
@@ -348,16 +350,20 @@ def main(
|
||||
quality_post: PostQuality,
|
||||
no_config_file: bool,
|
||||
):
|
||||
logging.basicConfig(
|
||||
format="[%(levelname)-8s %(asctime)s] %(message)s",
|
||||
datefmt="%H:%M:%S",
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(log_level)
|
||||
stream_handler = logging.StreamHandler()
|
||||
stream_handler.setFormatter(CustomFormatter())
|
||||
logger.addHandler(stream_handler)
|
||||
logger.info("Starting Gamdl")
|
||||
if not cookies_path.exists():
|
||||
logger.critical(X_NOT_FOUND_STRING.format("Cookies file", cookies_path))
|
||||
return
|
||||
while not cookies_path.exists():
|
||||
cookies_path_str = click.prompt(
|
||||
X_NOT_FOUND_STRING.format("Cookies file", cookies_path.absolute())
|
||||
+ ". Move it to that location or drag and drop it here. Then, press enter to continue",
|
||||
default=str(cookies_path),
|
||||
show_default=False,
|
||||
)
|
||||
cookies_path = Path(cookies_path_str.strip('"'))
|
||||
apple_music_api = AppleMusicApi(
|
||||
cookies_path,
|
||||
language=language,
|
||||
@@ -460,7 +466,7 @@ def main(
|
||||
_urls.extend(Path(url).read_text(encoding="utf-8").splitlines())
|
||||
urls = _urls
|
||||
for url_index, url in enumerate(urls, start=1):
|
||||
url_progress = f"URL {url_index}/{len(urls)}"
|
||||
url_progress = colored(f"URL {url_index}/{len(urls)}", "grey")
|
||||
try:
|
||||
logger.info(f'({url_progress}) Checking "{url}"')
|
||||
url_info = downloader.get_url_info(url)
|
||||
@@ -476,7 +482,10 @@ def main(
|
||||
for download_index, track_metadata in enumerate(
|
||||
download_queue_tracks_metadata, start=1
|
||||
):
|
||||
queue_progress = f"Track {download_index}/{len(download_queue_tracks_metadata)} from URL {url_index}/{len(urls)}"
|
||||
queue_progress = colored(
|
||||
f"Track {download_index}/{len(download_queue_tracks_metadata)} from URL {url_index}/{len(urls)}",
|
||||
"grey",
|
||||
)
|
||||
try:
|
||||
remuxed_path = None
|
||||
if download_queue.playlist_attributes:
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import logging
|
||||
from termcolor import colored
|
||||
|
||||
|
||||
class CustomFormatter(logging.Formatter):
|
||||
basic_format = "[%(levelname)-8s %(asctime)s]"
|
||||
formats = {
|
||||
logging.DEBUG: colored(basic_format, "grey"),
|
||||
logging.INFO: colored(basic_format, "green"),
|
||||
logging.WARNING: colored(basic_format, "yellow"),
|
||||
logging.ERROR: colored(basic_format, "red"),
|
||||
logging.CRITICAL: colored(basic_format, "red"),
|
||||
}
|
||||
date_format = "%H:%M:%S"
|
||||
|
||||
def format(self, record: logging.LogRecord) -> str:
|
||||
return logging.Formatter(
|
||||
self.formats.get(record.levelno) + " %(message)s",
|
||||
datefmt=self.date_format,
|
||||
).format(record)
|
||||
@@ -176,7 +176,10 @@ class DownloaderSong:
|
||||
secs = float(f"{mins_secs_ms[-2]}.{mins_secs_ms[-1]}")
|
||||
if len(mins_secs_ms) > 2:
|
||||
mins = int(mins_secs_ms[-3])
|
||||
return datetime.datetime.fromtimestamp((mins * 60) + secs + (ms / 1000))
|
||||
return datetime.datetime.fromtimestamp(
|
||||
(mins * 60) + secs + (ms / 1000),
|
||||
tz=datetime.timezone.utc,
|
||||
)
|
||||
|
||||
def get_lyrics_synced_timestamp_lrc(self, timestamp_ttml: str) -> str:
|
||||
datetime_obj = self.parse_datetime_obj_from_timestamp_ttml(timestamp_ttml)
|
||||
|
||||
@@ -11,6 +11,7 @@ dependencies = [
|
||||
"pillow",
|
||||
"pywidevine",
|
||||
"pyyaml",
|
||||
"termcolor",
|
||||
"yt-dlp",
|
||||
]
|
||||
readme = "README.md"
|
||||
|
||||
@@ -5,4 +5,5 @@ mutagen
|
||||
pillow
|
||||
pywidevine
|
||||
pyyaml
|
||||
termcolor
|
||||
yt-dlp
|
||||
|
||||
Reference in New Issue
Block a user