anipy-cli 2.7.17__py3-none-any.whl → 3.8.2__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.
- anipy_cli/__init__.py +2 -20
- anipy_cli/anilist_proxy.py +229 -0
- anipy_cli/arg_parser.py +109 -21
- anipy_cli/cli.py +98 -0
- anipy_cli/clis/__init__.py +17 -0
- anipy_cli/clis/anilist_cli.py +62 -0
- anipy_cli/clis/base_cli.py +34 -0
- anipy_cli/clis/binge_cli.py +96 -0
- anipy_cli/clis/default_cli.py +115 -0
- anipy_cli/clis/download_cli.py +85 -0
- anipy_cli/clis/history_cli.py +96 -0
- anipy_cli/clis/mal_cli.py +71 -0
- anipy_cli/{cli/clis → clis}/seasonal_cli.py +9 -6
- anipy_cli/colors.py +14 -8
- anipy_cli/config.py +387 -90
- anipy_cli/discord.py +34 -0
- anipy_cli/download_component.py +194 -0
- anipy_cli/logger.py +200 -0
- anipy_cli/mal_proxy.py +228 -0
- anipy_cli/menus/__init__.py +6 -0
- anipy_cli/menus/anilist_menu.py +671 -0
- anipy_cli/{cli/menus → menus}/base_menu.py +9 -14
- anipy_cli/menus/mal_menu.py +657 -0
- anipy_cli/menus/menu.py +265 -0
- anipy_cli/menus/seasonal_menu.py +270 -0
- anipy_cli/prompts.py +387 -0
- anipy_cli/util.py +268 -0
- anipy_cli-3.8.2.dist-info/METADATA +71 -0
- anipy_cli-3.8.2.dist-info/RECORD +31 -0
- {anipy_cli-2.7.17.dist-info → anipy_cli-3.8.2.dist-info}/WHEEL +1 -2
- anipy_cli-3.8.2.dist-info/entry_points.txt +3 -0
- anipy_cli/cli/__init__.py +0 -1
- anipy_cli/cli/cli.py +0 -37
- anipy_cli/cli/clis/__init__.py +0 -6
- anipy_cli/cli/clis/base_cli.py +0 -43
- anipy_cli/cli/clis/binge_cli.py +0 -54
- anipy_cli/cli/clis/default_cli.py +0 -46
- anipy_cli/cli/clis/download_cli.py +0 -92
- anipy_cli/cli/clis/history_cli.py +0 -64
- anipy_cli/cli/clis/mal_cli.py +0 -27
- anipy_cli/cli/menus/__init__.py +0 -3
- anipy_cli/cli/menus/mal_menu.py +0 -411
- anipy_cli/cli/menus/menu.py +0 -102
- anipy_cli/cli/menus/seasonal_menu.py +0 -174
- anipy_cli/cli/util.py +0 -118
- anipy_cli/download.py +0 -454
- anipy_cli/history.py +0 -83
- anipy_cli/mal.py +0 -645
- anipy_cli/misc.py +0 -227
- anipy_cli/player/__init__.py +0 -1
- anipy_cli/player/player.py +0 -33
- anipy_cli/player/players/__init__.py +0 -3
- anipy_cli/player/players/base.py +0 -106
- anipy_cli/player/players/mpv.py +0 -19
- anipy_cli/player/players/mpv_contrl.py +0 -37
- anipy_cli/player/players/syncplay.py +0 -19
- anipy_cli/player/players/vlc.py +0 -18
- anipy_cli/query.py +0 -92
- anipy_cli/run_anipy_cli.py +0 -14
- anipy_cli/seasonal.py +0 -106
- anipy_cli/url_handler.py +0 -442
- anipy_cli/version.py +0 -1
- anipy_cli-2.7.17.dist-info/LICENSE +0 -674
- anipy_cli-2.7.17.dist-info/METADATA +0 -159
- anipy_cli-2.7.17.dist-info/RECORD +0 -43
- anipy_cli-2.7.17.dist-info/entry_points.txt +0 -2
- anipy_cli-2.7.17.dist-info/top_level.txt +0 -1
anipy_cli/cli/menus/mal_menu.py
DELETED
|
@@ -1,411 +0,0 @@
|
|
|
1
|
-
from typing import List
|
|
2
|
-
|
|
3
|
-
from anipy_cli.arg_parser import CliArgs
|
|
4
|
-
from anipy_cli.colors import colors, cprint, cinput
|
|
5
|
-
from anipy_cli.misc import Entry, print_names, error
|
|
6
|
-
from anipy_cli.player import get_player
|
|
7
|
-
from anipy_cli.url_handler import videourl
|
|
8
|
-
from anipy_cli.query import query
|
|
9
|
-
from anipy_cli.download import download
|
|
10
|
-
from anipy_cli.config import Config
|
|
11
|
-
from anipy_cli.mal import MAL
|
|
12
|
-
from anipy_cli.cli.util import binge, get_season_searches
|
|
13
|
-
from anipy_cli.cli.menus.base_menu import MenuBase, MenuOption
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class MALMenu(MenuBase):
|
|
17
|
-
def __init__(self, options: CliArgs, rpc_client=None):
|
|
18
|
-
self.entry = Entry()
|
|
19
|
-
self.options = options
|
|
20
|
-
self.rpc_client = rpc_client
|
|
21
|
-
|
|
22
|
-
self.dl_path = Config().seasonals_dl_path
|
|
23
|
-
if options.location:
|
|
24
|
-
self.dl_path = options.location
|
|
25
|
-
|
|
26
|
-
user = None
|
|
27
|
-
if Config().mal_user and Config().mal_user != "":
|
|
28
|
-
user = Config().mal_user
|
|
29
|
-
|
|
30
|
-
if options.mal_password is not None and options.mal_password != "":
|
|
31
|
-
password = options.mal_password
|
|
32
|
-
else:
|
|
33
|
-
password = Config().mal_password
|
|
34
|
-
if not password or password == "":
|
|
35
|
-
password = None
|
|
36
|
-
|
|
37
|
-
if user is None or password is None:
|
|
38
|
-
cprint(colors.ERROR, "Missing credentials!\n")
|
|
39
|
-
cprint(
|
|
40
|
-
colors.CYAN,
|
|
41
|
-
"In order to use the MAL-Mode, you need to specify your username and password.\n",
|
|
42
|
-
)
|
|
43
|
-
cprint(
|
|
44
|
-
colors.CYAN, "Those can be specified in the anipy-cli config file.\n"
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
if user is None:
|
|
48
|
-
while not user:
|
|
49
|
-
user_input = cinput(
|
|
50
|
-
colors.CYAN,
|
|
51
|
-
"Please enter your MyAnimeList ",
|
|
52
|
-
colors.YELLOW,
|
|
53
|
-
"Username ",
|
|
54
|
-
colors.CYAN,
|
|
55
|
-
":\n",
|
|
56
|
-
)
|
|
57
|
-
if user_input and user_input != "":
|
|
58
|
-
user = user_input
|
|
59
|
-
|
|
60
|
-
if password is None:
|
|
61
|
-
cprint(
|
|
62
|
-
colors.MAGENTA,
|
|
63
|
-
"The password can also be passed with the '--mal-password' parameter.",
|
|
64
|
-
)
|
|
65
|
-
while not password:
|
|
66
|
-
pw_input = cinput(
|
|
67
|
-
colors.CYAN,
|
|
68
|
-
"Please enter your MyAnimeList ",
|
|
69
|
-
colors.YELLOW,
|
|
70
|
-
"Password ",
|
|
71
|
-
colors.CYAN,
|
|
72
|
-
":\n",
|
|
73
|
-
)
|
|
74
|
-
if pw_input and pw_input != "":
|
|
75
|
-
password = pw_input
|
|
76
|
-
|
|
77
|
-
self.m_class = MAL(user, password)
|
|
78
|
-
|
|
79
|
-
def print_header(self):
|
|
80
|
-
pass
|
|
81
|
-
|
|
82
|
-
@property
|
|
83
|
-
def menu_options(self) -> List[MenuOption]:
|
|
84
|
-
return [
|
|
85
|
-
MenuOption("Add Anime", self.add_anime, "a"),
|
|
86
|
-
MenuOption("Delete one anime from mal list", self.del_anime, "e"),
|
|
87
|
-
MenuOption("List anime in mal list", self.list_animes, "l"),
|
|
88
|
-
MenuOption("Map MAL anime to gogo Links", self.create_gogo_maps, "m"),
|
|
89
|
-
MenuOption("Sync MAL list into seasonals", self.sync_mal_to_seasonals, "s"),
|
|
90
|
-
MenuOption(
|
|
91
|
-
"Sync seasonals into MAL list",
|
|
92
|
-
self.m_class.sync_seasonals_with_mal,
|
|
93
|
-
"b",
|
|
94
|
-
),
|
|
95
|
-
MenuOption(
|
|
96
|
-
"Download newest episodes", lambda: self.download(mode="latest"), "d"
|
|
97
|
-
),
|
|
98
|
-
MenuOption("Download all episodes", lambda: self.download(mode="all"), "x"),
|
|
99
|
-
MenuOption("Binge watch newest episodes", self.binge_latest, "w"),
|
|
100
|
-
MenuOption("Quit", self.quit, "q"),
|
|
101
|
-
]
|
|
102
|
-
|
|
103
|
-
def add_anime(self):
|
|
104
|
-
searches = []
|
|
105
|
-
if (
|
|
106
|
-
not self.options.no_season_search
|
|
107
|
-
and input("Search for anime in Season? (y|n): \n>> ") == "y"
|
|
108
|
-
):
|
|
109
|
-
searches = get_season_searches(gogo=False)
|
|
110
|
-
|
|
111
|
-
else:
|
|
112
|
-
searches.append(input("Search: "))
|
|
113
|
-
|
|
114
|
-
for search in searches:
|
|
115
|
-
if isinstance(search, dict):
|
|
116
|
-
mal_entry = search
|
|
117
|
-
|
|
118
|
-
else:
|
|
119
|
-
print("\nCurrent: ", search)
|
|
120
|
-
temp_search = self.m_class.get_anime(search)
|
|
121
|
-
names = [item["node"]["title"] for item in temp_search]
|
|
122
|
-
print_names(names)
|
|
123
|
-
selected = False
|
|
124
|
-
skip = False
|
|
125
|
-
while selected is False:
|
|
126
|
-
try:
|
|
127
|
-
sel_index = input("Select show (Number or c for cancel):\n")
|
|
128
|
-
if sel_index == "c":
|
|
129
|
-
skip = True
|
|
130
|
-
break
|
|
131
|
-
selected = int(sel_index) - 1
|
|
132
|
-
except ValueError:
|
|
133
|
-
print("Please enter a valid number.")
|
|
134
|
-
if skip:
|
|
135
|
-
continue
|
|
136
|
-
mal_entry = temp_search[selected]
|
|
137
|
-
|
|
138
|
-
self.m_class.update_anime_list(
|
|
139
|
-
mal_entry["node"]["id"], {"status": "watching"}
|
|
140
|
-
)
|
|
141
|
-
self.create_gogo_maps()
|
|
142
|
-
|
|
143
|
-
self.print_options()
|
|
144
|
-
|
|
145
|
-
def del_anime(self):
|
|
146
|
-
mal_list = self.m_class.get_anime_list()
|
|
147
|
-
mal_list = [x for x in mal_list]
|
|
148
|
-
mal_names = [n["node"]["title"] for n in mal_list]
|
|
149
|
-
print_names(mal_names)
|
|
150
|
-
while True:
|
|
151
|
-
inp = cinput(colors.CYAN, "Enter Number: ")
|
|
152
|
-
try:
|
|
153
|
-
picked = mal_list[int(inp) - 1]["node"]["id"]
|
|
154
|
-
break
|
|
155
|
-
except:
|
|
156
|
-
error("Invalid Input")
|
|
157
|
-
|
|
158
|
-
self.m_class.del_show(picked)
|
|
159
|
-
self.print_options()
|
|
160
|
-
|
|
161
|
-
def list_animes(self):
|
|
162
|
-
mal_list = self.m_class.get_anime_list()
|
|
163
|
-
for i in mal_list:
|
|
164
|
-
status = i["node"]["my_list_status"]["status"]
|
|
165
|
-
|
|
166
|
-
if status == "completed":
|
|
167
|
-
color = colors.MAGENTA
|
|
168
|
-
elif status == "on_hold":
|
|
169
|
-
color = colors.YELLOW
|
|
170
|
-
elif status == "plan_to_watch":
|
|
171
|
-
color = colors.BLUE
|
|
172
|
-
elif status == "dropped":
|
|
173
|
-
color = colors.ERROR
|
|
174
|
-
else:
|
|
175
|
-
color = colors.GREEN
|
|
176
|
-
|
|
177
|
-
cprint(
|
|
178
|
-
colors.CYAN,
|
|
179
|
-
"==> Last watched EP: {}".format(
|
|
180
|
-
i["node"]["my_list_status"]["num_episodes_watched"]
|
|
181
|
-
),
|
|
182
|
-
color,
|
|
183
|
-
" | ({}) | ".format(status),
|
|
184
|
-
colors.CYAN,
|
|
185
|
-
i["node"]["title"],
|
|
186
|
-
)
|
|
187
|
-
# List is empty
|
|
188
|
-
if not mal_list:
|
|
189
|
-
cprint(colors.YELLOW, "No anime found.\nAdd an anime to your list first.")
|
|
190
|
-
|
|
191
|
-
input("Enter to continue")
|
|
192
|
-
self.print_options()
|
|
193
|
-
|
|
194
|
-
def list_possible(self, latest_urls):
|
|
195
|
-
for i in latest_urls:
|
|
196
|
-
cprint(colors.RED, f"{i}:")
|
|
197
|
-
for j in latest_urls[i]["ep_list"]:
|
|
198
|
-
cprint(colors.CYAN, f"==> EP: {j[0]}")
|
|
199
|
-
|
|
200
|
-
def download(self, mode="all"):
|
|
201
|
-
print("Preparing list of episodes...")
|
|
202
|
-
if mode == "latest":
|
|
203
|
-
urls = self.m_class.latest_eps()
|
|
204
|
-
|
|
205
|
-
else:
|
|
206
|
-
urls = self.m_class.latest_eps(all_eps=True)
|
|
207
|
-
|
|
208
|
-
if not urls:
|
|
209
|
-
error("Nothing to download")
|
|
210
|
-
return
|
|
211
|
-
|
|
212
|
-
cprint(colors.CYAN, "Stuff to be downloaded:")
|
|
213
|
-
self.list_possible(urls)
|
|
214
|
-
if not self.options.auto_update:
|
|
215
|
-
cinput(colors.RED, "Enter to continue or CTRL+C to abort.")
|
|
216
|
-
|
|
217
|
-
for i in urls:
|
|
218
|
-
cprint(f"Downloading newest urls for {i}", colors.CYAN)
|
|
219
|
-
show_entry = Entry()
|
|
220
|
-
show_entry.show_name = i
|
|
221
|
-
for j in urls[i]["ep_list"]:
|
|
222
|
-
show_entry.embed_url = ""
|
|
223
|
-
show_entry.ep = j[0]
|
|
224
|
-
show_entry.ep_url = j[1]
|
|
225
|
-
url_class = videourl(show_entry, self.options.quality)
|
|
226
|
-
url_class.stream_url()
|
|
227
|
-
show_entry = url_class.get_entry()
|
|
228
|
-
download(
|
|
229
|
-
show_entry, self.options.quality, self.options.ffmpeg, self.dl_path
|
|
230
|
-
).download()
|
|
231
|
-
|
|
232
|
-
if not self.options.auto_update:
|
|
233
|
-
self.print_options()
|
|
234
|
-
|
|
235
|
-
def binge_latest(self):
|
|
236
|
-
latest_eps = self.m_class.latest_eps()
|
|
237
|
-
cprint(colors.CYAN, "Stuff to be watched:")
|
|
238
|
-
self.list_possible(latest_eps)
|
|
239
|
-
cinput(colors.RED, "Enter to continue or CTRL+C to abort.")
|
|
240
|
-
ep_list = []
|
|
241
|
-
ep_urls = []
|
|
242
|
-
ep_dic = {}
|
|
243
|
-
for i in latest_eps:
|
|
244
|
-
for j in latest_eps[i]["ep_list"]:
|
|
245
|
-
ep_list.append(j[0])
|
|
246
|
-
ep_urls.append(j[1])
|
|
247
|
-
|
|
248
|
-
ep_dic.update(
|
|
249
|
-
{
|
|
250
|
-
i: {
|
|
251
|
-
"ep_urls": [x for x in ep_urls],
|
|
252
|
-
"eps": [x for x in ep_list],
|
|
253
|
-
"category_url": latest_eps[i]["category_url"],
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
)
|
|
257
|
-
ep_list.clear()
|
|
258
|
-
ep_urls.clear()
|
|
259
|
-
|
|
260
|
-
player = get_player(self.rpc_client, self.options.optional_player)
|
|
261
|
-
binge(
|
|
262
|
-
ep_dic,
|
|
263
|
-
self.options.quality,
|
|
264
|
-
player=player,
|
|
265
|
-
mode="mal",
|
|
266
|
-
mal_class=self.m_class,
|
|
267
|
-
)
|
|
268
|
-
player.kill_player()
|
|
269
|
-
self.print_options()
|
|
270
|
-
|
|
271
|
-
def sync_mal_to_seasonals(self):
|
|
272
|
-
self.create_gogo_maps()
|
|
273
|
-
|
|
274
|
-
self.m_class.sync_mal_with_seasonal()
|
|
275
|
-
|
|
276
|
-
def manual_gogomap(self):
|
|
277
|
-
self.create_gogo_maps()
|
|
278
|
-
|
|
279
|
-
def create_gogo_maps(self):
|
|
280
|
-
if not self.options.auto_update and input(
|
|
281
|
-
"Try auto mapping MAL to gogo format? (y/n):\n"
|
|
282
|
-
).lower() in ["y", "yes"]:
|
|
283
|
-
self.m_class.auto_map_all_without_map()
|
|
284
|
-
failed_to_map = list(self.m_class.get_all_without_gogo_map())
|
|
285
|
-
failed_to_map.sort(key=len, reverse=True)
|
|
286
|
-
if not self.options.auto_update and len(failed_to_map) > 0:
|
|
287
|
-
cprint(colors.YELLOW, "Some Anime failed auto-mapping...")
|
|
288
|
-
cprint(colors.GREEN, "Select Anime for manual mapping:\n")
|
|
289
|
-
selected = []
|
|
290
|
-
searches = []
|
|
291
|
-
|
|
292
|
-
print_names(failed_to_map)
|
|
293
|
-
print("Selection: (e.g. 1, 1 3, 1-3 or * [for all]) \n")
|
|
294
|
-
cprint(colors.YELLOW, "Enter or n to skip...")
|
|
295
|
-
selection = cinput(colors.GREEN, ">>")
|
|
296
|
-
if selection.__contains__("-"):
|
|
297
|
-
selection_range = selection.strip(" ").split("-")
|
|
298
|
-
for i in range(
|
|
299
|
-
int(selection_range[0]) - 1, int(selection_range[1]) - 1, 1
|
|
300
|
-
):
|
|
301
|
-
selected.append(i)
|
|
302
|
-
|
|
303
|
-
elif selection in ["all", "*"]:
|
|
304
|
-
selected = range(0, len(failed_to_map) - 1)
|
|
305
|
-
elif selection in ["", "n", "N"]:
|
|
306
|
-
selected = []
|
|
307
|
-
|
|
308
|
-
else:
|
|
309
|
-
for i in selection.strip(" ").split(" "):
|
|
310
|
-
selected.append(int(i) - 1)
|
|
311
|
-
|
|
312
|
-
for value in selected:
|
|
313
|
-
show_entries = []
|
|
314
|
-
done = False
|
|
315
|
-
search_name = failed_to_map[value]
|
|
316
|
-
while not done:
|
|
317
|
-
cprint(
|
|
318
|
-
colors.GREEN,
|
|
319
|
-
"Current: ",
|
|
320
|
-
colors.CYAN,
|
|
321
|
-
f"{failed_to_map[value]}\n",
|
|
322
|
-
)
|
|
323
|
-
show_entry = Entry()
|
|
324
|
-
query_class = query(search_name, show_entry)
|
|
325
|
-
links_query = query_class.get_links()
|
|
326
|
-
|
|
327
|
-
if not links_query:
|
|
328
|
-
skip = False
|
|
329
|
-
while not links_query and not skip:
|
|
330
|
-
cprint(
|
|
331
|
-
colors.ERROR,
|
|
332
|
-
"No search results for ",
|
|
333
|
-
colors.YELLOW,
|
|
334
|
-
failed_to_map[value],
|
|
335
|
-
)
|
|
336
|
-
cprint(
|
|
337
|
-
colors.GREEN,
|
|
338
|
-
"Sometimes the names on GoGo are too different from the ones on MAL.\n",
|
|
339
|
-
)
|
|
340
|
-
cprint(colors.CYAN, "Try custom name for mapping? (Y/N):\n")
|
|
341
|
-
if input().lower() == "y":
|
|
342
|
-
query_class = query(
|
|
343
|
-
cinput(
|
|
344
|
-
colors.GREEN,
|
|
345
|
-
"Enter Search String to search on GoGo:\n",
|
|
346
|
-
),
|
|
347
|
-
show_entry,
|
|
348
|
-
)
|
|
349
|
-
links_query = query_class.get_links()
|
|
350
|
-
if links_query:
|
|
351
|
-
show = query_class.pick_show(cancelable=True)
|
|
352
|
-
if show:
|
|
353
|
-
show_entries.append(show_entry)
|
|
354
|
-
mapped = self.m_class.manual_map_gogo_mal(
|
|
355
|
-
failed_to_map[value],
|
|
356
|
-
{
|
|
357
|
-
"link": show_entry.category_url,
|
|
358
|
-
"name": show_entry.show_name,
|
|
359
|
-
},
|
|
360
|
-
)
|
|
361
|
-
if mapped:
|
|
362
|
-
del failed_to_map[value]
|
|
363
|
-
del selected[value]
|
|
364
|
-
else:
|
|
365
|
-
print("Skipping show")
|
|
366
|
-
skip = True
|
|
367
|
-
done = True
|
|
368
|
-
elif links_query[0] != 0:
|
|
369
|
-
links, names = links_query
|
|
370
|
-
search_another = True
|
|
371
|
-
while search_another and len(links) > 0:
|
|
372
|
-
show = query_class.pick_show(cancelable=True)
|
|
373
|
-
if show:
|
|
374
|
-
show_entries.append(show_entry)
|
|
375
|
-
self.m_class.manual_map_gogo_mal(
|
|
376
|
-
failed_to_map[value],
|
|
377
|
-
{
|
|
378
|
-
"link": show_entry.category_url,
|
|
379
|
-
"name": show_entry.show_name,
|
|
380
|
-
},
|
|
381
|
-
)
|
|
382
|
-
|
|
383
|
-
links.remove(
|
|
384
|
-
"/category/"
|
|
385
|
-
+ show_entry.category_url.split("/category/")[1]
|
|
386
|
-
)
|
|
387
|
-
names.remove(show_entry.show_name)
|
|
388
|
-
print(
|
|
389
|
-
f"{colors.GREEN} Added {show_entry.show_name} ...{colors.END}"
|
|
390
|
-
)
|
|
391
|
-
if input(
|
|
392
|
-
f"Add another show map to {failed_to_map[value]}? (y/n):\n"
|
|
393
|
-
).lower() not in ["y", "yes"]:
|
|
394
|
-
search_another = False
|
|
395
|
-
done = True
|
|
396
|
-
else:
|
|
397
|
-
search_name_parts = search_name.split(" ")
|
|
398
|
-
if len(search_name_parts) <= 1:
|
|
399
|
-
print(
|
|
400
|
-
f"{colors.YELLOW}Could not find {failed_to_map[value]} on gogo.{colors.END}"
|
|
401
|
-
)
|
|
402
|
-
done = True
|
|
403
|
-
else:
|
|
404
|
-
print(
|
|
405
|
-
f"{colors.YELLOW} Nothing found. Trying to shorten name...{colors.END}"
|
|
406
|
-
)
|
|
407
|
-
|
|
408
|
-
search_name_parts.pop()
|
|
409
|
-
search_name = " ".join(search_name_parts)
|
|
410
|
-
self.m_class.write_save_data()
|
|
411
|
-
self.m_class.write_mal_list()
|
anipy_cli/cli/menus/menu.py
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
from typing import List
|
|
3
|
-
|
|
4
|
-
from anipy_cli.arg_parser import CliArgs
|
|
5
|
-
from anipy_cli.colors import colors, cprint
|
|
6
|
-
from anipy_cli.misc import Entry, error
|
|
7
|
-
from anipy_cli.player import PlayerBaseType
|
|
8
|
-
from anipy_cli.url_handler import videourl, epHandler
|
|
9
|
-
from anipy_cli.query import query
|
|
10
|
-
from anipy_cli.download import download
|
|
11
|
-
from anipy_cli.config import Config
|
|
12
|
-
from anipy_cli.cli.menus.base_menu import MenuBase, MenuOption
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class Menu(MenuBase):
|
|
16
|
-
def __init__(
|
|
17
|
-
self, options: CliArgs, entry: Entry, player: PlayerBaseType, rpc_client=None
|
|
18
|
-
):
|
|
19
|
-
self.rpc_client = rpc_client
|
|
20
|
-
self.options = options
|
|
21
|
-
self.entry = entry
|
|
22
|
-
self.player = player
|
|
23
|
-
|
|
24
|
-
@property
|
|
25
|
-
def menu_options(self) -> List[MenuOption]:
|
|
26
|
-
return [
|
|
27
|
-
MenuOption("Next Episode", self.next_ep, "n"),
|
|
28
|
-
MenuOption("Previous Episode", self.prev_ep, "p"),
|
|
29
|
-
MenuOption("Replay Episode", self.repl_ep, "r"),
|
|
30
|
-
MenuOption("Select episode", self.selec_ep, "s"),
|
|
31
|
-
MenuOption("Search for Anime", self.search, "a"),
|
|
32
|
-
MenuOption("Print Video Info", self.video_info, "i"),
|
|
33
|
-
MenuOption("Download Episode", self.download_video, "d"),
|
|
34
|
-
MenuOption("Quit", self.quit, "q"),
|
|
35
|
-
]
|
|
36
|
-
|
|
37
|
-
def print_header(self):
|
|
38
|
-
cprint(
|
|
39
|
-
colors.GREEN,
|
|
40
|
-
f"Playing: {self.entry.show_name} {self.entry.quality} | ",
|
|
41
|
-
colors.RED,
|
|
42
|
-
f"{self.entry.ep}/{self.entry.latest_ep}",
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
def start_ep(self):
|
|
46
|
-
self.entry.embed_url = ""
|
|
47
|
-
url_class = videourl(self.entry, self.options.quality)
|
|
48
|
-
url_class.stream_url()
|
|
49
|
-
self.entry = url_class.get_entry()
|
|
50
|
-
self.player.play_title(self.entry)
|
|
51
|
-
|
|
52
|
-
def next_ep(self):
|
|
53
|
-
ep_class = epHandler(self.entry)
|
|
54
|
-
self.entry = ep_class.next_ep()
|
|
55
|
-
self.start_ep()
|
|
56
|
-
self.print_options()
|
|
57
|
-
|
|
58
|
-
def prev_ep(self):
|
|
59
|
-
ep_class = epHandler(self.entry)
|
|
60
|
-
self.entry = ep_class.prev_ep()
|
|
61
|
-
self.start_ep()
|
|
62
|
-
self.print_options()
|
|
63
|
-
|
|
64
|
-
def repl_ep(self):
|
|
65
|
-
self.start_ep()
|
|
66
|
-
|
|
67
|
-
def selec_ep(self):
|
|
68
|
-
ep_class = epHandler(self.entry)
|
|
69
|
-
self.entry = ep_class.pick_ep()
|
|
70
|
-
self.start_ep()
|
|
71
|
-
self.print_options()
|
|
72
|
-
|
|
73
|
-
def search(self):
|
|
74
|
-
query_class = query(input("Search: "), self.entry)
|
|
75
|
-
if query_class.get_links() == 0:
|
|
76
|
-
error("no search results")
|
|
77
|
-
return
|
|
78
|
-
else:
|
|
79
|
-
self.entry = query_class.pick_show()
|
|
80
|
-
ep_class = epHandler(self.entry)
|
|
81
|
-
self.entry = ep_class.pick_ep()
|
|
82
|
-
self.start_ep()
|
|
83
|
-
self.print_options()
|
|
84
|
-
|
|
85
|
-
def video_info(self):
|
|
86
|
-
print(f"Show Name: {self.entry.show_name}")
|
|
87
|
-
print(f"Category Url: {self.entry.category_url}")
|
|
88
|
-
print(f"Episode Url: {self.entry.ep_url}")
|
|
89
|
-
print(f"Episode: {self.entry.ep}")
|
|
90
|
-
print(f"Embed Url: {self.entry.embed_url}")
|
|
91
|
-
print(f"Stream Url: {self.entry.stream_url}")
|
|
92
|
-
print(f"Quality: {self.entry.quality}")
|
|
93
|
-
|
|
94
|
-
def download_video(self):
|
|
95
|
-
path = download(self.entry, self.options.quality).download()
|
|
96
|
-
if Config().auto_open_dl_defaultcli:
|
|
97
|
-
self.player.play_file(str(path))
|
|
98
|
-
self.print_options()
|
|
99
|
-
|
|
100
|
-
def quit(self):
|
|
101
|
-
self.player.kill_player()
|
|
102
|
-
sys.exit(0)
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
from typing import List
|
|
3
|
-
|
|
4
|
-
from anipy_cli.arg_parser import CliArgs
|
|
5
|
-
from anipy_cli.colors import colors, cprint, cinput
|
|
6
|
-
from anipy_cli.misc import Entry, print_names, error
|
|
7
|
-
from anipy_cli.player import get_player
|
|
8
|
-
from anipy_cli.url_handler import videourl, epHandler
|
|
9
|
-
from anipy_cli.query import query
|
|
10
|
-
from anipy_cli.download import download
|
|
11
|
-
from anipy_cli.config import Config
|
|
12
|
-
from anipy_cli.seasonal import Seasonal
|
|
13
|
-
from anipy_cli.cli.util import get_season_searches, binge
|
|
14
|
-
from anipy_cli.cli.menus.base_menu import MenuBase, MenuOption
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class SeasonalMenu(MenuBase, Seasonal):
|
|
18
|
-
def __init__(self, options: CliArgs, rpc_client=None):
|
|
19
|
-
super().__init__()
|
|
20
|
-
|
|
21
|
-
self.rpc_client = rpc_client
|
|
22
|
-
self.options = options
|
|
23
|
-
self.entry = Entry()
|
|
24
|
-
self.dl_path = Config().seasonals_dl_path
|
|
25
|
-
if options.location:
|
|
26
|
-
self.dl_path = options.location
|
|
27
|
-
|
|
28
|
-
@property
|
|
29
|
-
def menu_options(self) -> List[MenuOption]:
|
|
30
|
-
return [
|
|
31
|
-
MenuOption("Add Anime", self.add_anime, "a"),
|
|
32
|
-
MenuOption("Delete one anime from seasonals", self.del_anime, "e"),
|
|
33
|
-
MenuOption("List anime in seasonals file", self.list_animes, "l"),
|
|
34
|
-
MenuOption("Download newest episodes", self.download_latest, "d"),
|
|
35
|
-
MenuOption("Binge watch newest episodes", self.binge_latest, "w"),
|
|
36
|
-
MenuOption("Quit", self.quit, "q"),
|
|
37
|
-
]
|
|
38
|
-
|
|
39
|
-
def print_header(self):
|
|
40
|
-
pass
|
|
41
|
-
|
|
42
|
-
def add_anime(self):
|
|
43
|
-
show_entry = Entry()
|
|
44
|
-
is_season_search = False
|
|
45
|
-
searches = []
|
|
46
|
-
if (
|
|
47
|
-
not self.options.no_season_search
|
|
48
|
-
and input("Search for anime in Season? (y|n): \n>> ") == "y"
|
|
49
|
-
):
|
|
50
|
-
searches = get_season_searches()
|
|
51
|
-
|
|
52
|
-
else:
|
|
53
|
-
searches.append(input("Search: "))
|
|
54
|
-
|
|
55
|
-
for search in searches:
|
|
56
|
-
query_class = None
|
|
57
|
-
if isinstance(search, dict):
|
|
58
|
-
is_season_search = True
|
|
59
|
-
links = [search["category_url"]]
|
|
60
|
-
|
|
61
|
-
else:
|
|
62
|
-
print("\nCurrent: ", search)
|
|
63
|
-
query_class = query(search, show_entry)
|
|
64
|
-
query_class.get_pages()
|
|
65
|
-
links = query_class.get_links()
|
|
66
|
-
|
|
67
|
-
if links == 0:
|
|
68
|
-
error("no search results")
|
|
69
|
-
input("Enter to continue")
|
|
70
|
-
self.print_options()
|
|
71
|
-
|
|
72
|
-
if is_season_search:
|
|
73
|
-
show_entry = Entry()
|
|
74
|
-
show_entry.show_name = search["name"]
|
|
75
|
-
show_entry.category_url = search["category_url"]
|
|
76
|
-
|
|
77
|
-
else:
|
|
78
|
-
show_entry = query_class.pick_show()
|
|
79
|
-
|
|
80
|
-
picked_ep = epHandler(show_entry).pick_ep_seasonal().ep
|
|
81
|
-
self.add_show(show_entry.show_name, show_entry.category_url, picked_ep)
|
|
82
|
-
self.print_options()
|
|
83
|
-
|
|
84
|
-
def del_anime(self):
|
|
85
|
-
seasonals = self.list_seasonals()
|
|
86
|
-
seasonals = [x[0] for x in seasonals]
|
|
87
|
-
print_names(seasonals)
|
|
88
|
-
while True:
|
|
89
|
-
inp = cinput(colors.CYAN, "Enter Number: ")
|
|
90
|
-
try:
|
|
91
|
-
picked = seasonals[int(inp) - 1]
|
|
92
|
-
break
|
|
93
|
-
except:
|
|
94
|
-
error("Invalid Input")
|
|
95
|
-
|
|
96
|
-
self.del_show(picked)
|
|
97
|
-
|
|
98
|
-
self.print_options()
|
|
99
|
-
|
|
100
|
-
def list_animes(self):
|
|
101
|
-
for i in self.list_seasonals():
|
|
102
|
-
print(f"==> EP: {i[1]} | {i[0]}")
|
|
103
|
-
|
|
104
|
-
def list_possible(self, latest_urls):
|
|
105
|
-
for i in latest_urls:
|
|
106
|
-
cprint(colors.RED, f"{i}:")
|
|
107
|
-
for j in latest_urls[i]["ep_list"]:
|
|
108
|
-
cprint(colors.CYAN, f"==> EP: {j[0]}")
|
|
109
|
-
|
|
110
|
-
def download_latest(self):
|
|
111
|
-
latest_urls = self.latest_eps()
|
|
112
|
-
|
|
113
|
-
if not latest_urls:
|
|
114
|
-
error("Nothing to download")
|
|
115
|
-
return
|
|
116
|
-
|
|
117
|
-
print("Stuff to be downloaded:")
|
|
118
|
-
self.list_possible(latest_urls)
|
|
119
|
-
if not self.options.auto_update:
|
|
120
|
-
cinput(colors.RED, "Enter to continue or CTRL+C to abort.")
|
|
121
|
-
|
|
122
|
-
for i in latest_urls:
|
|
123
|
-
print(f"Downloading newest urls for {i}")
|
|
124
|
-
show_entry = Entry()
|
|
125
|
-
show_entry.show_name = i
|
|
126
|
-
for j in latest_urls[i]["ep_list"]:
|
|
127
|
-
show_entry.embed_url = ""
|
|
128
|
-
show_entry.ep = j[0]
|
|
129
|
-
show_entry.ep_url = j[1]
|
|
130
|
-
url_class = videourl(show_entry, self.options.quality)
|
|
131
|
-
url_class.stream_url()
|
|
132
|
-
show_entry = url_class.get_entry()
|
|
133
|
-
download(
|
|
134
|
-
show_entry, self.options.quality, self.options.ffmpeg, self.dl_path
|
|
135
|
-
).download()
|
|
136
|
-
|
|
137
|
-
if not self.options.auto_update:
|
|
138
|
-
self.print_options()
|
|
139
|
-
|
|
140
|
-
for i in latest_urls:
|
|
141
|
-
self.update_show(i, latest_urls[i]["category_url"])
|
|
142
|
-
|
|
143
|
-
def binge_latest(self):
|
|
144
|
-
latest_eps = self.latest_eps()
|
|
145
|
-
print("Stuff to be watched:")
|
|
146
|
-
self.list_possible(latest_eps)
|
|
147
|
-
cinput(colors.RED, "Enter to continue or CTRL+C to abort.")
|
|
148
|
-
ep_list = []
|
|
149
|
-
ep_urls = []
|
|
150
|
-
ep_dic = {}
|
|
151
|
-
for i in latest_eps:
|
|
152
|
-
for j in latest_eps[i]["ep_list"]:
|
|
153
|
-
ep_list.append(j[0])
|
|
154
|
-
ep_urls.append(j[1])
|
|
155
|
-
|
|
156
|
-
ep_dic.update(
|
|
157
|
-
{
|
|
158
|
-
i: {
|
|
159
|
-
"ep_urls": [x for x in ep_urls],
|
|
160
|
-
"eps": [x for x in ep_list],
|
|
161
|
-
"category_url": latest_eps[i]["category_url"],
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
)
|
|
165
|
-
ep_list.clear()
|
|
166
|
-
ep_urls.clear()
|
|
167
|
-
|
|
168
|
-
player = get_player(self.rpc_client, self.options.optional_player)
|
|
169
|
-
binge(ep_dic, self.options.quality, player, mode="seasonal")
|
|
170
|
-
player.kill_player()
|
|
171
|
-
for i in latest_eps:
|
|
172
|
-
self.update_show(i, latest_eps[i]["category_url"])
|
|
173
|
-
|
|
174
|
-
self.print_options()
|