anipy-cli 2.7.31__py3-none-any.whl → 3.0.0.dev0__py3-none-any.whl

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.

Files changed (62) hide show
  1. anipy_cli/__init__.py +2 -20
  2. anipy_cli/arg_parser.py +30 -20
  3. anipy_cli/cli.py +66 -0
  4. anipy_cli/clis/__init__.py +15 -0
  5. anipy_cli/clis/base_cli.py +32 -0
  6. anipy_cli/clis/binge_cli.py +83 -0
  7. anipy_cli/clis/default_cli.py +104 -0
  8. anipy_cli/clis/download_cli.py +111 -0
  9. anipy_cli/clis/history_cli.py +93 -0
  10. anipy_cli/clis/mal_cli.py +71 -0
  11. anipy_cli/{cli/clis → clis}/seasonal_cli.py +9 -6
  12. anipy_cli/colors.py +4 -4
  13. anipy_cli/config.py +308 -87
  14. anipy_cli/discord.py +34 -0
  15. anipy_cli/mal_proxy.py +216 -0
  16. anipy_cli/menus/__init__.py +5 -0
  17. anipy_cli/{cli/menus → menus}/base_menu.py +8 -12
  18. anipy_cli/menus/mal_menu.py +660 -0
  19. anipy_cli/menus/menu.py +194 -0
  20. anipy_cli/menus/seasonal_menu.py +263 -0
  21. anipy_cli/prompts.py +231 -0
  22. anipy_cli/util.py +262 -0
  23. anipy_cli-3.0.0.dev0.dist-info/METADATA +67 -0
  24. anipy_cli-3.0.0.dev0.dist-info/RECORD +26 -0
  25. {anipy_cli-2.7.31.dist-info → anipy_cli-3.0.0.dev0.dist-info}/WHEEL +1 -2
  26. anipy_cli-3.0.0.dev0.dist-info/entry_points.txt +3 -0
  27. anipy_cli/cli/__init__.py +0 -1
  28. anipy_cli/cli/cli.py +0 -37
  29. anipy_cli/cli/clis/__init__.py +0 -6
  30. anipy_cli/cli/clis/base_cli.py +0 -43
  31. anipy_cli/cli/clis/binge_cli.py +0 -54
  32. anipy_cli/cli/clis/default_cli.py +0 -46
  33. anipy_cli/cli/clis/download_cli.py +0 -92
  34. anipy_cli/cli/clis/history_cli.py +0 -64
  35. anipy_cli/cli/clis/mal_cli.py +0 -27
  36. anipy_cli/cli/menus/__init__.py +0 -3
  37. anipy_cli/cli/menus/mal_menu.py +0 -411
  38. anipy_cli/cli/menus/menu.py +0 -108
  39. anipy_cli/cli/menus/seasonal_menu.py +0 -177
  40. anipy_cli/cli/util.py +0 -125
  41. anipy_cli/download.py +0 -467
  42. anipy_cli/history.py +0 -83
  43. anipy_cli/mal.py +0 -651
  44. anipy_cli/misc.py +0 -227
  45. anipy_cli/player/__init__.py +0 -1
  46. anipy_cli/player/player.py +0 -35
  47. anipy_cli/player/players/__init__.py +0 -3
  48. anipy_cli/player/players/base.py +0 -107
  49. anipy_cli/player/players/mpv.py +0 -19
  50. anipy_cli/player/players/mpv_control.py +0 -37
  51. anipy_cli/player/players/syncplay.py +0 -19
  52. anipy_cli/player/players/vlc.py +0 -18
  53. anipy_cli/query.py +0 -100
  54. anipy_cli/run_anipy_cli.py +0 -14
  55. anipy_cli/seasonal.py +0 -112
  56. anipy_cli/url_handler.py +0 -470
  57. anipy_cli/version.py +0 -1
  58. anipy_cli-2.7.31.dist-info/LICENSE +0 -674
  59. anipy_cli-2.7.31.dist-info/METADATA +0 -162
  60. anipy_cli-2.7.31.dist-info/RECORD +0 -43
  61. anipy_cli-2.7.31.dist-info/entry_points.txt +0 -2
  62. anipy_cli-2.7.31.dist-info/top_level.txt +0 -1
anipy_cli/util.py ADDED
@@ -0,0 +1,262 @@
1
+ import sys
2
+ import time
3
+ from pathlib import Path
4
+ from typing import (
5
+ TYPE_CHECKING,
6
+ Iterator,
7
+ List,
8
+ Literal,
9
+ NoReturn,
10
+ Optional,
11
+ Union,
12
+ overload,
13
+ )
14
+
15
+ from anipy_api.anime import Anime
16
+ from anipy_api.download import Downloader
17
+ from anipy_api.player import get_player
18
+ from anipy_api.provider import (
19
+ LanguageTypeEnum,
20
+ list_providers,
21
+ get_provider,
22
+ )
23
+ from anipy_api.locallist import LocalListData, LocalListEntry
24
+ from anipy_api.error import LangTypeNotAvailableError
25
+ from InquirerPy import inquirer
26
+ from yaspin.core import Yaspin
27
+ from yaspin.spinners import Spinners
28
+
29
+ from anipy_cli.colors import color, colors
30
+ from anipy_cli.config import Config
31
+ from anipy_cli.discord import DiscordPresence
32
+
33
+ if TYPE_CHECKING:
34
+ from anipy_api.player import PlayerBase
35
+ from anipy_api.provider import BaseProvider, Episode, ProviderStream
36
+
37
+
38
+ class DotSpinner(Yaspin):
39
+ def __init__(self, *text_and_colors, **spinner_args):
40
+ super().__init__(
41
+ text=color(*text_and_colors),
42
+ color="cyan",
43
+ spinner=Spinners.dots,
44
+ **spinner_args,
45
+ )
46
+
47
+ def __enter__(self) -> "DotSpinner":
48
+ self.start()
49
+ return self
50
+
51
+ def set_text(self, *text_and_colors):
52
+ self.text = color(*text_and_colors)
53
+
54
+
55
+ @overload
56
+ def error(error: str, fatal: Literal[True]) -> NoReturn: ...
57
+ @overload
58
+ def error(error: str, fatal: Literal[False] = ...) -> None: ...
59
+
60
+
61
+ def error(error: str, fatal: bool = False) -> Union[NoReturn, None]:
62
+ if not fatal:
63
+ sys.stderr.write(
64
+ color(colors.RED, "anipy-cli: error: ", colors.END, f"{error}\n")
65
+ )
66
+ else:
67
+ sys.stderr.write(
68
+ color(
69
+ colors.RED,
70
+ "anipy-cli: fatal error: ",
71
+ colors.END,
72
+ f"{error}, exiting\n",
73
+ )
74
+ )
75
+ sys.exit(1)
76
+
77
+
78
+ def get_prefered_providers(mode: str) -> Iterator["BaseProvider"]:
79
+ config = Config()
80
+ preferred_providers = config.providers[mode]
81
+
82
+ if not preferred_providers:
83
+ error(
84
+ f"you have no providers set for {mode} mode, look into your config",
85
+ fatal=True,
86
+ )
87
+
88
+ for i in list_providers():
89
+ if i.NAME in preferred_providers:
90
+ url_override = config.provider_urls.get(i.NAME, None)
91
+ yield i(url_override)
92
+
93
+
94
+ def get_download_path(
95
+ anime: "Anime",
96
+ stream: "ProviderStream",
97
+ parent_directory: Optional[Path] = None,
98
+ ) -> Path:
99
+ config = Config()
100
+ download_folder = parent_directory or config.download_folder_path
101
+
102
+ anime_name = Downloader._get_valid_pathname(anime.name)
103
+ filename = config.download_name_format.format(
104
+ show_name=anime_name,
105
+ episode_number=str(stream.episode).zfill(2),
106
+ quality=stream.resolution,
107
+ provider=anime.provider.NAME,
108
+ type=stream.language,
109
+ )
110
+
111
+ filename = Downloader._get_valid_pathname(filename) # type: ignore
112
+
113
+ return download_folder / anime_name / filename
114
+
115
+
116
+ def parse_episode_ranges(ranges: str, episodes: List["Episode"]) -> List["Episode"]:
117
+ picked = set()
118
+ for r in ranges.split():
119
+ numbers = r.split("-")
120
+ if numbers[0] > numbers[-1]:
121
+ error(f"invalid range: {r}")
122
+ continue
123
+ # return pick_episode_range_prompt(anime, dub)
124
+
125
+ try:
126
+ picked = picked | set(
127
+ episodes[
128
+ episodes.index(parsenum(numbers[0])) : episodes.index(
129
+ parsenum(numbers[-1])
130
+ )
131
+ + 1
132
+ ]
133
+ )
134
+ except ValueError:
135
+ error(f"range `{r}` is not contained in episodes {episodes}")
136
+ continue
137
+
138
+ return sorted(picked)
139
+
140
+
141
+ def parsenum(n: str):
142
+ try:
143
+ return int(n)
144
+ except ValueError:
145
+ return float(n)
146
+
147
+
148
+ def find_closest(episodes: List["Episode"], target: int) -> "Episode":
149
+ left, right = 0, len(episodes) - 1
150
+ while left < right:
151
+ if abs(episodes[left] - target) <= abs(episodes[right] - target):
152
+ right -= 1
153
+ else:
154
+ left += 1
155
+
156
+ return episodes[left]
157
+
158
+
159
+ def get_configured_player(player_override: Optional[str] = None) -> "PlayerBase":
160
+ config = Config()
161
+ player = Path(player_override or config.player_path)
162
+ if config.dc_presence:
163
+ # If the cache size is 0, it means that DiscordPresence was
164
+ # not intialized once in the run_cli function and therefore we
165
+ # can assume that it failed to initialize beacuse of some error.
166
+ if DiscordPresence.cache_info().currsize > 0:
167
+ discord_cb = DiscordPresence().dc_presence_callback
168
+ else:
169
+ discord_cb = None
170
+ else:
171
+ discord_cb = None
172
+
173
+ if "mpv" in player.stem:
174
+ args = config.mpv_commandline_options
175
+ elif "vlc" in player.stem:
176
+ args = config.vlc_commandline_options
177
+ else:
178
+ args = []
179
+
180
+ return get_player(player, args, discord_cb)
181
+
182
+
183
+ def get_anime_season(month):
184
+ if 1 <= month <= 3:
185
+ return "Winter"
186
+ elif 4 <= month <= 6:
187
+ return "Spring"
188
+ elif 7 <= month <= 9:
189
+ return "Summer"
190
+ else:
191
+ return "Fall"
192
+
193
+
194
+ def migrate_locallist(file: Path) -> LocalListData:
195
+ import json
196
+ import re
197
+
198
+ error(
199
+ f"{file} is in an unsuported format, trying to migrate the old gogoanime entries..."
200
+ )
201
+
202
+ old_data = json.load(file.open("r"))
203
+ new_list = LocalListData({})
204
+ gogo = get_provider(
205
+ "gogoanime", base_url_override=Config().provider_urls.get("gogoanime", None)
206
+ )
207
+ assert gogo is not None
208
+
209
+ try:
210
+ for k, v in old_data.items():
211
+ name = k
212
+ name = re.sub(r"\s?\((dub|japanese\sdub)\)", "", name, flags=re.IGNORECASE)
213
+ identifier = Path(v.get("category_url", v["category-link"])).name
214
+ is_dub = identifier.endswith("-dub") or identifier.endswith("-japanese-dub")
215
+ identifier = identifier.removesuffix("-dub").removesuffix("-japanese-dub")
216
+ episode = v["ep"]
217
+ unique_id = f"gogoanime:{identifier}"
218
+
219
+ langs = set()
220
+
221
+ try:
222
+ gogo.get_episodes(identifier, lang=LanguageTypeEnum.DUB)
223
+ langs.add(LanguageTypeEnum.DUB)
224
+ gogo.get_episodes(identifier, lang=LanguageTypeEnum.SUB)
225
+ langs.add(LanguageTypeEnum.SUB)
226
+ except LangTypeNotAvailableError:
227
+ pass
228
+
229
+ if not langs:
230
+ error(f"> failed to migrate {name}, as it was not found in gogoanime")
231
+
232
+ if is_dub and LanguageTypeEnum.DUB not in langs:
233
+ error(
234
+ f"> failed to migrate {name}, as it was configured as dub but"
235
+ f"{gogo.BASE_URL}/category/{identifier}-dub or {gogo.BASE_URL}/category/{identifier}-japanese-dub was not found!"
236
+ )
237
+ continue
238
+
239
+ new_entry = LocalListEntry(
240
+ provider="gogoanmie",
241
+ name=name,
242
+ identifier=identifier,
243
+ episode=episode,
244
+ language=LanguageTypeEnum.DUB if is_dub else LanguageTypeEnum.SUB,
245
+ languages=langs,
246
+ timestamp=int(time.time()),
247
+ )
248
+
249
+ new_list.data[unique_id] = new_entry
250
+
251
+ new_list.write(file)
252
+ return new_list
253
+ except KeyError:
254
+ choice = inquirer.confirm( # type: ignore
255
+ message=f"Can not migrate {file}, should it be delted?",
256
+ default=False,
257
+ ).execute()
258
+ if choice:
259
+ file.unlink()
260
+ return new_list
261
+ else:
262
+ error("could not read {file}", fatal=True)
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.1
2
+ Name: anipy-cli
3
+ Version: 3.0.0.dev0
4
+ Summary: Watch and Download anime from the comfort of your Terminal
5
+ Home-page: https://sdaqo.github.io/anipy-cli
6
+ License: GPL-3.0
7
+ Keywords: anime,cli
8
+ Author: sdaqo
9
+ Author-email: sdaqo.dev@protonmail.com
10
+ Requires-Python: >=3.9,<4.0
11
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Requires-Dist: anipy-api (==3.*)
18
+ Requires-Dist: appdirs (>=1.4.4,<2.0.0)
19
+ Requires-Dist: inquirerpy (>=0.3.4,<0.4.0)
20
+ Requires-Dist: pypresence (>=4.3.0,<5.0.0)
21
+ Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
22
+ Requires-Dist: yaspin (>=3.0.2,<4.0.0)
23
+ Project-URL: Bug Tracker, https://github.com/sdaqo/anipy-cli/issues
24
+ Project-URL: Documentation, https://sdaqo.github.io/anipy-cli/getting-started-cli
25
+ Project-URL: Repository, https://github.com/sdaqo/anipy-cli
26
+ Description-Content-Type: text/markdown
27
+
28
+ # ANIPY-CLI
29
+ **Anime from the comfort of your Terminal**
30
+
31
+ <p align="center"><img src="https://github.com/sdaqo/anipy-cli/assets/63876564/1dafa5fb-4273-4dc1-a7ab-2664dd668fc9" /> </p>
32
+
33
+ https://user-images.githubusercontent.com/63876564/162056019-ed0e7a60-78f6-4a2c-bc73-9be5dc2a4f07.mp4
34
+
35
+
36
+ ## What even is this?
37
+ A Little tool written in python to watch and download anime from the terminal (the better way to watch anime)
38
+ This project's main aim is to create a enjoyable anime watching and downloading experience, directly in the terminal - your favorite place.
39
+
40
+ Since the version 3 rewrite this project is split into api and frontend this makes it easy to integrate this into your project!
41
+
42
+ ## You are just here for the client?
43
+ As one wise man once said:
44
+ > I DONT GIVE A FUCK ABOUT THE FUCKING CODE! i just want to download this stupid fucking application and use it.
45
+ >
46
+ > WHY IS THERE CODE??? MAKE A FUCKING .EXE FILE AND GIVE IT TO ME. these dumbfucks think that everyone is a developer and understands code. well i am not and i don't understand it. I only know to download and install applications. SO WHY THE FUCK IS THERE CODE? make an EXE file and give it to me. STUPID FUCKING SMELLY NERDS
47
+
48
+ <sub>Please do not take this seriously this is some stupid copypasta</sub>
49
+
50
+ We do not have a .exe but we have pipx: `pipx install anipy-cli`
51
+
52
+ Check out [Getting Started - CLI](https://sdaqo.github.io/anipy-cli/getting-started-cli) for better instructions and advice!
53
+
54
+ ## You want to use the api for your project?
55
+ Feel free to - please check out [Getting Started - API](https://sdaqo.github.io/anipy-cli/getting-started-api) for instructions
56
+
57
+
58
+ ## :heart: Credits!
59
+
60
+ #### Heavily inspired by https://github.com/pystardust/ani-cli/
61
+
62
+ #### All contributors for contributing
63
+
64
+ <a href="https://github.com/sdaqo/anipy-cli/graphs/contributors">
65
+ <img src="https://contrib.rocks/image?repo=sdaqo/anipy-cli" alt="anipy-cli contributors" title="anipy-cli contributors" width="800"/>
66
+ </a>
67
+
@@ -0,0 +1,26 @@
1
+ anipy_cli/__init__.py,sha256=bTdKhyhozpxYVDifnW0oWECIIrqEf-nPSwZy6irBbkI,53
2
+ anipy_cli/arg_parser.py,sha256=r2yxTYqKdhKvbzj8Pg00_4lmhK8mguxAVbg9G2vM-II,5299
3
+ anipy_cli/cli.py,sha256=Ah5BE-u_SjcuzU5dQ5cSHtUloVRApCWwTK5i49yQtH8,1922
4
+ anipy_cli/clis/__init__.py,sha256=Y00uiPWiMvvRImxJMvfLA55BOkMUOrrx5vJUNvquNsY,411
5
+ anipy_cli/clis/base_cli.py,sha256=CC8L9gKhzWpduHHdHyvuh004YbP1LUTCx3woiwV08fc,609
6
+ anipy_cli/clis/binge_cli.py,sha256=eSvdOo_BRSb8-Xp48ZDcelqUBlDPdyQqu8OV0vc4szo,2281
7
+ anipy_cli/clis/default_cli.py,sha256=lBjPAhdhIQRkvjHDsmkxrgv_T-_70YpCt6QR14g0e1o,2815
8
+ anipy_cli/clis/download_cli.py,sha256=MSNiLpkotdRY4SeHEmxIcSb6thNmx__ABpfCyailKz0,3197
9
+ anipy_cli/clis/history_cli.py,sha256=dwihSahyzXKMWhRQs3O7VuZqrd6vEeBTDy-pHdaJZU0,2676
10
+ anipy_cli/clis/mal_cli.py,sha256=StPRHTA3GrmcKEZXHPVYeeaZi_DJdI_DFGq-SApYjbM,2260
11
+ anipy_cli/clis/seasonal_cli.py,sha256=GV2TQNm9UotG1cxfYbrFFgg7Jmy8SFa7w_GlFtPdRVE,616
12
+ anipy_cli/colors.py,sha256=voXC7z1Fs9tHg4zzNTNMIrt9k-EVgJ3_xEf5KiW2xgo,916
13
+ anipy_cli/config.py,sha256=Q0RqI_aX5V5I35qT0mG7YLuxzVbMUuf3331RdSUk7E0,15404
14
+ anipy_cli/discord.py,sha256=9Pnc-epxexjSw3SkCiEnd1hhFnoyAdDGO6ZKoaZEnok,1134
15
+ anipy_cli/mal_proxy.py,sha256=wIsku2_dl8vKD2K99L63OlzA3L5fl-VmyeiXC9VrxI4,6981
16
+ anipy_cli/menus/__init__.py,sha256=aIzbphxAW-QGfZwR1DIegFZuTJp1O3tSUnai0f0f4lY,185
17
+ anipy_cli/menus/base_menu.py,sha256=g5b9Z7SpvCxcq_vqObcPzxLwcXeGPltLgSwa0sEzyfk,1140
18
+ anipy_cli/menus/mal_menu.py,sha256=PJKZtvO-X-_AUIQ4NuOxLcK28EpW2AcOrIKe3N8IiIY,24091
19
+ anipy_cli/menus/menu.py,sha256=raHBeNQ5NNXOrTr1pCoE44FlOXWrqa1f1_kk1Rk3bH4,6179
20
+ anipy_cli/menus/seasonal_menu.py,sha256=VBmeXanJb-vS5TXiK79KgtJ5vPW87gIOdpN_EijAG_U,9097
21
+ anipy_cli/prompts.py,sha256=5h4FI0TJ8YwvVmRtfl-NBnEzPWUc7UMqgSnWuWfEVrI,6989
22
+ anipy_cli/util.py,sha256=FiWEfz-tQVIFMOOlUZY26fArhEPRJNhtfF0U1sT3T7Q,7700
23
+ anipy_cli-3.0.0.dev0.dist-info/METADATA,sha256=CUU0oD_cuutrHguG4tePsXe3hFIHCFQdSr0Sh95-PbQ,3080
24
+ anipy_cli-3.0.0.dev0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
25
+ anipy_cli-3.0.0.dev0.dist-info/entry_points.txt,sha256=86iXpcm_ECFndrt0JAI2mqYfXC2Ar7mGi0iOaxCrNP0,51
26
+ anipy_cli-3.0.0.dev0.dist-info/RECORD,,
@@ -1,5 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: poetry-core 1.9.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
-
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ anipy-cli=anipy_cli.cli:run_cli
3
+
anipy_cli/cli/__init__.py DELETED
@@ -1 +0,0 @@
1
- from anipy_cli.cli.cli import run_cli
anipy_cli/cli/cli.py DELETED
@@ -1,37 +0,0 @@
1
- from anipy_cli.misc import error, dc_presence_connect
2
- from anipy_cli.arg_parser import parse_args
3
- from anipy_cli.config import Config
4
- from anipy_cli.colors import cprint, colors
5
- from anipy_cli.cli.clis import *
6
-
7
-
8
- def run_cli() -> None:
9
- args = parse_args()
10
-
11
- rpc_client = None
12
- if Config().dc_presence:
13
- rpc_client = dc_presence_connect()
14
-
15
- if args.config:
16
- print(Config()._config_file)
17
- return
18
- elif args.delete:
19
- try:
20
- Config().history_file_path.unlink()
21
- cprint(colors.RED, "Done")
22
- except FileNotFoundError:
23
- error("no history file found")
24
- return
25
-
26
- clis_dict = {
27
- args.download: DownloadCli,
28
- args.binge: BingeCli,
29
- args.seasonal: SeasonalCli,
30
- args.history: HistoryCli,
31
- args.mal: MalCli,
32
- args.auto_update: SeasonalCli,
33
- }
34
-
35
- cli_class = clis_dict.get(True, DefaultCli)
36
-
37
- cli_class(options=args, rpc_client=rpc_client).run()
@@ -1,6 +0,0 @@
1
- from anipy_cli.cli.clis.default_cli import DefaultCli
2
- from anipy_cli.cli.clis.history_cli import HistoryCli
3
- from anipy_cli.cli.clis.mal_cli import MalCli
4
- from anipy_cli.cli.clis.seasonal_cli import SeasonalCli
5
- from anipy_cli.cli.clis.binge_cli import BingeCli
6
- from anipy_cli.cli.clis.download_cli import DownloadCli
@@ -1,43 +0,0 @@
1
- import sys
2
- from abc import ABC, abstractmethod
3
-
4
- from anipy_cli.arg_parser import CliArgs
5
- from anipy_cli.misc import error
6
-
7
-
8
- class CliBase(ABC):
9
- def __init__(self, options: CliArgs, rpc_client=None):
10
- self.options = options
11
- self.rpc_client = rpc_client
12
-
13
- @abstractmethod
14
- def print_header(self):
15
- pass
16
-
17
- @abstractmethod
18
- def take_input(self):
19
- pass
20
-
21
- @abstractmethod
22
- def process(self):
23
- pass
24
-
25
- @abstractmethod
26
- def show(self):
27
- pass
28
-
29
- @abstractmethod
30
- def post(self):
31
- pass
32
-
33
- def run(self):
34
- self.print_header()
35
- self.take_input()
36
- self.process()
37
- self.show()
38
- self.post()
39
-
40
- @staticmethod
41
- def exit(error_str: str):
42
- error(error_str)
43
- sys.exit()
@@ -1,54 +0,0 @@
1
- from anipy_cli.colors import cprint, colors
2
- from anipy_cli.misc import Entry
3
- from anipy_cli.query import query
4
- from anipy_cli.url_handler import epHandler
5
- from anipy_cli.player import get_player
6
- from anipy_cli.arg_parser import CliArgs
7
- from anipy_cli.cli.util import binge
8
- from anipy_cli.cli.clis.base_cli import CliBase
9
-
10
-
11
- class BingeCli(CliBase):
12
- def __init__(self, options: CliArgs, rpc_client=None):
13
- super().__init__(options, rpc_client)
14
- self.entry = Entry()
15
- self.ep_list = []
16
- self.binge_list = {}
17
- self.player = get_player(self.rpc_client, self.options.optional_player)
18
-
19
- def print_header(self):
20
- cprint(colors.GREEN, "***Binge Mode***")
21
-
22
- def take_input(self):
23
- inp = input("Search: ")
24
- user_query = query(inp, self.entry)
25
-
26
- if user_query.get_links() == 0:
27
- self.exit("no search results")
28
-
29
- self.entry = user_query.pick_show()
30
- self.ep_list = epHandler(self.entry).pick_range()
31
-
32
- def process(self):
33
- ep_urls = []
34
- for i in self.ep_list:
35
- ent = Entry()
36
- ent.ep = int(i)
37
- ent.category_url = self.entry.category_url
38
- ep_class = epHandler(ent)
39
- ent = ep_class.gen_eplink()
40
- ep_urls.append(ent.ep_url)
41
-
42
- self.binge_list = {
43
- self.entry.show_name: {
44
- "ep_urls": ep_urls,
45
- "eps": self.ep_list,
46
- "category_url": self.entry.category_url,
47
- }
48
- }
49
-
50
- def show(self):
51
- binge(self.binge_list, self.options.quality, self.player)
52
-
53
- def post(self):
54
- self.player.kill_player()
@@ -1,46 +0,0 @@
1
- import sys
2
-
3
- from anipy_cli.misc import Entry
4
- from anipy_cli.query import query
5
- from anipy_cli.url_handler import epHandler, videourl
6
- from anipy_cli.player import get_player
7
- from anipy_cli.arg_parser import CliArgs
8
- from anipy_cli.cli.menus import Menu
9
- from anipy_cli.cli.clis.base_cli import CliBase
10
-
11
-
12
- class DefaultCli(CliBase):
13
- def __init__(self, options: CliArgs, rpc_client=None):
14
- super().__init__(options, rpc_client)
15
-
16
- self.entry = Entry()
17
- self.player = get_player(self.rpc_client, self.options.optional_player)
18
-
19
- def print_header(self):
20
- pass
21
-
22
- def take_input(self):
23
- inp = input("Search: ")
24
- user_query = query(inp, self.entry)
25
-
26
- if user_query.get_links() == 0:
27
- self.exit("no search results")
28
-
29
- self.entry = user_query.pick_show()
30
- self.entry = epHandler(self.entry).pick_ep()
31
-
32
- def process(self):
33
- url_parser = videourl(self.entry, self.options.quality)
34
- url_parser.stream_url()
35
- self.entry = url_parser.get_entry()
36
-
37
- def show(self):
38
- self.player.play_title(self.entry)
39
-
40
- def post(self):
41
- Menu(
42
- options=self.options,
43
- entry=self.entry,
44
- player=self.player,
45
- rpc_client=self.rpc_client,
46
- ).run()
@@ -1,92 +0,0 @@
1
- from copy import deepcopy
2
-
3
- from anipy_cli.arg_parser import CliArgs
4
- from anipy_cli.config import Config
5
- from anipy_cli.colors import cprint, colors
6
- from anipy_cli.misc import Entry, parsenum
7
- from anipy_cli.query import query
8
- from anipy_cli.url_handler import videourl, epHandler
9
- from anipy_cli.download import download
10
- from anipy_cli.cli.util import get_season_searches
11
- from anipy_cli.cli.clis.base_cli import CliBase
12
-
13
-
14
- class DownloadCli(CliBase):
15
- def __init__(self, options: CliArgs, rpc_client=None):
16
- super().__init__(options, rpc_client)
17
-
18
- self.entry = Entry()
19
- self.show_entries = []
20
- self.dl_path = Config().download_folder_path
21
- if options.location:
22
- self.dl_path = options.location
23
-
24
- def print_header(self):
25
- cprint(colors.GREEN, "***Download Mode***")
26
- cprint(colors.GREEN, "Downloads are stored in: ", colors.END, str(self.dl_path))
27
-
28
- def take_input(self):
29
- is_season_search = False
30
-
31
- searches = []
32
- if (
33
- not self.options.no_season_search
34
- and input("Search MyAnimeList for anime in Season? (y|n): \n>> ") == "y"
35
- ):
36
- searches = get_season_searches()
37
-
38
- else:
39
- another = "y"
40
- while another == "y":
41
- searches.append(input("Search: "))
42
- another = input("Add another search: (y|n)\n")
43
-
44
- for search in searches:
45
- links = 0
46
- query_class = None
47
- if isinstance(search, dict):
48
- is_season_search = True
49
- links = [search["category_url"]]
50
-
51
- else:
52
- print("\nCurrent: ", search)
53
- query_class = query(search, self.entry)
54
- query_class.get_pages()
55
- links = query_class.get_links()
56
-
57
- if links == 0:
58
- self.exit("no search results")
59
-
60
- if is_season_search:
61
- self.entry = Entry()
62
- self.entry.show_name = search["name"]
63
- self.entry.category_url = search["category_url"]
64
-
65
- else:
66
- self.entry = query_class.pick_show()
67
-
68
- ep_class = epHandler(self.entry)
69
- ep_list = ep_class.pick_range()
70
- self.show_entries.append(
71
- {"show_entry": deepcopy(self.entry), "ep_list": deepcopy(ep_list)}
72
- )
73
-
74
- def process(self):
75
- for ent in self.show_entries:
76
- entry = ent["show_entry"]
77
- ep_list = ent["ep_list"]
78
- for i in ep_list:
79
- entry.ep = parsenum(i)
80
- entry.embed_url = ""
81
- ep_class = epHandler(entry)
82
- entry = ep_class.gen_eplink()
83
- url_class = videourl(entry, self.options.quality)
84
- url_class.stream_url()
85
- entry = url_class.get_entry()
86
- download(entry, self.options.quality, self.options.ffmpeg).download()
87
-
88
- def show(self):
89
- pass
90
-
91
- def post(self):
92
- pass