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.
Files changed (67) hide show
  1. anipy_cli/__init__.py +2 -20
  2. anipy_cli/anilist_proxy.py +229 -0
  3. anipy_cli/arg_parser.py +109 -21
  4. anipy_cli/cli.py +98 -0
  5. anipy_cli/clis/__init__.py +17 -0
  6. anipy_cli/clis/anilist_cli.py +62 -0
  7. anipy_cli/clis/base_cli.py +34 -0
  8. anipy_cli/clis/binge_cli.py +96 -0
  9. anipy_cli/clis/default_cli.py +115 -0
  10. anipy_cli/clis/download_cli.py +85 -0
  11. anipy_cli/clis/history_cli.py +96 -0
  12. anipy_cli/clis/mal_cli.py +71 -0
  13. anipy_cli/{cli/clis → clis}/seasonal_cli.py +9 -6
  14. anipy_cli/colors.py +14 -8
  15. anipy_cli/config.py +387 -90
  16. anipy_cli/discord.py +34 -0
  17. anipy_cli/download_component.py +194 -0
  18. anipy_cli/logger.py +200 -0
  19. anipy_cli/mal_proxy.py +228 -0
  20. anipy_cli/menus/__init__.py +6 -0
  21. anipy_cli/menus/anilist_menu.py +671 -0
  22. anipy_cli/{cli/menus → menus}/base_menu.py +9 -14
  23. anipy_cli/menus/mal_menu.py +657 -0
  24. anipy_cli/menus/menu.py +265 -0
  25. anipy_cli/menus/seasonal_menu.py +270 -0
  26. anipy_cli/prompts.py +387 -0
  27. anipy_cli/util.py +268 -0
  28. anipy_cli-3.8.2.dist-info/METADATA +71 -0
  29. anipy_cli-3.8.2.dist-info/RECORD +31 -0
  30. {anipy_cli-2.7.17.dist-info → anipy_cli-3.8.2.dist-info}/WHEEL +1 -2
  31. anipy_cli-3.8.2.dist-info/entry_points.txt +3 -0
  32. anipy_cli/cli/__init__.py +0 -1
  33. anipy_cli/cli/cli.py +0 -37
  34. anipy_cli/cli/clis/__init__.py +0 -6
  35. anipy_cli/cli/clis/base_cli.py +0 -43
  36. anipy_cli/cli/clis/binge_cli.py +0 -54
  37. anipy_cli/cli/clis/default_cli.py +0 -46
  38. anipy_cli/cli/clis/download_cli.py +0 -92
  39. anipy_cli/cli/clis/history_cli.py +0 -64
  40. anipy_cli/cli/clis/mal_cli.py +0 -27
  41. anipy_cli/cli/menus/__init__.py +0 -3
  42. anipy_cli/cli/menus/mal_menu.py +0 -411
  43. anipy_cli/cli/menus/menu.py +0 -102
  44. anipy_cli/cli/menus/seasonal_menu.py +0 -174
  45. anipy_cli/cli/util.py +0 -118
  46. anipy_cli/download.py +0 -454
  47. anipy_cli/history.py +0 -83
  48. anipy_cli/mal.py +0 -645
  49. anipy_cli/misc.py +0 -227
  50. anipy_cli/player/__init__.py +0 -1
  51. anipy_cli/player/player.py +0 -33
  52. anipy_cli/player/players/__init__.py +0 -3
  53. anipy_cli/player/players/base.py +0 -106
  54. anipy_cli/player/players/mpv.py +0 -19
  55. anipy_cli/player/players/mpv_contrl.py +0 -37
  56. anipy_cli/player/players/syncplay.py +0 -19
  57. anipy_cli/player/players/vlc.py +0 -18
  58. anipy_cli/query.py +0 -92
  59. anipy_cli/run_anipy_cli.py +0 -14
  60. anipy_cli/seasonal.py +0 -106
  61. anipy_cli/url_handler.py +0 -442
  62. anipy_cli/version.py +0 -1
  63. anipy_cli-2.7.17.dist-info/LICENSE +0 -674
  64. anipy_cli-2.7.17.dist-info/METADATA +0 -159
  65. anipy_cli-2.7.17.dist-info/RECORD +0 -43
  66. anipy_cli-2.7.17.dist-info/entry_points.txt +0 -2
  67. anipy_cli-2.7.17.dist-info/top_level.txt +0 -1
anipy_cli/misc.py DELETED
@@ -1,227 +0,0 @@
1
- import os
2
- import requests
3
- import sys
4
- import json
5
- import time
6
- from pypresence import Presence
7
- from pypresence.exceptions import DiscordNotFound
8
- from bs4 import BeautifulSoup
9
- from dataclasses import dataclass
10
- from typing import Union
11
-
12
- from anipy_cli.config import Config
13
- from anipy_cli.colors import colors, color, cprint
14
-
15
-
16
- @dataclass
17
- class Entry:
18
- """
19
- This is the class that saves
20
- metadata about a show.
21
- """
22
-
23
- show_name: str = ""
24
- category_url: str = ""
25
- ep_url: str = ""
26
- embed_url: str = ""
27
- stream_url: str = ""
28
- ep: Union[int, float] = 0
29
- latest_ep: Union[int, float] = 0
30
- quality: str = ""
31
-
32
-
33
- def clear_console():
34
- os.system("cls" if os.name == "nt" else "clear")
35
-
36
-
37
- def error(error: str) -> None:
38
- """
39
- Error function for better error handling,
40
- that takes an error and prints it to stderr.
41
- """
42
- sys.stderr.write(color(colors.ERROR, "anipy-cli: error: " + error) + "\n")
43
-
44
-
45
- def response_err(req, link) -> None:
46
- """
47
- Function that checks if a request
48
- was succesfull.
49
- """
50
- if req.ok:
51
- pass
52
- else:
53
- error(
54
- f"requested url not available/blocked: {link}: response-code: {req.status_code}"
55
- )
56
- sys.exit()
57
-
58
-
59
- def loc_err(soup, link: str, element: str) -> None:
60
- """
61
- Function that checks if beautifulsoup
62
- could locate an element.
63
- """
64
- if soup == None:
65
- error(f"could not locate {element}: {link}")
66
- sys.exit()
67
-
68
-
69
- def keyboard_inter() -> None:
70
- cprint(colors.ERROR, "\nanipy-cli: error: interrupted")
71
- sys.exit()
72
-
73
-
74
- def parsenum(n: str):
75
- """
76
- Parse String to either
77
- int or float.
78
- """
79
-
80
- try:
81
- return int(n)
82
- except ValueError:
83
- return float(n)
84
-
85
-
86
- def read_json(path):
87
- """
88
- Read a json file, if
89
- it doesn't exist create it,
90
- along with user_files folder.
91
- """
92
- while True:
93
- try:
94
- with open(path, "r") as data:
95
- json_data = json.load(data)
96
- break
97
-
98
- except FileNotFoundError:
99
- try:
100
- Config().user_files_path.mkdir(exist_ok=True, parents=True)
101
- path.touch(exist_ok=True)
102
- # avoids error on empty json file
103
- with path.open("a") as f:
104
- f.write("{}")
105
- continue
106
-
107
- except PermissionError:
108
- error(f"Unable to create {path} due to permissions.")
109
- sys.exit()
110
-
111
- return json_data
112
-
113
-
114
- def print_names(names):
115
- """
116
- Cli function that takes a
117
- list of names and prints
118
- them to the terminal.
119
- """
120
- for number, value in enumerate(names, 1):
121
- value_color = colors.END
122
- if number % 2 == 0:
123
- value_color = colors.YELLOW
124
-
125
- cprint(colors.GREEN, f"[{number}] ", value_color, value)
126
-
127
-
128
- def get_anime_info(category_url: str) -> dict:
129
- """
130
- Get metadata about an anime.
131
- """
132
- r = requests.get(category_url)
133
- soup = BeautifulSoup(r.text, "html.parser")
134
- info_body = soup.find("div", {"class": "anime_info_body_bg"})
135
- image_url = info_body.find("img")["src"]
136
- other_info = info_body.find_all("p", {"class": "type"})
137
- info_dict = {
138
- "image_url": image_url,
139
- "type": other_info[0].text.replace("\n", "").replace("Type: ", ""),
140
- "synopsis": other_info[1].text.replace("\n", ""),
141
- "genres": [
142
- x["title"]
143
- for x in BeautifulSoup(str(other_info[2]), "html.parser").find_all("a")
144
- ],
145
- "release_year": other_info[3].text.replace("Released: ", ""),
146
- "status": other_info[4].text.replace("\n", "").replace("Status: ", ""),
147
- }
148
-
149
- return info_dict
150
-
151
-
152
- def search_in_season_on_gogo(s_year, s_name):
153
- page = 1
154
- content = True
155
- gogo_anime_season_list = []
156
- while content:
157
- r = requests.get(
158
- f"{Config().gogoanime_url}/sub-category/{s_name}-{s_year}-anime",
159
- params={"page": page},
160
- )
161
- soup = BeautifulSoup(r.content, "html.parser")
162
- wrapper_div = soup.find("div", attrs={"class": "last_episodes"})
163
- try:
164
- anime_items = wrapper_div.findAll("li")
165
- for link in anime_items:
166
- link_a = link.find("p", attrs={"class": "name"}).find("a")
167
- name = link_a.get("title")
168
- gogo_anime_season_list.append(
169
- {
170
- "name": name,
171
- "category_url": "{}{}".format(
172
- Config().gogoanime_url, link_a.get("href")
173
- ),
174
- }
175
- )
176
-
177
- except AttributeError:
178
- content = False
179
-
180
- page += 1
181
- filtered_list = filter_anime_list_dub_sub(gogo_anime_season_list)
182
-
183
- return filtered_list
184
-
185
-
186
- def filter_anime_list_dub_sub(gogo_anime_season_list):
187
- if "sub" not in Config().anime_types and "dub" in Config().anime_types:
188
- filtered_list = [
189
- x for x in gogo_anime_season_list if "(dub)" in x["name"].lower()
190
- ]
191
-
192
- elif "dub" not in Config().anime_types and "sub" in Config().anime_types:
193
- filtered_list = [
194
- x for x in gogo_anime_season_list if "(dub)" not in x["name"].lower()
195
- ]
196
-
197
- else:
198
- filtered_list = gogo_anime_season_list
199
- return filtered_list
200
-
201
-
202
- def dc_presence_connect():
203
- CLIENT_ID = 966365883691855942
204
- rpc_client = None
205
- try:
206
- rpc_client = Presence(CLIENT_ID)
207
- rpc_client.connect()
208
- cprint(colors.GREEN, "Initialized Discord Presence Client")
209
- except DiscordNotFound:
210
- rpc_client = None
211
- cprint(colors.RED, "Discord is not opened, can't initialize Discord Presence")
212
- except ConnectionError:
213
- rpc_client = None
214
- cprint(colors.RED, "Can't Connect to discord.")
215
-
216
- return rpc_client
217
-
218
-
219
- def dc_presence(media_title, category_url, rpc_client):
220
- info = get_anime_info(category_url)
221
- rpc_client.update(
222
- details="Watching anime via anipy-cli",
223
- state=media_title,
224
- large_image=info["image_url"],
225
- small_image="https://github.com/Dankni95/ulauncher-anime/raw/master/images/icon.png",
226
- start=int(time.time()),
227
- )
@@ -1 +0,0 @@
1
- from anipy_cli.player.player import get_player, PlayerBaseType
@@ -1,33 +0,0 @@
1
- import sys
2
- from typing import TypeVar
3
-
4
- from anipy_cli.config import Config
5
- from anipy_cli.misc import error
6
- from anipy_cli.player.players import Mpv, Vlc, Syncplay
7
- from anipy_cli.player.players.base import PlayerBase
8
-
9
- PlayerBaseType = TypeVar("PlayerBaseType", bound=PlayerBase)
10
-
11
-
12
- def get_player(rpc_client=None, player_override=None) -> PlayerBaseType:
13
- cfg = Config()
14
-
15
- player = player_override
16
-
17
- if not player_override:
18
- player = cfg.player_path
19
-
20
- if player == "mpv" and cfg.reuse_mpv_window:
21
- from anipy_cli.player.players.mpv_contrl import MpvControllable
22
-
23
- return MpvControllable(rpc_client=rpc_client)
24
-
25
- if player in ("mpv", "mpvnet"):
26
- return Mpv(rpc_client=rpc_client, mpv_exec_name=player)
27
- elif player == "vlc":
28
- return Vlc(rpc_client=rpc_client)
29
- elif player == "syncplay":
30
- return Syncplay(rpc_client=rpc_client)
31
- else:
32
- error(f"Specified player `{player}` is unknown")
33
- sys.exit()
@@ -1,3 +0,0 @@
1
- from anipy_cli.player.players.mpv import Mpv
2
- from anipy_cli.player.players.vlc import Vlc
3
- from anipy_cli.player.players.syncplay import Syncplay
@@ -1,106 +0,0 @@
1
- import os
2
- import subprocess as sp
3
- import sys
4
- from typing import List
5
- from abc import ABC, abstractmethod
6
-
7
- from anipy_cli.colors import cprint, colors
8
- from anipy_cli.history import history
9
- from anipy_cli.misc import dc_presence, Entry
10
-
11
-
12
- class PlayerBase(ABC):
13
- @property
14
- @abstractmethod
15
- def rpc_client(self):
16
- pass
17
-
18
- @abstractmethod
19
- def play_title(self, entry: Entry):
20
- pass
21
-
22
- @abstractmethod
23
- def play_file(self, path: str):
24
- pass
25
-
26
- @abstractmethod
27
- def wait(self):
28
- pass
29
-
30
- @abstractmethod
31
- def kill_player(self):
32
- pass
33
-
34
- def _start_dc_presence(self, entry: Entry):
35
- if self.rpc_client:
36
- dc_media_title = f"{entry.show_name} | {entry.ep}/{entry.latest_ep}"
37
- dc_presence(dc_media_title, entry.category_url, self.rpc_client)
38
-
39
- @staticmethod
40
- def _write_hist(entry: Entry):
41
- history(entry).write_hist()
42
-
43
- @staticmethod
44
- def _get_media_title(entry: Entry):
45
- return (
46
- entry.show_name
47
- + " - Episode: "
48
- + str(entry.ep)
49
- + " - "
50
- + str(entry.quality)
51
- )
52
-
53
-
54
- class SubProcessPlayerBase(PlayerBase):
55
- def __init__(
56
- self, player_args_template: List[str], player_exec: str, rpc_client=None
57
- ):
58
- self._rpc_client = rpc_client
59
- self._sub_proc = None
60
- self._player_args_template = player_args_template
61
- self._player_exec = player_exec
62
-
63
- @property
64
- def rpc_client(self):
65
- return self._rpc_client
66
-
67
- def play_title(self, entry):
68
- player_cmd = [
69
- i.format(media_title=self._get_media_title(entry), **vars(entry))
70
- for i in self._player_args_template
71
- ]
72
- player_cmd.insert(0, self._player_exec)
73
-
74
- if isinstance(self._sub_proc, sp.Popen):
75
- self.kill_player()
76
-
77
- self._sub_proc = self._open_sproc(player_cmd)
78
-
79
- self._write_hist(entry)
80
- self._start_dc_presence(entry)
81
-
82
- def play_file(self, path):
83
- if isinstance(self._sub_proc, sp.Popen):
84
- self.kill_player()
85
-
86
- player_cmd = [self._player_exec, path]
87
- self._sub_proc = self._open_sproc(player_cmd)
88
-
89
- def wait(self):
90
- self._sub_proc.wait()
91
-
92
- def kill_player(self):
93
- self._sub_proc.kill()
94
-
95
- @staticmethod
96
- def _open_sproc(player_command: List[str]) -> sp.Popen:
97
- try:
98
- if os.name in ("nt", "dos"):
99
- sub_proc = sp.Popen(player_command)
100
- else:
101
- sub_proc = sp.Popen(player_command, stdout=sp.PIPE, stderr=sp.DEVNULL)
102
- except FileNotFoundError as e:
103
- cprint(colors.RED, "Error:" + str(e))
104
- sys.exit()
105
-
106
- return sub_proc
@@ -1,19 +0,0 @@
1
- from anipy_cli.player.players.base import SubProcessPlayerBase
2
- from anipy_cli.config import Config
3
-
4
-
5
- class Mpv(SubProcessPlayerBase):
6
- def __init__(self, rpc_client=None, mpv_exec_name: str = "mpv"):
7
- player_args_template = [
8
- "{stream_url}",
9
- "--force-media-title={media_title}",
10
- "--referrer={embed_url}",
11
- "--force-window=immediate",
12
- *Config().mpv_commandline_options,
13
- ]
14
-
15
- super().__init__(
16
- player_args_template=player_args_template,
17
- rpc_client=rpc_client,
18
- player_exec=mpv_exec_name,
19
- )
@@ -1,37 +0,0 @@
1
- import mpv
2
-
3
- from anipy_cli.player.players.base import PlayerBase
4
-
5
-
6
- class MpvControllable(mpv.MPV, PlayerBase):
7
- def __init__(self, rpc_client=None):
8
- super().__init__(
9
- input_default_bindings=True,
10
- input_vo_keyboard=True,
11
- force_window="immediate",
12
- title="MPV - Receiving Links from anipy-cli",
13
- osc=True,
14
- )
15
- self._rpc_client = rpc_client
16
-
17
- @property
18
- def rpc_client(self):
19
- return self._rpc_client
20
-
21
- def play_title(self, entry):
22
- self.force_media_title = self._get_media_title(entry)
23
-
24
- self.referrer = entry.embed_url
25
- self.play(entry.stream_url)
26
-
27
- self._write_hist(entry)
28
- self._start_dc_presence(entry)
29
-
30
- def play_file(self, path: str):
31
- self.play(path)
32
-
33
- def wait(self):
34
- self.wait_for_playback()
35
-
36
- def kill_player(self):
37
- self.terminate()
@@ -1,19 +0,0 @@
1
- from anipy_cli.player.players.base import SubProcessPlayerBase
2
- from anipy_cli.config import Config
3
-
4
-
5
- class Syncplay(SubProcessPlayerBase):
6
- def __init__(self, rpc_client=None):
7
- self.player_exec = "syncplay"
8
- player_args_template = [
9
- "--" "--http-referrer='{embed_url}'",
10
- "--meta-title='{media_title}'",
11
- "{stream_url}",
12
- *Config().mpv_commandline_options,
13
- ]
14
-
15
- super().__init__(
16
- rpc_client=rpc_client,
17
- player_exec=self.player_exec,
18
- player_args_template=player_args_template,
19
- )
@@ -1,18 +0,0 @@
1
- from anipy_cli.player.players.base import SubProcessPlayerBase
2
- from anipy_cli.config import Config
3
-
4
-
5
- class Vlc(SubProcessPlayerBase):
6
- def __init__(self, rpc_client=None):
7
- player_args_template = [
8
- "--http-referrer='{embed_url}'",
9
- "--meta-title='{media_title}'",
10
- "{stream_url}",
11
- *Config().vlc_commandline_options,
12
- ]
13
-
14
- super().__init__(
15
- rpc_client=rpc_client,
16
- player_args_template=player_args_template,
17
- player_exec="vlc",
18
- )
anipy_cli/query.py DELETED
@@ -1,92 +0,0 @@
1
- import requests
2
- import re
3
- from bs4 import BeautifulSoup
4
-
5
- from anipy_cli.misc import loc_err, response_err, error, print_names
6
- from anipy_cli.colors import colors, cinput
7
- from anipy_cli.config import Config
8
-
9
- base_url = Config().gogoanime_url
10
-
11
-
12
- class query:
13
- """
14
- Class to get query results
15
- from a search parameter.
16
- Takes an empty entry or one
17
- with fields filled.
18
- """
19
-
20
- def __init__(self, search_param, entry) -> None:
21
- self.entry = entry
22
- self.search_url = base_url + f"/search.html?keyword={search_param}"
23
- r = requests.get(self.search_url)
24
- response_err(r, self.search_url)
25
- self.soup = BeautifulSoup(r.content, "html.parser")
26
-
27
- def get_pages(self):
28
- """Get count of result pages of query"""
29
- pages = self.soup.find_all(
30
- "a", attrs={"data-page": re.compile(r"^ *\d[\d ]*$")}
31
- )
32
- loc_err(pages, self.search_url, "page-count")
33
- pages = [x.get("data-page") for x in pages]
34
- try:
35
- self.pages = int(pages[-1])
36
- except:
37
- self.pages = 1
38
-
39
- def get_links(self):
40
- """
41
- Get all category links and names of a query
42
- and returns them.
43
- """
44
- self.get_pages()
45
- self.links = []
46
- self.names = []
47
- for i in range(self.pages):
48
- req_link = self.search_url + f"&page={i + 1}"
49
- r = requests.get(req_link)
50
- response_err(r, req_link)
51
- self.soup = BeautifulSoup(r.content, "html.parser")
52
-
53
- for link in self.soup.find_all("p", attrs={"class": "name"}):
54
- name_lower = link.text.lower()
55
- if len(Config().anime_types) == 1:
56
- if "sub" in Config().anime_types and "(dub)" in name_lower:
57
- continue
58
- elif "dub" in Config().anime_types and "(dub)" not in name_lower:
59
- continue
60
-
61
- loc_err(link, req_link, "query results")
62
- self.names.append(link.text.replace("\n", ""))
63
- a_tag = link.findChildren("a", recursive=False)
64
- self.links.append(a_tag[0].get("href"))
65
-
66
- if not self.links:
67
- return 0
68
- else:
69
- return self.links, self.names
70
-
71
- def pick_show(self, cancelable=False):
72
- """
73
- Cli Function that
74
- Lets you pick a show from
75
- yout query, filles the category_url
76
- field from the entry and returns it.
77
- """
78
- print_names(self.names)
79
- if cancelable:
80
- print(f"{colors.GREEN}[C] {colors.YELLOW} Cancel.")
81
- while True:
82
- inp = cinput("Enter Number: ", colors.CYAN)
83
- try:
84
- self.entry.category_url = base_url + self.links[int(inp) - 1]
85
- self.entry.show_name = self.names[int(inp) - 1]
86
- break
87
- except:
88
- if cancelable and inp.lower() == "c":
89
- return False
90
- error("Invalid Input")
91
-
92
- return self.entry
@@ -1,14 +0,0 @@
1
- #!/bin/python
2
- from anipy_cli import cli
3
- from anipy_cli.misc import keyboard_inter
4
-
5
-
6
- def main():
7
- try:
8
- cli.run_cli()
9
- except KeyboardInterrupt:
10
- keyboard_inter()
11
-
12
-
13
- if __name__ == "__main__":
14
- main()
anipy_cli/seasonal.py DELETED
@@ -1,106 +0,0 @@
1
- import json
2
- import sys
3
-
4
- from anipy_cli.config import Config
5
- from anipy_cli.url_handler import epHandler
6
- from anipy_cli.misc import Entry, error, read_json
7
-
8
-
9
- class Seasonal:
10
- def __init__(self):
11
- self.entry = Entry()
12
-
13
- def latest_eps(self):
14
- """
15
- returns a dict like so:
16
- {"name": {
17
- "ep_list": [[ep, ep-link], [], ...],
18
- "category_url": "https://"
19
- },
20
- "another anime": {
21
- ...
22
- },
23
- }
24
- """
25
-
26
- self.read_save_data()
27
- names = [i for i in self.json]
28
- categ_urls = []
29
- user_eps = []
30
- for i in names:
31
- categ_urls.append(self.json[i]["category_url"])
32
- user_eps.append(self.json[i]["ep"])
33
-
34
- latest_urls = {}
35
- for i, e, n in zip(categ_urls, user_eps, names):
36
- self.entry.category_url = i
37
- ep_class = epHandler(self.entry)
38
- latest = ep_class.get_latest()
39
- eps_range = list(range(e + 1, latest + 1))
40
- ep_urls = []
41
- for j in eps_range:
42
- self.entry.ep = j
43
- ep_class = epHandler(self.entry)
44
- entry = ep_class.gen_eplink()
45
- ep_urls.append([j, entry.ep_url])
46
-
47
- latest_urls.update({n: {"ep_list": ep_urls, "category_url": i}})
48
-
49
- return latest_urls
50
-
51
- def read_save_data(self):
52
- self.json = read_json(Config().seasonal_file_path)
53
-
54
- def write_seasonals(self):
55
- try:
56
- with Config().seasonal_file_path.open("w") as f:
57
- json.dump(self.json, f, indent=4)
58
-
59
- except PermissionError:
60
- error("Unable to write to history file due permissions.")
61
- sys.exit()
62
-
63
- def update_show(self, name, categ_url, ep=None):
64
- self.read_save_data()
65
-
66
- if name not in [x for x in self.json]:
67
- return 0
68
-
69
- self.entry.category_url = categ_url
70
- if ep is not None:
71
- self.json[name]["ep"] = ep
72
-
73
- else:
74
- self.json[name]["ep"] = epHandler(self.entry).get_latest()
75
- self.write_seasonals()
76
-
77
- def add_show(self, name, categ_url, start_ep):
78
- self.read_save_data()
79
-
80
- if name in [x for x in self.json]:
81
- return 0
82
-
83
- dic = {name: {"ep": start_ep, "category_url": categ_url}}
84
-
85
- self.json.update(dic)
86
- self.write_seasonals()
87
-
88
- def del_show(self, name):
89
- self.read_save_data()
90
-
91
- if name not in [x for x in self.json]:
92
- return 0
93
-
94
- self.json.pop(name)
95
- self.write_seasonals()
96
-
97
- def list_seasonals(self):
98
- self.read_save_data()
99
-
100
- return [[i, self.json[i]["ep"]] for i in self.json]
101
-
102
- def export_seasonals(self):
103
- self.read_save_data()
104
- return [
105
- [i, self.json[i]["category_url"], self.json[i]["ep"]] for i in self.json
106
- ]