gamdl 3.2__tar.gz → 3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gamdl-3.2 → gamdl-3.4}/PKG-INFO +1 -1
- gamdl-3.4/gamdl/__init__.py +1 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/cli/cli.py +6 -14
- {gamdl-3.2 → gamdl-3.4}/gamdl/cli/database.py +12 -2
- {gamdl-3.2 → gamdl-3.4}/gamdl/cli/utils.py +25 -2
- {gamdl-3.2 → gamdl-3.4}/gamdl/downloader/downloader.py +3 -2
- {gamdl-3.2 → gamdl-3.4}/gamdl/downloader/types.py +2 -2
- {gamdl-3.2 → gamdl-3.4}/gamdl/interface/base.py +8 -4
- {gamdl-3.2 → gamdl-3.4}/gamdl/interface/exceptions.py +3 -1
- {gamdl-3.2 → gamdl-3.4}/gamdl/interface/interface.py +0 -2
- {gamdl-3.2 → gamdl-3.4}/gamdl/utils.py +14 -5
- {gamdl-3.2 → gamdl-3.4}/gamdl.egg-info/PKG-INFO +1 -1
- {gamdl-3.2 → gamdl-3.4}/pyproject.toml +1 -1
- gamdl-3.2/gamdl/__init__.py +0 -1
- {gamdl-3.2 → gamdl-3.4}/LICENSE +0 -0
- {gamdl-3.2 → gamdl-3.4}/README.md +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/__main__.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/api/__init__.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/api/apple_music.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/api/constants.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/api/exceptions.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/api/itunes.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/cli/__init__.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/cli/cli_config.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/cli/config_file.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/cli/constants.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/cli/interactive_prompts.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/downloader/__init__.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/downloader/amdecrypt.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/downloader/base.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/downloader/constants.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/downloader/enums.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/downloader/exceptions.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/downloader/music_video.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/downloader/song.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/downloader/uploaded_video.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/interface/__init__.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/interface/constants.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/interface/enums.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/interface/music_video.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/interface/song.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/interface/types.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/interface/uploaded_video.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl/interface/wvd.py +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl.egg-info/SOURCES.txt +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl.egg-info/dependency_links.txt +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl.egg-info/entry_points.txt +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl.egg-info/requires.txt +0 -0
- {gamdl-3.2 → gamdl-3.4}/gamdl.egg-info/top_level.txt +0 -0
- {gamdl-3.2 → gamdl-3.4}/setup.cfg +0 -0
{gamdl-3.2 → gamdl-3.4}/PKG-INFO
RENAMED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "3.4"
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import logging
|
|
3
2
|
from functools import wraps
|
|
4
3
|
from pathlib import Path
|
|
5
4
|
|
|
@@ -38,7 +37,7 @@ from .cli_config import CliConfig
|
|
|
38
37
|
from .config_file import ConfigFile
|
|
39
38
|
from .database import Database
|
|
40
39
|
from .interactive_prompts import InteractivePrompts
|
|
41
|
-
from .utils import custom_structlog_formatter, prompt_path
|
|
40
|
+
from .utils import CustomOutputWriter, custom_structlog_formatter, prompt_path
|
|
42
41
|
|
|
43
42
|
logger = structlog.get_logger(__name__)
|
|
44
43
|
|
|
@@ -60,18 +59,10 @@ def make_sync(func):
|
|
|
60
59
|
async def main(config: CliConfig):
|
|
61
60
|
colorama.just_fix_windows_console()
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
root_logger.setLevel(config.log_level)
|
|
65
|
-
root_logger.propagate = False
|
|
66
|
-
|
|
67
|
-
stream_handler = logging.StreamHandler()
|
|
68
|
-
stream_handler.setFormatter(logging.Formatter("%(message)s"))
|
|
69
|
-
root_logger.addHandler(stream_handler)
|
|
62
|
+
log_output = CustomOutputWriter()
|
|
70
63
|
|
|
71
64
|
if config.log_file:
|
|
72
|
-
|
|
73
|
-
file_handler.setFormatter(logging.Formatter("%(message)s"))
|
|
74
|
-
root_logger.addHandler(file_handler)
|
|
65
|
+
log_output.add_file(config.log_file)
|
|
75
66
|
|
|
76
67
|
structlog.configure(
|
|
77
68
|
processors=[
|
|
@@ -79,7 +70,8 @@ async def main(config: CliConfig):
|
|
|
79
70
|
structlog.processors.ExceptionPrettyPrinter(),
|
|
80
71
|
custom_structlog_formatter,
|
|
81
72
|
],
|
|
82
|
-
logger_factory=structlog.
|
|
73
|
+
logger_factory=structlog.PrintLoggerFactory(file=log_output),
|
|
74
|
+
wrapper_class=structlog.make_filtering_bound_logger(config.log_level),
|
|
83
75
|
)
|
|
84
76
|
|
|
85
77
|
logger.info(f"Starting Gamdl {__version__}")
|
|
@@ -127,7 +119,7 @@ async def main(config: CliConfig):
|
|
|
127
119
|
)
|
|
128
120
|
|
|
129
121
|
if config.database_path:
|
|
130
|
-
database = Database(config.database_path)
|
|
122
|
+
database = Database(config.database_path, config.overwrite)
|
|
131
123
|
flat_filter = database.flat_filter
|
|
132
124
|
else:
|
|
133
125
|
database = None
|
|
@@ -3,7 +3,13 @@ from pathlib import Path
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class Database:
|
|
6
|
-
def __init__(
|
|
6
|
+
def __init__(
|
|
7
|
+
self,
|
|
8
|
+
path: Path,
|
|
9
|
+
overwrite: bool,
|
|
10
|
+
):
|
|
11
|
+
self.overwrite = overwrite
|
|
12
|
+
|
|
7
13
|
self.connection = sqlite3.connect(path)
|
|
8
14
|
self.cursor = self.connection.cursor()
|
|
9
15
|
self._create_tables()
|
|
@@ -45,4 +51,8 @@ class Database:
|
|
|
45
51
|
if not result:
|
|
46
52
|
return None
|
|
47
53
|
|
|
48
|
-
return
|
|
54
|
+
return (
|
|
55
|
+
"Registered in database"
|
|
56
|
+
if Path(result).exists() and not self.overwrite
|
|
57
|
+
else None
|
|
58
|
+
)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import atexit
|
|
2
|
+
import sys
|
|
1
3
|
from datetime import datetime
|
|
2
4
|
from enum import Enum
|
|
3
5
|
from pathlib import Path
|
|
@@ -39,12 +41,33 @@ class Csv(click.ParamType):
|
|
|
39
41
|
return result
|
|
40
42
|
|
|
41
43
|
|
|
44
|
+
class CustomOutputWriter:
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
streams: list[Any] = [sys.stdout],
|
|
48
|
+
):
|
|
49
|
+
self.streams = streams
|
|
50
|
+
|
|
51
|
+
def add_file(self, path: str):
|
|
52
|
+
file_stream = open(path, "a")
|
|
53
|
+
atexit.register(file_stream.close)
|
|
54
|
+
self.streams.append(file_stream)
|
|
55
|
+
|
|
56
|
+
def write(self, message: str):
|
|
57
|
+
for stream in self.streams:
|
|
58
|
+
stream.write(message)
|
|
59
|
+
|
|
60
|
+
def flush(self):
|
|
61
|
+
for stream in self.streams:
|
|
62
|
+
stream.flush()
|
|
63
|
+
|
|
64
|
+
|
|
42
65
|
def custom_structlog_formatter(
|
|
43
66
|
logger: Any,
|
|
44
67
|
name: str,
|
|
45
68
|
event_dict: dict[str, Any],
|
|
46
69
|
) -> str:
|
|
47
|
-
level = event_dict.
|
|
70
|
+
level = event_dict.pop("level", "INFO").upper()
|
|
48
71
|
timestamp = datetime.now().strftime("%H:%M:%S")
|
|
49
72
|
|
|
50
73
|
level_colors = {
|
|
@@ -63,7 +86,7 @@ def custom_structlog_formatter(
|
|
|
63
86
|
prefix += click.style(f" [{action}]", dim=True)
|
|
64
87
|
|
|
65
88
|
if level in {"INFO", "WARNING", "ERROR", "CRITICAL"}:
|
|
66
|
-
message = event_dict.
|
|
89
|
+
message = event_dict.pop("event", "")
|
|
67
90
|
return f"{prefix} {message}"
|
|
68
91
|
else:
|
|
69
92
|
return f"{prefix} {event_dict}"
|
|
@@ -88,7 +88,8 @@ class AppleMusicDownloader:
|
|
|
88
88
|
await self._download(item)
|
|
89
89
|
await self._final_processing(item)
|
|
90
90
|
finally:
|
|
91
|
-
self.
|
|
91
|
+
if not self.skip_cleanup:
|
|
92
|
+
self._cleanup_temp(item.uuid_)
|
|
92
93
|
|
|
93
94
|
def _update_playlist_file(
|
|
94
95
|
self,
|
|
@@ -263,6 +264,6 @@ class AppleMusicDownloader:
|
|
|
263
264
|
log = logger.bind(action="cleanup_temp", folder_tag=folder_tag)
|
|
264
265
|
|
|
265
266
|
temp_path = Path(self.base.temp_path) / TEMP_PATH_TEMPLATE.format(folder_tag)
|
|
266
|
-
if temp_path.exists() and temp_path.is_dir()
|
|
267
|
+
if temp_path.exists() and temp_path.is_dir():
|
|
267
268
|
shutil.rmtree(temp_path, ignore_errors=True)
|
|
268
269
|
log.debug("success")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import uuid
|
|
2
|
-
from dataclasses import dataclass
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
3
|
|
|
4
4
|
from ..interface.types import AppleMusicMedia
|
|
5
5
|
|
|
@@ -7,7 +7,7 @@ from ..interface.types import AppleMusicMedia
|
|
|
7
7
|
@dataclass
|
|
8
8
|
class DownloadItem:
|
|
9
9
|
media: AppleMusicMedia
|
|
10
|
-
uuid_: str = uuid.uuid4().hex[:8]
|
|
10
|
+
uuid_: str = field(default_factory=lambda: uuid.uuid4().hex[:8])
|
|
11
11
|
staged_path: str = None
|
|
12
12
|
final_path: str = None
|
|
13
13
|
playlist_file_path: str = None
|
|
@@ -223,12 +223,16 @@ class AppleMusicBaseInterface:
|
|
|
223
223
|
|
|
224
224
|
def _get_raw_cover_url(self, cover_url_template: str) -> str:
|
|
225
225
|
return re.sub(
|
|
226
|
-
r"
|
|
226
|
+
r"/\{w\}x\{h\}bb\.jpg",
|
|
227
227
|
"",
|
|
228
228
|
re.sub(
|
|
229
|
-
r"
|
|
230
|
-
"
|
|
231
|
-
|
|
229
|
+
r"image/thumb/",
|
|
230
|
+
"",
|
|
231
|
+
re.sub(
|
|
232
|
+
r"is1-ssl",
|
|
233
|
+
"a1",
|
|
234
|
+
cover_url_template,
|
|
235
|
+
),
|
|
232
236
|
),
|
|
233
237
|
)
|
|
234
238
|
|
|
@@ -46,6 +46,8 @@ class GamdlInterfaceArtistMediaTypeError(GamdlInterfaceError):
|
|
|
46
46
|
|
|
47
47
|
class GamdlInterfaceFlatFilterExcludedError(GamdlInterfaceError):
|
|
48
48
|
def __init__(self, media_id: str, result: Any):
|
|
49
|
-
super().__init__(
|
|
49
|
+
super().__init__(
|
|
50
|
+
f"Media excluded by flat filter (media ID: {media_id}): {result}"
|
|
51
|
+
)
|
|
50
52
|
|
|
51
53
|
self.result = result
|
|
@@ -281,7 +281,6 @@ class AppleMusicInterface:
|
|
|
281
281
|
self._get_song_media(
|
|
282
282
|
media_id=track["id"],
|
|
283
283
|
index=index,
|
|
284
|
-
total=base_media.media_metadata["attributes"]["trackCount"],
|
|
285
284
|
media_metadata=track,
|
|
286
285
|
playlist_metadata=base_media.media_metadata,
|
|
287
286
|
)
|
|
@@ -289,7 +288,6 @@ class AppleMusicInterface:
|
|
|
289
288
|
else self._get_music_video_media(
|
|
290
289
|
media_id=track["id"],
|
|
291
290
|
index=index,
|
|
292
|
-
total=base_media.media_metadata["attributes"]["trackCount"],
|
|
293
291
|
media_metadata=track,
|
|
294
292
|
playlist_metadata=base_media.media_metadata,
|
|
295
293
|
)
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import string
|
|
3
|
-
import subprocess
|
|
4
3
|
import typing
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
async def async_subprocess(*args: str, silent: bool = False) -> None:
|
|
8
7
|
if silent:
|
|
9
8
|
additional_args = {
|
|
10
|
-
"stdout": subprocess.
|
|
11
|
-
"stderr": subprocess.
|
|
9
|
+
"stdout": asyncio.subprocess.PIPE,
|
|
10
|
+
"stderr": asyncio.subprocess.PIPE,
|
|
12
11
|
}
|
|
13
12
|
else:
|
|
14
13
|
additional_args = {}
|
|
@@ -17,10 +16,20 @@ async def async_subprocess(*args: str, silent: bool = False) -> None:
|
|
|
17
16
|
*args,
|
|
18
17
|
**additional_args,
|
|
19
18
|
)
|
|
20
|
-
|
|
19
|
+
|
|
20
|
+
stdout, stderr = await proc.communicate()
|
|
21
21
|
|
|
22
22
|
if proc.returncode != 0:
|
|
23
|
-
|
|
23
|
+
msg = (
|
|
24
|
+
f"Exited with code {proc.returncode}: {' '.join(str(arg) for arg in args)}"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if stdout:
|
|
28
|
+
msg += f"\nstdout:\n{stdout.decode()}"
|
|
29
|
+
if stderr:
|
|
30
|
+
msg += f"\nstderr:\n{stderr.decode()}"
|
|
31
|
+
|
|
32
|
+
raise Exception(msg)
|
|
24
33
|
|
|
25
34
|
|
|
26
35
|
async def safe_gather(
|
gamdl-3.2/gamdl/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "3.2"
|
{gamdl-3.2 → gamdl-3.4}/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|