anipy-cli 3.5.3__tar.gz → 3.5.5__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.
Potentially problematic release.
This version of anipy-cli might be problematic. Click here for more details.
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/PKG-INFO +2 -2
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/pyproject.toml +2 -2
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/__init__.py +1 -1
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/clis/base_cli.py +1 -1
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/clis/download_cli.py +6 -2
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/config.py +2 -2
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/download_component.py +4 -5
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/menus/menu.py +10 -5
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/menus/seasonal_menu.py +9 -7
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/util.py +15 -13
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/README.md +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/arg_parser.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/cli.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/clis/__init__.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/clis/binge_cli.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/clis/default_cli.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/clis/history_cli.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/clis/mal_cli.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/clis/seasonal_cli.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/colors.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/discord.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/mal_proxy.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/menus/__init__.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/menus/base_menu.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/menus/mal_menu.py +0 -0
- {anipy_cli-3.5.3 → anipy_cli-3.5.5}/src/anipy_cli/prompts.py +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: anipy-cli
|
|
3
|
-
Version: 3.5.
|
|
3
|
+
Version: 3.5.5
|
|
4
4
|
Summary: Watch and Download anime from the comfort of your Terminal
|
|
5
5
|
License: GPL-3.0
|
|
6
6
|
Keywords: anime,cli
|
|
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
-
Requires-Dist: anipy-api (>=3.5.
|
|
17
|
+
Requires-Dist: anipy-api (>=3.5.5,<4.0.0)
|
|
18
18
|
Requires-Dist: appdirs (>=1.4.4,<2.0.0)
|
|
19
19
|
Requires-Dist: inquirerpy (>=0.3.4,<0.4.0)
|
|
20
20
|
Requires-Dist: pypresence (>=4.3.0,<5.0.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "anipy-cli"
|
|
3
|
-
version = "3.5.
|
|
3
|
+
version = "3.5.5"
|
|
4
4
|
description = "Watch and Download anime from the comfort of your Terminal"
|
|
5
5
|
authors = ["sdaqo <sdaqo.dev@protonmail.com>"]
|
|
6
6
|
license = "GPL-3.0"
|
|
@@ -20,7 +20,7 @@ yaspin = "^3.0.2"
|
|
|
20
20
|
inquirerpy = "^0.3.4"
|
|
21
21
|
appdirs = "^1.4.4"
|
|
22
22
|
pypresence = "^4.3.0"
|
|
23
|
-
anipy-api = "^3.5.
|
|
23
|
+
anipy-api = "^3.5.5"
|
|
24
24
|
|
|
25
25
|
[tool.poetry.scripts]
|
|
26
26
|
anipy-cli = "anipy_cli.cli:run_cli"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__appname__ = "anipy-cli"
|
|
2
|
-
__version__ = "3.5.
|
|
2
|
+
__version__ = "3.5.5"
|
|
@@ -69,8 +69,12 @@ class DownloadCli(CliBase):
|
|
|
69
69
|
assert self.anime is not None
|
|
70
70
|
assert self.lang is not None
|
|
71
71
|
|
|
72
|
-
errors = DownloadComponent(
|
|
73
|
-
|
|
72
|
+
errors = DownloadComponent(
|
|
73
|
+
self.options, self.dl_path, "download"
|
|
74
|
+
).download_anime(
|
|
75
|
+
[(self.anime, self.lang, self.episodes)],
|
|
76
|
+
only_skip_ep_on_err=True,
|
|
77
|
+
sub_only=self.options.subtitles,
|
|
74
78
|
)
|
|
75
79
|
DownloadComponent.serve_download_errors(errors, only_skip_ep_on_err=True)
|
|
76
80
|
|
|
@@ -228,7 +228,7 @@ class Config:
|
|
|
228
228
|
has been downloaded. As with the 'providers' option, you can configure
|
|
229
229
|
different behaviour, depending on which part of anipy-cli the download occurs.
|
|
230
230
|
Configurable areas are as follows: default (and history), download (-D), seasonal (-S)
|
|
231
|
-
and mal (-M). The example will show you how it is done! Please note that if you define
|
|
231
|
+
and mal (-M). The example will show you how it is done! Please note that if you define
|
|
232
232
|
several scripts for one area, they will run in the order you put them in the list.
|
|
233
233
|
You can also define a timeout (in seconds), after which a script will be terminated,
|
|
234
234
|
if set to null there will be no timeout and any script will run forever.
|
|
@@ -254,7 +254,7 @@ class Config:
|
|
|
254
254
|
"download": [],
|
|
255
255
|
"seasonal": [],
|
|
256
256
|
"mal": [],
|
|
257
|
-
"timeout": None
|
|
257
|
+
"timeout": None,
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
value = self._get_value("post_download_scripts", defaults, dict)
|
|
@@ -32,7 +32,7 @@ class DownloadComponent:
|
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
34
|
def __init__(self, options: CliArgs, dl_path: Path, mode: str) -> None:
|
|
35
|
-
self.options = options
|
|
35
|
+
self.options = options
|
|
36
36
|
self.dl_path = dl_path
|
|
37
37
|
self.mode = mode
|
|
38
38
|
|
|
@@ -141,19 +141,18 @@ class DownloadComponent:
|
|
|
141
141
|
)
|
|
142
142
|
|
|
143
143
|
spinner.set_text("Downloading...")
|
|
144
|
-
|
|
144
|
+
|
|
145
145
|
if not sub_only:
|
|
146
146
|
downloader.download(
|
|
147
147
|
stream,
|
|
148
148
|
get_download_path(anime, stream, parent_directory=self.dl_path),
|
|
149
149
|
container=config.remux_to,
|
|
150
150
|
ffmpeg=self.options.ffmpeg or config.ffmpeg_hls,
|
|
151
|
-
post_dl_cb=get_post_download_scripts_hook(self.mode, anime, spinner)
|
|
151
|
+
post_dl_cb=get_post_download_scripts_hook(self.mode, anime, spinner),
|
|
152
152
|
)
|
|
153
153
|
else:
|
|
154
154
|
downloader.download_sub(
|
|
155
|
-
stream,
|
|
156
|
-
get_download_path(anime, stream, parent_directory=self.dl_path)
|
|
155
|
+
stream, get_download_path(anime, stream, parent_directory=self.dl_path)
|
|
157
156
|
)
|
|
158
157
|
|
|
159
158
|
@staticmethod
|
|
@@ -6,12 +6,17 @@ from InquirerPy.base.control import Choice
|
|
|
6
6
|
from anipy_api.download import Downloader
|
|
7
7
|
from anipy_api.provider import LanguageTypeEnum, ProviderStream
|
|
8
8
|
from anipy_api.locallist import LocalList
|
|
9
|
-
from anipy_api.provider.base import ExternalSub
|
|
10
9
|
|
|
11
10
|
from anipy_cli.colors import colors, cprint
|
|
12
11
|
from anipy_cli.config import Config
|
|
13
12
|
from anipy_cli.menus.base_menu import MenuBase, MenuOption
|
|
14
|
-
from anipy_cli.util import
|
|
13
|
+
from anipy_cli.util import (
|
|
14
|
+
DotSpinner,
|
|
15
|
+
error,
|
|
16
|
+
get_download_path,
|
|
17
|
+
get_post_download_scripts_hook,
|
|
18
|
+
migrate_locallist,
|
|
19
|
+
)
|
|
15
20
|
from anipy_cli.prompts import pick_episode_prompt, search_show_prompt
|
|
16
21
|
|
|
17
22
|
|
|
@@ -169,7 +174,7 @@ class Menu(MenuBase):
|
|
|
169
174
|
print(f"Referer: {self.stream.referrer}")
|
|
170
175
|
|
|
171
176
|
if self.stream.subtitle:
|
|
172
|
-
print(
|
|
177
|
+
print("Subtitles:")
|
|
173
178
|
for name, sub in self.stream.subtitle.items():
|
|
174
179
|
print(f" {name} - {sub.url}")
|
|
175
180
|
|
|
@@ -202,7 +207,7 @@ class Menu(MenuBase):
|
|
|
202
207
|
|
|
203
208
|
if stream is None:
|
|
204
209
|
return
|
|
205
|
-
|
|
210
|
+
|
|
206
211
|
stream = next(filter(lambda x: x.url == stream["url"], streams))
|
|
207
212
|
self.options.quality = stream.resolution
|
|
208
213
|
self.stream = stream
|
|
@@ -241,7 +246,7 @@ class Menu(MenuBase):
|
|
|
241
246
|
get_download_path(self.anime, self.stream),
|
|
242
247
|
container=config.remux_to,
|
|
243
248
|
ffmpeg=self.options.ffmpeg or config.ffmpeg_hls,
|
|
244
|
-
post_dl_cb=get_post_download_scripts_hook("default", self.anime, s)
|
|
249
|
+
post_dl_cb=get_post_download_scripts_hook("default", self.anime, s),
|
|
245
250
|
)
|
|
246
251
|
|
|
247
252
|
if Config().auto_open_dl_defaultcli:
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from typing import TYPE_CHECKING, List, Tuple
|
|
3
3
|
|
|
4
|
-
from anipy_api.mal import MyAnimeListAdapter
|
|
5
4
|
|
|
6
5
|
from anipy_cli.download_component import DownloadComponent
|
|
7
6
|
|
|
@@ -20,12 +19,15 @@ from anipy_cli.menus.base_menu import MenuBase, MenuOption
|
|
|
20
19
|
from anipy_cli.util import (
|
|
21
20
|
DotSpinner,
|
|
22
21
|
error,
|
|
23
|
-
find_closest,
|
|
24
22
|
get_configured_player,
|
|
25
|
-
get_prefered_providers,
|
|
26
23
|
migrate_locallist,
|
|
27
24
|
)
|
|
28
|
-
from anipy_cli.prompts import
|
|
25
|
+
from anipy_cli.prompts import (
|
|
26
|
+
pick_episode_prompt,
|
|
27
|
+
search_show_prompt,
|
|
28
|
+
lang_prompt,
|
|
29
|
+
migrate_provider,
|
|
30
|
+
)
|
|
29
31
|
|
|
30
32
|
|
|
31
33
|
if TYPE_CHECKING:
|
|
@@ -224,9 +226,9 @@ class SeasonalMenu(MenuBase):
|
|
|
224
226
|
def on_successful_download(anime: Anime, ep: Episode, lang: LanguageTypeEnum):
|
|
225
227
|
self.seasonal_list.update(anime, episode=ep, language=lang)
|
|
226
228
|
|
|
227
|
-
failed_series = DownloadComponent(
|
|
228
|
-
|
|
229
|
-
)
|
|
229
|
+
failed_series = DownloadComponent(
|
|
230
|
+
self.options, self.dl_path, "seasonal"
|
|
231
|
+
).download_anime(picked, on_successful_download)
|
|
230
232
|
|
|
231
233
|
if not self.options.auto_update:
|
|
232
234
|
# Clear screen only if there were no issues
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import sys
|
|
2
|
-
import time
|
|
3
2
|
import subprocess as sp
|
|
4
3
|
from pathlib import Path
|
|
5
4
|
from typing import (
|
|
6
5
|
TYPE_CHECKING,
|
|
7
|
-
Callable,
|
|
8
6
|
Iterator,
|
|
9
7
|
List,
|
|
10
8
|
Literal,
|
|
@@ -16,10 +14,9 @@ from typing import (
|
|
|
16
14
|
|
|
17
15
|
from anipy_api.anime import Anime
|
|
18
16
|
from anipy_api.download import Downloader, PostDownloadCallback
|
|
19
|
-
from anipy_api.
|
|
20
|
-
from anipy_api.locallist import LocalListData, LocalListEntry
|
|
17
|
+
from anipy_api.locallist import LocalListData
|
|
21
18
|
from anipy_api.player import get_player
|
|
22
|
-
from anipy_api.provider import
|
|
19
|
+
from anipy_api.provider import list_providers
|
|
23
20
|
from InquirerPy import inquirer
|
|
24
21
|
from yaspin.core import Yaspin
|
|
25
22
|
from yaspin.spinners import Spinners
|
|
@@ -121,7 +118,10 @@ def get_download_path(
|
|
|
121
118
|
|
|
122
119
|
return download_folder / anime_name / filename
|
|
123
120
|
|
|
124
|
-
|
|
121
|
+
|
|
122
|
+
def get_post_download_scripts_hook(
|
|
123
|
+
mode: str, anime: "Anime", spinner: DotSpinner
|
|
124
|
+
) -> PostDownloadCallback:
|
|
125
125
|
config = Config()
|
|
126
126
|
scripts = config.post_download_scripts[mode]
|
|
127
127
|
timeout = config.post_download_scripts["timeout"]
|
|
@@ -129,17 +129,21 @@ def get_post_download_scripts_hook(mode: str, anime: "Anime", spinner: DotSpinne
|
|
|
129
129
|
def hook(path: Path, stream: "ProviderStream"):
|
|
130
130
|
spinner.hide()
|
|
131
131
|
arguments = [
|
|
132
|
-
str(path),
|
|
133
|
-
|
|
134
|
-
str(stream.
|
|
132
|
+
str(path),
|
|
133
|
+
anime.name,
|
|
134
|
+
str(stream.episode),
|
|
135
|
+
anime.provider.NAME,
|
|
136
|
+
str(stream.resolution),
|
|
137
|
+
stream.language.name,
|
|
135
138
|
]
|
|
136
139
|
for s in scripts:
|
|
137
140
|
sub_proc = sp.Popen([s, *arguments])
|
|
138
|
-
sub_proc.wait(timeout)
|
|
141
|
+
sub_proc.wait(timeout) # type: ignore
|
|
139
142
|
spinner.show()
|
|
140
143
|
|
|
141
144
|
return hook
|
|
142
145
|
|
|
146
|
+
|
|
143
147
|
def parse_episode_ranges(ranges: str, episodes: List["Episode"]) -> List["Episode"]:
|
|
144
148
|
picked = set()
|
|
145
149
|
for r in ranges.split():
|
|
@@ -233,9 +237,7 @@ def convert_letter_to_season(letter: str) -> Optional[str]:
|
|
|
233
237
|
|
|
234
238
|
|
|
235
239
|
def migrate_locallist(file: Path) -> LocalListData:
|
|
236
|
-
error(
|
|
237
|
-
f"{file} is in an unsuported format..."
|
|
238
|
-
)
|
|
240
|
+
error(f"{file} is in an unsuported format...")
|
|
239
241
|
|
|
240
242
|
new_list = LocalListData({})
|
|
241
243
|
choice = inquirer.confirm( # type: ignore
|
|
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
|
|
@@ -336,6 +336,7 @@ def parse_auto_search(
|
|
|
336
336
|
|
|
337
337
|
return result, lang, chosen
|
|
338
338
|
|
|
339
|
+
|
|
339
340
|
def migrate_provider(mode: str, local_list: "LocalList"):
|
|
340
341
|
config = Config()
|
|
341
342
|
all_entries = local_list.get_all()
|
|
@@ -384,4 +385,3 @@ def migrate_provider(mode: str, local_list: "LocalList"):
|
|
|
384
385
|
|
|
385
386
|
episode = find_closest(best_anime.get_episodes(s.language), s.episode)
|
|
386
387
|
local_list.update(best_anime, language=s.language, episode=episode)
|
|
387
|
-
|