anipy-cli 3.2.4__py3-none-any.whl → 3.3.1__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.

anipy_cli/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
1
  __appname__ = "anipy-cli"
2
- __version__ = "3.2.4"
2
+ __version__ = "3.3.1"
anipy_cli/config.py CHANGED
@@ -72,7 +72,7 @@ class Config:
72
72
 
73
73
  For an updated list of providers look here: https://sdaqo.github.io/anipy-cli/availabilty
74
74
 
75
- Supported providers (as of $version): gogoanime, yugenanime
75
+ Supported providers (as of $version): gogoanime, anivibe
76
76
 
77
77
  Examples:
78
78
  providers:
@@ -83,12 +83,12 @@ class Config:
83
83
  mal: ["provider2", "provider3"]
84
84
  """
85
85
  defaults = {
86
- "default": ["yugenanime"],
87
- "download": ["yugenanime"],
88
- "history": ["yugenanime"],
89
- "seasonal": ["yugenanime"],
90
- "binge": ["yugenanime"],
91
- "mal": ["yugenanime"],
86
+ "default": ["anivibe"],
87
+ "download": ["anivibe"],
88
+ "history": ["anivibe"],
89
+ "seasonal": ["anivibe"],
90
+ "binge": ["anivibe"],
91
+ "mal": ["anivibe"],
92
92
  }
93
93
 
94
94
  value = self._get_value("providers", defaults, dict)
anipy_cli/mal_proxy.py CHANGED
@@ -167,9 +167,15 @@ class MyAnimeListProxy:
167
167
  return mapping
168
168
 
169
169
  if self.local_list.mappings[anime.id].mappings:
170
- map = list(self.local_list.mappings[anime.id].mappings.values())[0]
171
- provider = next(filter(lambda x: x.NAME == map.provider, list_providers()))
172
- return Anime(provider(), map.name, map.identifier, map.languages)
170
+ for map in self.local_list.mappings[anime.id].mappings.values():
171
+ provider = next(
172
+ filter(lambda x: x.NAME == map.provider, list_providers()), None
173
+ )
174
+
175
+ if provider is None:
176
+ continue
177
+
178
+ return Anime(provider(), map.name, map.identifier, map.languages)
173
179
 
174
180
  config = Config()
175
181
  result = None
@@ -1,12 +1,15 @@
1
1
  import sys
2
2
  from typing import TYPE_CHECKING, List, Tuple
3
3
 
4
+ from anipy_api.mal import MyAnimeListAdapter
5
+
4
6
  from anipy_cli.download_component import DownloadComponent
5
7
 
6
8
  from anipy_api.anime import Anime
7
9
  from anipy_api.provider import LanguageTypeEnum
8
10
  from anipy_api.provider.base import Episode
9
11
  from anipy_api.locallist import LocalList, LocalListEntry
12
+ from anipy_api.error import ProviderNotAvailable
10
13
  from InquirerPy import inquirer
11
14
  from InquirerPy.base.control import Choice
12
15
  from InquirerPy.utils import get_style
@@ -17,11 +20,14 @@ from anipy_cli.menus.base_menu import MenuBase, MenuOption
17
20
  from anipy_cli.util import (
18
21
  DotSpinner,
19
22
  error,
23
+ find_closest,
20
24
  get_configured_player,
25
+ get_prefered_providers,
21
26
  migrate_locallist,
22
27
  )
23
28
  from anipy_cli.prompts import pick_episode_prompt, search_show_prompt, lang_prompt
24
29
 
30
+
25
31
  if TYPE_CHECKING:
26
32
  from anipy_cli.arg_parser import CliArgs
27
33
 
@@ -43,6 +49,7 @@ class SeasonalMenu(MenuBase):
43
49
  MenuOption("Add Anime", self.add_anime, "a"),
44
50
  MenuOption("Delete one anime from seasonals", self.del_anime, "e"),
45
51
  MenuOption("List anime in seasonals", self.list_animes, "l"),
52
+ MenuOption("Migrate to current provider", self.migrate_provider, "m"),
46
53
  MenuOption("Change dub/sub of anime in seasonals", self.change_lang, "c"),
47
54
  MenuOption("Download newest episodes", self.download_latest, "d"),
48
55
  MenuOption("Binge watch newest episodes", self.binge_latest, "w"),
@@ -56,7 +63,16 @@ class SeasonalMenu(MenuBase):
56
63
  with DotSpinner("Fetching status of shows in seasonals..."):
57
64
  choices = []
58
65
  for s in self.seasonal_list.get_all():
59
- anime = Anime.from_local_list_entry(s)
66
+ try:
67
+ anime = Anime.from_local_list_entry(s)
68
+ except ProviderNotAvailable:
69
+ error(
70
+ f"Can not load '{s.name}' because the configured provider"
71
+ f" '{s.provider}' was not found, maybe try to migrate"
72
+ " providers with 'm'."
73
+ )
74
+ continue
75
+
60
76
  lang = s.language
61
77
  episodes = anime.get_episodes(lang)
62
78
 
@@ -93,7 +109,7 @@ class SeasonalMenu(MenuBase):
93
109
  return choices or []
94
110
 
95
111
  def add_anime(self):
96
- anime = search_show_prompt("default")
112
+ anime = search_show_prompt("seasonal")
97
113
 
98
114
  if anime is None:
99
115
  return
@@ -192,6 +208,56 @@ class SeasonalMenu(MenuBase):
192
208
  for i in all_seasonals:
193
209
  print(i)
194
210
 
211
+ def migrate_provider(self):
212
+ config = Config()
213
+ all_seasonals = self.seasonal_list.get_all()
214
+ current_providers = list(get_prefered_providers("seasonal"))
215
+ print(
216
+ "Migrating to configured providers:",
217
+ ", ".join([p.NAME for p in current_providers]),
218
+ )
219
+ for s in all_seasonals:
220
+ if s.provider in [p.NAME for p in current_providers]:
221
+ continue
222
+
223
+ print(f"Mapping: {s.name}")
224
+
225
+ search_results: List[Anime] = []
226
+ for p in current_providers:
227
+ search_results.extend(
228
+ [Anime.from_search_result(p, r) for r in p.get_search(s.name)]
229
+ )
230
+
231
+ best_anime = None
232
+ best_ratio = 0
233
+ for r in search_results:
234
+ titles = {r.name}
235
+ titles |= set(r.get_info().alternative_names or [])
236
+ ratio = MyAnimeListAdapter._find_best_ratio(titles, {s.name})
237
+
238
+ if ratio > best_ratio:
239
+ best_ratio = ratio
240
+ best_anime = r
241
+
242
+ if best_ratio == 1:
243
+ break
244
+
245
+ if best_anime is None:
246
+ continue
247
+
248
+ if best_ratio >= config.mal_mapping_min_similarity:
249
+ self.seasonal_list.delete(s)
250
+ else:
251
+ print(f"Could not autmatically map {s.name}, you can map it manually.")
252
+ best_anime = search_show_prompt("seasonal", skip_season_search=True)
253
+ if best_anime is None:
254
+ continue
255
+
256
+ episode = find_closest(best_anime.get_episodes(s.language), s.episode)
257
+ self.seasonal_list.update(best_anime, language=s.language, episode=episode)
258
+
259
+ self.print_options(clear_screen=True)
260
+
195
261
  def download_latest(self):
196
262
  picked = self._choose_latest()
197
263
  total_eps = sum([len(e) for _a, _d, e in picked])
anipy_cli/util.py CHANGED
@@ -78,14 +78,24 @@ def get_prefered_providers(mode: str) -> Iterator["BaseProvider"]:
78
78
 
79
79
  if not preferred_providers:
80
80
  error(
81
- f"you have no providers set for {mode} mode, look into your config",
81
+ f"you have no providers set for '{mode}' mode, look into your config",
82
82
  fatal=True,
83
83
  )
84
84
 
85
+ providers = []
85
86
  for i in list_providers():
86
87
  if i.NAME in preferred_providers:
87
88
  url_override = config.provider_urls.get(i.NAME, None)
88
- yield i(url_override)
89
+ providers.append(i(url_override))
90
+
91
+ if not providers:
92
+ error(
93
+ f"there are no working providers for '{mode}' mode, look into your config",
94
+ fatal=True,
95
+ )
96
+
97
+ for p in providers:
98
+ yield p
89
99
 
90
100
 
91
101
  def get_download_path(
@@ -135,7 +145,7 @@ def parsenum(n: str):
135
145
  return float(n)
136
146
 
137
147
 
138
- def find_closest(episodes: List["Episode"], target: int) -> "Episode":
148
+ def find_closest(episodes: List["Episode"], target: "Episode") -> "Episode":
139
149
  left, right = 0, len(episodes) - 1
140
150
  while left < right:
141
151
  if abs(episodes[left] - target) <= abs(episodes[right] - target):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: anipy-cli
3
- Version: 3.2.4
3
+ Version: 3.3.1
4
4
  Summary: Watch and Download anime from the comfort of your Terminal
5
5
  Home-page: https://sdaqo.github.io/anipy-cli
6
6
  License: GPL-3.0
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.10
15
15
  Classifier: Programming Language :: Python :: 3.11
16
16
  Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Programming Language :: Python :: 3.13
18
- Requires-Dist: anipy-api (>=3.2.4,<4.0.0)
18
+ Requires-Dist: anipy-api (>=3.3.1,<4.0.0)
19
19
  Requires-Dist: appdirs (>=1.4.4,<2.0.0)
20
20
  Requires-Dist: inquirerpy (>=0.3.4,<0.4.0)
21
21
  Requires-Dist: pypresence (>=4.3.0,<5.0.0)
@@ -1,4 +1,4 @@
1
- anipy_cli/__init__.py,sha256=NhZk09M1CKoqll7LwLaDDAej6WK8EeB18GAYSlwtWKw,48
1
+ anipy_cli/__init__.py,sha256=VIX0DpDFvN9R1K0maY6aDEB5ofODHoiovUNhSW-ac0E,48
2
2
  anipy_cli/arg_parser.py,sha256=Y_p5Sh7LR0yeqfhFVXkyAbZMjDR1-NIoY_TVuPwUnwk,6009
3
3
  anipy_cli/cli.py,sha256=Ah5BE-u_SjcuzU5dQ5cSHtUloVRApCWwTK5i49yQtH8,1922
4
4
  anipy_cli/clis/__init__.py,sha256=Y00uiPWiMvvRImxJMvfLA55BOkMUOrrx5vJUNvquNsY,411
@@ -10,18 +10,18 @@ anipy_cli/clis/history_cli.py,sha256=2ccv6BpQQpUhY4K-KM7lO9qxVLXBrmCY5lec6czipSE
10
10
  anipy_cli/clis/mal_cli.py,sha256=_tSLgDUOa6GOZNyCncSSzaVj088y5GAKkHVRSndLLxk,2258
11
11
  anipy_cli/clis/seasonal_cli.py,sha256=GV2TQNm9UotG1cxfYbrFFgg7Jmy8SFa7w_GlFtPdRVE,616
12
12
  anipy_cli/colors.py,sha256=voXC7z1Fs9tHg4zzNTNMIrt9k-EVgJ3_xEf5KiW2xgo,916
13
- anipy_cli/config.py,sha256=R26KvF-mUDQ9uTqViHJn1gsrCk9TCj2ndVXW9jmQH9c,15955
13
+ anipy_cli/config.py,sha256=tVZk51QuX4V4BOIzyDYdQ6y6QKU69NkagAYXhcikHXY,15934
14
14
  anipy_cli/discord.py,sha256=c6mdqnEdblzZBYs3cGP66oDeS4ySm59OfTRP-R-Duls,1160
15
15
  anipy_cli/download_component.py,sha256=6N-7ItCj1hiqFu7falu6gvLp5KNYtfISMqlazHFPiAg,5098
16
- anipy_cli/mal_proxy.py,sha256=wIsku2_dl8vKD2K99L63OlzA3L5fl-VmyeiXC9VrxI4,6981
16
+ anipy_cli/mal_proxy.py,sha256=me2ESB442pYeNEpHY8mqrOEb477UA0uAg2LprKcp8sM,7098
17
17
  anipy_cli/menus/__init__.py,sha256=aIzbphxAW-QGfZwR1DIegFZuTJp1O3tSUnai0f0f4lY,185
18
18
  anipy_cli/menus/base_menu.py,sha256=g5b9Z7SpvCxcq_vqObcPzxLwcXeGPltLgSwa0sEzyfk,1140
19
19
  anipy_cli/menus/mal_menu.py,sha256=RBq80HG-rKUeJaDuT9ZCCZuujebb2Jc0xwo2Pedo3VQ,23690
20
20
  anipy_cli/menus/menu.py,sha256=iSEko3ckcLMOccwB8qJ2LE4j15Qgy0RMLWKY9jnAJrY,7985
21
- anipy_cli/menus/seasonal_menu.py,sha256=ZB0i37xdR5tERqPNDIdYS9cFLh2swFFQdvOdCD_CdkY,8245
21
+ anipy_cli/menus/seasonal_menu.py,sha256=t4LJMtempxf3OaqtOvGJoRJ1IhmxgFjsIgeSceKKnR4,10636
22
22
  anipy_cli/prompts.py,sha256=lQDrb8IlhsQhOpLG4sflamprTSn-PlCy41tGpXIowdo,10156
23
- anipy_cli/util.py,sha256=YPCYMmsXUhcikYvT9407Asie5qd20pvhqnK949JcirE,7992
24
- anipy_cli-3.2.4.dist-info/METADATA,sha256=-nk5ez9jJ1y_SUSKFWuuXqho42L1P7oiSuUwrr1WA5U,3469
25
- anipy_cli-3.2.4.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
26
- anipy_cli-3.2.4.dist-info/entry_points.txt,sha256=86iXpcm_ECFndrt0JAI2mqYfXC2Ar7mGi0iOaxCrNP0,51
27
- anipy_cli-3.2.4.dist-info/RECORD,,
23
+ anipy_cli/util.py,sha256=Y_kPyb3D0-lVipWIJFL3GNcnunSlQw4kNTzCzgRXOQg,8232
24
+ anipy_cli-3.3.1.dist-info/METADATA,sha256=IIYyezuJb1Y6f5gQ_0Ff8EjCwJLeQolLXMtEJbrNFAE,3469
25
+ anipy_cli-3.3.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
26
+ anipy_cli-3.3.1.dist-info/entry_points.txt,sha256=86iXpcm_ECFndrt0JAI2mqYfXC2Ar7mGi0iOaxCrNP0,51
27
+ anipy_cli-3.3.1.dist-info/RECORD,,