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/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 successful.
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,35 +0,0 @@
1
- import sys
2
- from typing import TypeVar
3
- from pathlib import Path
4
-
5
- from anipy_cli.config import Config
6
- from anipy_cli.misc import error
7
- from anipy_cli.player.players import Mpv, Vlc, Syncplay
8
- from anipy_cli.player.players.base import PlayerBase
9
-
10
- PlayerBaseType = TypeVar("PlayerBaseType", bound=PlayerBase)
11
-
12
-
13
- def get_player(rpc_client=None, player_override="") -> PlayerBaseType:
14
- cfg = Config()
15
-
16
- player = player_override
17
-
18
- if not player_override:
19
- player = cfg.player_path
20
-
21
- player = Path(player)
22
-
23
- if Path(player.name).stem == "mpv" and cfg.reuse_mpv_window:
24
- from anipy_cli.player.players.mpv_control import MpvControllable
25
- return MpvControllable(rpc_client=rpc_client)
26
-
27
- player_dict = {"mpv": Mpv, "mpvnet": Mpv, "vlc": Vlc, "syncplay": Syncplay}
28
-
29
- player_class = player_dict.get(Path(player.name).stem, None)
30
-
31
- if player_class:
32
- return player_class(str(player), rpc_client=rpc_client)
33
- else:
34
- error(f"Specified player `{player}` is unknown")
35
- 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,107 +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.config import Config
9
- from anipy_cli.history import history
10
- from anipy_cli.misc import dc_presence, Entry
11
-
12
-
13
- class PlayerBase(ABC):
14
- @property
15
- @abstractmethod
16
- def rpc_client(self):
17
- pass
18
-
19
- @abstractmethod
20
- def play_title(self, entry: Entry):
21
- pass
22
-
23
- @abstractmethod
24
- def play_file(self, path: str):
25
- pass
26
-
27
- @abstractmethod
28
- def wait(self):
29
- pass
30
-
31
- @abstractmethod
32
- def kill_player(self):
33
- pass
34
-
35
- def _start_dc_presence(self, entry: Entry):
36
- if self.rpc_client:
37
- dc_media_title = f"{entry.show_name} | {entry.ep}/{entry.latest_ep}"
38
- dc_presence(dc_media_title, entry.category_url, self.rpc_client)
39
-
40
- @staticmethod
41
- def _write_hist(entry: Entry):
42
- history(entry).write_hist()
43
-
44
- @staticmethod
45
- def _get_media_title(entry: Entry):
46
- return (
47
- entry.show_name
48
- + " - Episode: "
49
- + str(entry.ep)
50
- + " - "
51
- + str(entry.quality)
52
- )
53
-
54
-
55
- class SubProcessPlayerBase(PlayerBase):
56
- def __init__(
57
- self, player_args_template: List[str], player_path: str, rpc_client=None
58
- ):
59
- self._rpc_client = rpc_client
60
- self._sub_proc = None
61
- self._player_args_template = player_args_template
62
- self._player_exec = player_path
63
-
64
- @property
65
- def rpc_client(self):
66
- return self._rpc_client
67
-
68
- def play_title(self, entry):
69
- player_cmd = [
70
- i.format(media_title=self._get_media_title(entry), **vars(entry))
71
- for i in self._player_args_template
72
- ]
73
- player_cmd.insert(0, self._player_exec)
74
-
75
- if isinstance(self._sub_proc, sp.Popen):
76
- self.kill_player()
77
-
78
- self._sub_proc = self._open_sproc(player_cmd)
79
-
80
- self._write_hist(entry)
81
- self._start_dc_presence(entry)
82
-
83
- def play_file(self, path):
84
- if isinstance(self._sub_proc, sp.Popen):
85
- self.kill_player()
86
-
87
- player_cmd = [self._player_exec, path]
88
- self._sub_proc = self._open_sproc(player_cmd)
89
-
90
- def wait(self):
91
- self._sub_proc.wait()
92
-
93
- def kill_player(self):
94
- self._sub_proc.kill()
95
-
96
- @staticmethod
97
- def _open_sproc(player_command: List[str]) -> sp.Popen:
98
- try:
99
- if os.name in ("nt", "dos"):
100
- sub_proc = sp.Popen(player_command)
101
- else:
102
- sub_proc = sp.Popen(player_command, stdout=sp.PIPE, stderr=sp.DEVNULL)
103
- except FileNotFoundError as e:
104
- cprint(colors.RED, "Error:" + str(e))
105
- sys.exit()
106
-
107
- 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, player_path: str, rpc_client=None):
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
- player_path=player_path,
18
- rpc_client=rpc_client,
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, player_path: str, 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_path=player_path,
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, player_path: str, 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_path=player_path,
17
- player_args_template=player_args_template,
18
- )
anipy_cli/query.py DELETED
@@ -1,100 +0,0 @@
1
- import requests
2
- import re
3
- from bs4 import BeautifulSoup
4
- from yaspin import yaspin
5
- from yaspin.spinners import Spinners
6
-
7
-
8
- from anipy_cli.misc import loc_err, response_err, error, print_names
9
- from anipy_cli.colors import colors, cinput
10
- from anipy_cli.config import Config
11
-
12
- base_url = Config().gogoanime_url
13
-
14
-
15
- class query:
16
- """
17
- Class to get query results
18
- from a search parameter.
19
- Takes an empty entry or one
20
- with fields filled.
21
- """
22
-
23
- def __init__(self, search_param, entry) -> None:
24
- with yaspin() as spinner:
25
- spinner.text = f"Searching for {colors.BLUE}{search_param}{colors.END}"
26
- spinner.spinner = Spinners.dots
27
- spinner.color = "cyan"
28
- self.entry = entry
29
- self.search_url = base_url + f"/search.html?keyword={search_param}"
30
- r = requests.get(self.search_url)
31
- response_err(r, self.search_url)
32
- self.soup = BeautifulSoup(r.content, "html.parser")
33
- spinner.ok("✓")
34
-
35
- def get_pages(self):
36
- """Get count of result pages of query"""
37
- pages = self.soup.find_all(
38
- "a", attrs={"data-page": re.compile(r"^ *\d[\d ]*$")}
39
- )
40
- loc_err(pages, self.search_url, "page-count")
41
- pages = [x.get("data-page") for x in pages]
42
- try:
43
- self.pages = int(pages[-1])
44
- except:
45
- self.pages = 1
46
-
47
- def get_links(self):
48
- """
49
- Get all category links and names of a query
50
- and returns them.
51
- """
52
- self.get_pages()
53
- self.links = []
54
- self.names = []
55
- for i in range(self.pages):
56
- req_link = self.search_url + f"&page={i + 1}"
57
- r = requests.get(req_link)
58
- response_err(r, req_link)
59
- self.soup = BeautifulSoup(r.content, "html.parser")
60
-
61
- for link in self.soup.find_all("p", attrs={"class": "name"}):
62
- name_lower = link.text.lower()
63
- if len(Config().anime_types) == 1:
64
- if "sub" in Config().anime_types and "(dub)" in name_lower:
65
- continue
66
- elif "dub" in Config().anime_types and "(dub)" not in name_lower:
67
- continue
68
-
69
- loc_err(link, req_link, "query results")
70
- self.names.append(link.text.replace("\n", ""))
71
- a_tag = link.findChildren("a", recursive=False)
72
- self.links.append(a_tag[0].get("href"))
73
-
74
- if not self.links:
75
- return 0
76
- else:
77
- return self.links, self.names
78
-
79
- def pick_show(self, cancelable=False):
80
- """
81
- Cli Function that
82
- Lets you pick a show from
83
- yout query, filled the category_url
84
- field from the entry and returns it.
85
- """
86
- print_names(self.names)
87
- if cancelable:
88
- print(f"{colors.GREEN}[C] {colors.YELLOW} Cancel.")
89
- while True:
90
- inp = cinput("Enter Number: ", colors.CYAN)
91
- try:
92
- self.entry.category_url = base_url + self.links[int(inp) - 1]
93
- self.entry.show_name = self.names[int(inp) - 1]
94
- break
95
- except:
96
- if cancelable and inp.lower() == "c":
97
- return False
98
- error("Invalid Input")
99
-
100
- 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,112 +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
- from anipy_cli.misc import parsenum
8
-
9
-
10
- class Seasonal:
11
- def __init__(self):
12
- self.entry = Entry()
13
-
14
- def latest_eps(self):
15
- """
16
- returns a dict like so:
17
- {"name": {
18
- "ep_list": [[ep, ep-link], [], ...],
19
- "category_url": "https://"
20
- },
21
- "another anime": {
22
- ...
23
- },
24
- }
25
- """
26
-
27
- self.read_save_data()
28
- names = [i for i in self.json]
29
- categ_urls = []
30
- user_eps = []
31
- for i in names:
32
- categ_urls.append(self.json[i]["category_url"])
33
- user_eps.append(self.json[i]["ep"])
34
-
35
- latest_urls = {}
36
- for i, e, n in zip(categ_urls, user_eps, names):
37
- self.entry.category_url = i
38
- ep_class = epHandler(self.entry)
39
-
40
- eps_range = ep_class._load_eps_list()
41
- for j in eps_range:
42
- if parsenum(j["ep"]) == e:
43
- eps_range = eps_range[eps_range.index(j) + 1 :]
44
- break
45
-
46
- ep_urls = []
47
- for j in eps_range:
48
- self.entry.ep = parsenum(j["ep"])
49
- ep_class = epHandler(self.entry)
50
- entry = ep_class.gen_eplink()
51
- ep_urls.append([parsenum(j["ep"]), entry.ep_url])
52
-
53
- latest_urls.update({n: {"ep_list": ep_urls, "category_url": i}})
54
-
55
- return latest_urls
56
-
57
- def read_save_data(self):
58
- self.json = read_json(Config().seasonal_file_path)
59
-
60
- def write_seasonals(self):
61
- try:
62
- with Config().seasonal_file_path.open("w") as f:
63
- json.dump(self.json, f, indent=4)
64
-
65
- except PermissionError:
66
- error("Unable to write to history file due permissions.")
67
- sys.exit()
68
-
69
- def update_show(self, name, categ_url, ep=None):
70
- self.read_save_data()
71
-
72
- if name not in [x for x in self.json]:
73
- return 0
74
-
75
- self.entry.category_url = categ_url
76
- if ep is not None:
77
- self.json[name]["ep"] = ep
78
-
79
- else:
80
- self.json[name]["ep"] = epHandler(self.entry).get_latest()
81
- self.write_seasonals()
82
-
83
- def add_show(self, name, categ_url, start_ep):
84
- self.read_save_data()
85
-
86
- if name in [x for x in self.json]:
87
- return 0
88
-
89
- dic = {name: {"ep": start_ep, "category_url": categ_url}}
90
-
91
- self.json.update(dic)
92
- self.write_seasonals()
93
-
94
- def del_show(self, name):
95
- self.read_save_data()
96
-
97
- if name not in [x for x in self.json]:
98
- return 0
99
-
100
- self.json.pop(name)
101
- self.write_seasonals()
102
-
103
- def list_seasonals(self):
104
- self.read_save_data()
105
-
106
- return [[i, self.json[i]["ep"]] for i in self.json]
107
-
108
- def export_seasonals(self):
109
- self.read_save_data()
110
- return [
111
- [i, self.json[i]["category_url"], self.json[i]["ep"]] for i in self.json
112
- ]