anipy-cli 3.6.0__py3-none-any.whl → 3.8.0__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.6.0"
2
+ __version__ = "3.8.0"
@@ -0,0 +1,221 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Dict, List, Optional, Set
3
+
4
+ from anipy_api.anime import Anime
5
+ from anipy_api.anilist import (
6
+ AniListAnime,
7
+ AniListMyListStatus,
8
+ AniListMyListStatusEnum,
9
+ AniList,
10
+ AniListAdapter,
11
+ )
12
+ from anipy_api.provider import LanguageTypeEnum, list_providers
13
+ from dataclasses_json import DataClassJsonMixin, config
14
+ from InquirerPy import inquirer
15
+
16
+ from anipy_cli.config import Config
17
+ from anipy_cli.util import error, get_prefered_providers
18
+
19
+
20
+ @dataclass
21
+ class ProviderMapping(DataClassJsonMixin):
22
+ provider: str = field(metadata=config(field_name="pv"))
23
+ name: str = field(metadata=config(field_name="na"))
24
+ identifier: str = field(metadata=config(field_name="id"))
25
+ languages: Set[LanguageTypeEnum] = field(metadata=config(field_name="la"))
26
+
27
+
28
+ @dataclass
29
+ class AniListProviderMapping(DataClassJsonMixin):
30
+ anilist_anime: AniListAnime
31
+ mappings: Dict[str, ProviderMapping]
32
+
33
+
34
+ @dataclass
35
+ class AniListLocalList(DataClassJsonMixin):
36
+ mappings: Dict[int, AniListProviderMapping]
37
+
38
+ def write(self, user_id: int):
39
+ config = Config()
40
+ local_list = config._anilist_local_user_list_path.with_stem(
41
+ f"{config._anilist_local_user_list_path.stem}_{user_id}"
42
+ )
43
+ local_list.write_text(self.to_json())
44
+
45
+ @staticmethod
46
+ def read(user_id: int) -> "AniListLocalList":
47
+ config = Config()
48
+ local_list = config._anilist_local_user_list_path.with_stem(
49
+ f"{config._anilist_local_user_list_path.stem}_{user_id}"
50
+ )
51
+
52
+ if not local_list.is_file():
53
+ local_list.parent.mkdir(exist_ok=True, parents=True)
54
+ local_list.touch()
55
+ mylist = AniListLocalList({})
56
+ mylist.write(user_id)
57
+ return mylist
58
+
59
+ try:
60
+ mylist: AniListLocalList = AniListLocalList.from_json(local_list.read_text())
61
+ except KeyError:
62
+ choice = inquirer.confirm(
63
+ message=f"Your local AniList ({str(local_list)}) is not in the correct format, should it be deleted?",
64
+ default=False,
65
+ ).execute()
66
+ if choice:
67
+ local_list.unlink()
68
+ return AniListLocalList.read(user_id)
69
+ else:
70
+ error("could not read your AniList", fatal=True)
71
+
72
+ return mylist
73
+
74
+
75
+ class AniListProxy:
76
+ def __init__(self, anilist: AniList):
77
+ self.anilist = anilist
78
+ self.user_id = anilist.get_user().id
79
+ self.local_list = AniListLocalList.read(self.user_id)
80
+
81
+ def _cache_list(self, mylist: List[AniListAnime]):
82
+ config = Config()
83
+ for e in mylist:
84
+ if self.local_list.mappings.get(e.id, None):
85
+ if e.my_list_status and config.tracker_ignore_tag in e.my_list_status.tags:
86
+ self.local_list.mappings.pop(e.id)
87
+ else:
88
+ self.local_list.mappings[e.id].anilist_anime = e
89
+ else:
90
+ self.local_list.mappings[e.id] = AniListProviderMapping(e, {})
91
+
92
+ self.local_list.write(self.user_id)
93
+
94
+ def _write_mapping(self, anilist_anime: AniListAnime, mapping: Anime):
95
+ self._cache_list([anilist_anime])
96
+
97
+ self.local_list.mappings[anilist_anime.id].mappings[
98
+ f"{mapping.provider.NAME}:{mapping.identifier}"
99
+ ] = ProviderMapping(
100
+ mapping.provider.NAME, mapping.name, mapping.identifier, mapping.languages
101
+ )
102
+
103
+ self.local_list.write(self.user_id)
104
+
105
+ def get_list(
106
+ self, status_catagories: Optional[Set[AniListMyListStatusEnum]] = None
107
+ ) -> List[AniListAnime]:
108
+ config = Config()
109
+ mylist: List[AniListAnime] = []
110
+
111
+ catagories = (
112
+ status_catagories
113
+ if status_catagories is not None
114
+ else set(
115
+ [AniListMyListStatusEnum[s.upper()] for s in config.tracker_status_categories]
116
+ )
117
+ )
118
+
119
+ for c in catagories:
120
+ mylist.extend(
121
+ filter(
122
+ lambda e: (
123
+ config.tracker_ignore_tag not in e.my_list_status.tags
124
+ if e.my_list_status
125
+ else True
126
+ ),
127
+ self.anilist.get_anime_list(c),
128
+ )
129
+ )
130
+
131
+ self._cache_list(mylist)
132
+ filtered_list = filter(
133
+ lambda x: (
134
+ x.my_list_status.status in catagories if x.my_list_status else False
135
+ ),
136
+ mylist,
137
+ )
138
+ return list(filtered_list)
139
+
140
+ def update_show(
141
+ self,
142
+ anime: AniListAnime,
143
+ status: Optional[AniListMyListStatusEnum] = None,
144
+ episode: Optional[int] = None,
145
+ tags: Set[str] = set(),
146
+ ) -> AniListMyListStatus:
147
+ config = Config()
148
+ tags |= set(config.tracker_tags)
149
+ result = self.anilist.update_anime_list(
150
+ anime.id, status=status, watched_episodes=episode, tags=list(tags)
151
+ )
152
+ anime.my_list_status = result
153
+ self._cache_list([anime])
154
+ return result
155
+
156
+ def delete_show(self, anime: AniListAnime) -> None:
157
+ self.local_list.mappings.pop(anime.id)
158
+ self.local_list.write(self.user_id)
159
+
160
+ self.anilist.remove_from_anime_list(anime.id)
161
+
162
+ def map_from_anilist(
163
+ self, anime: AniListAnime, mapping: Optional[Anime] = None
164
+ ) -> Optional[Anime]:
165
+ if mapping is not None:
166
+ self._write_mapping(anime, mapping)
167
+ return mapping
168
+
169
+ if self.local_list.mappings[anime.id].mappings:
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)
179
+
180
+ config = Config()
181
+ result = None
182
+ for p in get_prefered_providers("anilist"):
183
+ adapter = AniListAdapter(self.anilist, p)
184
+ result = adapter.from_anilist(
185
+ anime,
186
+ config.tracker_mapping_min_similarity,
187
+ config.tracker_mapping_use_filters,
188
+ config.tracker_mapping_use_alternatives,
189
+ )
190
+ if result is not None:
191
+ break
192
+
193
+ if result:
194
+ self._write_mapping(anime, result)
195
+
196
+ return result
197
+
198
+ def map_from_provider(
199
+ self, anime: Anime, mapping: Optional[AniListAnime] = None
200
+ ) -> Optional[AniListAnime]:
201
+ if mapping is not None:
202
+ self._write_mapping(mapping, anime)
203
+ return mapping
204
+
205
+ for _, m in self.local_list.mappings.items():
206
+ existing = m.mappings.get(f"{anime.provider.NAME}:{anime.identifier}", None)
207
+ if existing:
208
+ return m.anilist_anime
209
+
210
+ config = Config()
211
+ adapter = AniListAdapter(self.anilist, anime.provider)
212
+ result = adapter.from_provider(
213
+ anime,
214
+ config.tracker_mapping_min_similarity,
215
+ config.tracker_mapping_use_alternatives,
216
+ )
217
+
218
+ if result:
219
+ self._write_mapping(result, anime)
220
+
221
+ return result
anipy_cli/arg_parser.py CHANGED
@@ -13,12 +13,14 @@ class CliArgs:
13
13
  history: bool
14
14
  seasonal: bool
15
15
  mal: bool
16
+ anilist: bool
16
17
  delete: bool
17
18
  migrate_hist: bool
18
19
  quality: Optional[Union[str, int]]
19
20
  ffmpeg: bool
20
21
  auto_update: bool
21
22
  mal_sync_seasonals: bool
23
+ anilist_sync_seasonals: bool
22
24
  optional_player: Optional[str]
23
25
  search: Optional[str]
24
26
  location: Optional[Path]
@@ -95,6 +97,15 @@ def parse_args(override_args: Optional[list[str]] = None) -> CliArgs:
95
97
  "(requires MAL account credentials to be set in config).",
96
98
  )
97
99
 
100
+ actions_group.add_argument(
101
+ "-A",
102
+ "--anilist",
103
+ required=False,
104
+ dest="anilist",
105
+ action="store_true",
106
+ help="Anilist mode. Similar to seasonal mode, but using Anilist"
107
+ )
108
+
98
109
  actions_group.add_argument(
99
110
  "--delete-history",
100
111
  required=False,
@@ -221,6 +232,14 @@ def parse_args(override_args: Optional[list[str]] = None) -> CliArgs:
221
232
  help="Automatically sync myanimelist to seasonals (only works with `-M`)",
222
233
  )
223
234
 
235
+ options_group.add_argument(
236
+ "--anilist-sync-to-seasonals",
237
+ required=False,
238
+ dest="anilist_sync_seasonals",
239
+ action="store_true",
240
+ help="Automatically sync anilist to seasonals (only works with `-A`)",
241
+ )
242
+
224
243
  info_group.add_argument(
225
244
  "-h", "--help", action="help", help="show this help message and exit"
226
245
  )
anipy_cli/cli.py CHANGED
@@ -81,6 +81,7 @@ def _safe_cli(args: CliArgs):
81
81
  args.seasonal: SeasonalCli,
82
82
  args.history: HistoryCli,
83
83
  args.mal: MalCli,
84
+ args.anilist: AniListCli,
84
85
  }
85
86
 
86
87
  cli_class = clis_dict.get(True, DefaultCli)
@@ -4,11 +4,13 @@ from anipy_cli.clis.mal_cli import MalCli
4
4
  from anipy_cli.clis.seasonal_cli import SeasonalCli
5
5
  from anipy_cli.clis.binge_cli import BingeCli
6
6
  from anipy_cli.clis.download_cli import DownloadCli
7
+ from anipy_cli.clis.anilist_cli import AniListCli
7
8
 
8
9
  __all__ = [
9
10
  "DefaultCli",
10
11
  "HistoryCli",
11
12
  "MalCli",
13
+ "AniListCli",
12
14
  "SeasonalCli",
13
15
  "BingeCli",
14
16
  "DownloadCli",
@@ -0,0 +1,62 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from anipy_api.error import AniListError
4
+ from anipy_api.anilist import AniList
5
+ from InquirerPy import inquirer
6
+
7
+ from anipy_cli.clis.base_cli import CliBase
8
+ from anipy_cli.config import Config
9
+ from anipy_cli.menus import AniListMenu
10
+ from anipy_cli.util import DotSpinner, error
11
+ import webbrowser
12
+
13
+ if TYPE_CHECKING:
14
+ from anipy_cli.arg_parser import CliArgs
15
+
16
+
17
+ class AniListCli(CliBase):
18
+ def __init__(self, options: "CliArgs"):
19
+ super().__init__(options)
20
+ self.access_token = ""
21
+ self.anilist = None
22
+
23
+ def print_header(self):
24
+ pass
25
+
26
+ def take_input(self):
27
+ config = Config()
28
+ self.access_token = config.anilist_token
29
+
30
+ if not self.access_token:
31
+ webbrowser.open(AniList.AUTH_URL)
32
+ self.access_token = inquirer.text( # type: ignore
33
+ "Paste the token from the browser for Auth",
34
+ validate=lambda x: len(x) > 1,
35
+ invalid_message="You must enter a access_token!",
36
+ long_instruction="Hint: You can save your access token in the config!",
37
+ ).execute()
38
+
39
+ def process(self):
40
+ try:
41
+ with DotSpinner("Logging into AniList..."):
42
+ self.anilist = AniList.from_implicit_grant(self.access_token)
43
+ except AniListError as e:
44
+ error(
45
+ f"{str(e)}\nCannot login to AniList, it is likely your response token is wrong",
46
+ fatal=True,
47
+ )
48
+
49
+ def show(self):
50
+ pass
51
+
52
+ def post(self):
53
+ assert self.anilist is not None
54
+
55
+ menu = AniListMenu(anilist=self.anilist, options=self.options)
56
+
57
+ if self.options.auto_update:
58
+ menu.download()
59
+ elif self.options.anilist_sync_seasonals:
60
+ menu.sync_anilist_seasonls()
61
+ else:
62
+ menu.run()
anipy_cli/config.py CHANGED
@@ -12,8 +12,6 @@ from anipy_cli import __appname__, __version__
12
12
 
13
13
 
14
14
  class Config:
15
- _EXPAND_PATHS = True
16
-
17
15
  def __init__(self):
18
16
  self._config_file, self._yaml_conf = Config._read_config()
19
17
 
@@ -44,6 +42,10 @@ class Config:
44
42
  def _mal_local_user_list_path(self) -> Path:
45
43
  return self.user_files_path / "mal_list.json"
46
44
 
45
+ @property
46
+ def _anilist_local_user_list_path(self) -> Path:
47
+ return self.user_files_path / "anilist_list.json"
48
+
47
49
  @property
48
50
  def download_folder_path(self) -> Path:
49
51
  """Path to your download folder/directory.
@@ -68,13 +70,13 @@ class Config:
68
70
  def providers(self) -> Dict[str, List[str]]:
69
71
  """A list of pairs defining which providers will search for anime
70
72
  in different parts of the program. Configurable areas are as follows:
71
- default (and history), download (-D), seasonal (-S), binge (-B) and mal
72
- (-M) The example will show you how it is done! Please note that for seasonal
73
+ default (and history), download (-D), seasonal (-S), binge (-B), anilist (-A)
74
+ and mal (-M) The example will show you how it is done! Please note that for seasonal
73
75
  search always the first provider that supports it is used.
74
76
 
75
77
  For an updated list of providers look here: https://sdaqo.github.io/anipy-cli/availabilty
76
78
 
77
- Supported providers (as of $version): allanime, animekai (animekai is not functional for now)
79
+ Supported providers (as of $version): allanime, animekai (animekai is not functional for now), native (filesystem provider, set root in provider_urls config)
78
80
 
79
81
  Examples:
80
82
  providers:
@@ -83,6 +85,7 @@ class Config:
83
85
  seasonal: ["provider3"]
84
86
  binge: ["provider4"]
85
87
  mal: ["provider2", "provider3"]
88
+ anilist: ["provider1"]
86
89
  """
87
90
  defaults = {
88
91
  "default": ["allanime"],
@@ -90,6 +93,7 @@ class Config:
90
93
  "seasonal": ["allanime"],
91
94
  "binge": ["allanime"],
92
95
  "mal": ["allanime"],
96
+ "anilist": ["allanime"],
93
97
  }
94
98
 
95
99
  value = self._get_value("providers", defaults, dict)
@@ -102,9 +106,12 @@ class Config:
102
106
  def provider_urls(self) -> Dict[str, str]:
103
107
  """A list of pairs to override the default urls that providers use.
104
108
 
109
+ Note: the native provider accepts a path instead of a url, it defaults to ~/Videos
110
+
105
111
  Examples:
106
112
  provider_urls:
107
113
  gogoanime: "https://gogoanime3.co"
114
+ native: "~/Videos"
108
115
  provider_urls: {} # do not override any urls
109
116
  """
110
117
 
@@ -229,9 +236,9 @@ class Config:
229
236
  """With this option you can define scripts that run after a file
230
237
  has been downloaded. As with the 'providers' option, you can configure
231
238
  different behaviour, depending on which part of anipy-cli the download occurs.
232
- Configurable areas are as follows: default (and history), download (-D), seasonal (-S)
233
- and mal (-M). The example will show you how it is done! Please note that if you define
234
- several scripts for one area, they will run in the order you put them in the list.
239
+ Configurable areas are as follows: default (and history), download (-D), seasonal (-S),
240
+ anilist (-A) and mal (-M). The example will show you how it is done! Please note that
241
+ if you define several scripts for one area, they will run in the order you put them in the list.
235
242
  You can also define a timeout (in seconds), after which a script will be terminated,
236
243
  if set to null there will be no timeout and any script will run forever.
237
244
 
@@ -256,6 +263,7 @@ class Config:
256
263
  "download": [],
257
264
  "seasonal": [],
258
265
  "mal": [],
266
+ "anilist": [],
259
267
  "timeout": None,
260
268
  }
261
269
 
@@ -281,6 +289,11 @@ class Config:
281
289
  """Your MyAnimeList username for MAL mode."""
282
290
  return self._get_value("mal_user", "", str)
283
291
 
292
+ @property
293
+ def anilist_token(self) -> str:
294
+ """Your AniList access token for AniList mode."""
295
+ return self._get_value("anilist_token", "", str)
296
+
284
297
  @property
285
298
  def mal_password(self) -> str:
286
299
  """Your MyAnimeList password for MAL mode.
@@ -291,55 +304,55 @@ class Config:
291
304
  return self._get_value("mal_password", "", str)
292
305
 
293
306
  @property
294
- def mal_ignore_tag(self) -> str:
307
+ def tracker_ignore_tag(self) -> str:
295
308
  """All anime in your MyAnimeList with this tag will be ignored by
296
309
  anipy-cli.
297
310
 
298
311
  Examples:
299
- mal_ignore_tag: ignore # all anime with ignore tag will be ignored
300
- mal_ignore_tag: "" # no anime will be ignored
312
+ tracker_ignore_tag: ignore # all anime with ignore tag will be ignored
313
+ tracker_ignore_tag: "" # no anime will be ignored
301
314
  """
302
- return self._get_value("mal_ignore_tag", "ignore", str)
315
+ return self._get_value("tracker_ignore_tag", "ignore", str)
303
316
 
304
317
  @property
305
- def mal_dub_tag(self) -> str:
306
- """All anime in your MyAnimeList with this tag will be switched over to
307
- dub in MAL mode, if the dub is available. If you do not specify a tag,
308
- anipy-cli will use `preferred_type` to choose dub or sub in MAL mode.
318
+ def tracker_dub_tag(self) -> str:
319
+ """All anime in your Anime Tracker with this tag will be switched over to
320
+ dub in tracker mode, if the dub is available. If you do not specify a tag,
321
+ anipy-cli will use `preferred_type` to choose dub or sub in tracker mode.
309
322
 
310
323
  Examples:
311
- mal_dub_tag: dub # all anime with this tag will be switched to dub
312
- mal_dub_tag: "" # no anime will be switched to dub, except you have preferred_type on dub
324
+ tracker_dub_tag: dub # all anime with this tag will be switched to dub
325
+ tracker_dub_tag: "" # no anime will be switched to dub, except you have preferred_type on dub
313
326
  """
314
- return self._get_value("mal_dub_tag", "dub", str)
327
+ return self._get_value("tracker_dub_tag", "dub", str)
315
328
 
316
329
  @property
317
- def mal_tags(self) -> List[str]:
318
- """Custom tags to tag all anime in your MyAnimeList that are
330
+ def tracker_tags(self) -> List[str]:
331
+ """Custom tags to tag all anime in your Anime Tracker that are
319
332
  altered/added by anipy-cli.
320
333
 
321
334
  Examples:
322
- mal_tags: ["anipy-cli"] # tag all anime with anipy-cli
323
- mal_tags: ["anipy-cli", "important"] # tag all anime with anipy-cli and important
324
- mal_tags: null or mal_tags: [] # Do not tag the anime
335
+ tracker_tags: ["anipy-cli"] # tag all anime with anipy-cli
336
+ tracker_tags: ["anipy-cli", "important"] # tag all anime with anipy-cli and important
337
+ tracker_tags: null or tracker_tags: [] # Do not tag the anime
325
338
  """
326
- return self._get_value("mal_tags", [], list)
339
+ return self._get_value("tracker_tags", [], list)
327
340
 
328
341
  @property
329
- def mal_status_categories(self) -> List[str]:
330
- """Status categories of your MyAnimeList that anipy-cli uses for
342
+ def tracker_status_categories(self) -> List[str]:
343
+ """Status categories of your Anime Tracker that anipy-cli uses for
331
344
  downloading/watching new episodes listing anime in your list and stuff
332
345
  like that. Normally the watching catagory should be enough as you would
333
346
  normally put anime you currently watch in the watching catagory.
334
347
 
335
348
  Valid values are: watching, completed, on_hold, dropped, plan_to_watch
336
349
  """
337
- return self._get_value("mal_status_categories", ["watching"], list)
350
+ return self._get_value("tracker_status_categories", ["watching"], list)
338
351
 
339
352
  @property
340
- def mal_mapping_min_similarity(self) -> float:
353
+ def tracker_mapping_min_similarity(self) -> float:
341
354
  """
342
- The minumum similarity between titles when mapping anime in MAL mode.
355
+ The minumum similarity between titles when mapping anime in tracker mode.
343
356
  This is a decimal number from 0 - 1, 1 meaning 100% match and 0 meaning all characters are different.
344
357
  If the similarity of a map is below the threshold you will be prompted for a manual map.
345
358
 
@@ -349,24 +362,24 @@ class Config:
349
362
 
350
363
  If you are interested, the algorithm being used here is this: https://en.wikipedia.org/wiki/Levenshtein_distance
351
364
  """
352
- return self._get_value("mal_mapping_min_similarity", 0.8, float)
365
+ return self._get_value("tracker_mapping_min_similarity", 0.8, float)
353
366
 
354
367
  @property
355
- def mal_mapping_use_alternatives(self) -> bool:
368
+ def tracker_mapping_use_alternatives(self) -> bool:
356
369
  """Check alternative names when mapping anime.
357
370
 
358
371
  If turned on this will slow down mapping but provide better
359
372
  chances of finding a match.
360
373
  """
361
- return self._get_value("mal_mapping_use_alternatives", True, bool)
374
+ return self._get_value("tracker_mapping_use_alternatives", True, bool)
362
375
 
363
376
  @property
364
- def mal_mapping_use_filters(self) -> bool:
377
+ def tracker_mapping_use_filters(self) -> bool:
365
378
  """Use filters (e.g. year, season etc.) of providers to narrow down the
366
379
  results, this will lead to more accurate mapping, but provide wrong
367
380
  results if the filters of the provider do not work properly or if anime
368
381
  are not correctly marked with the correct data."""
369
- return self._get_value("mal_mapping_use_filters", True, bool)
382
+ return self._get_value("tracker_mapping_use_filters", True, bool)
370
383
 
371
384
  @property
372
385
  def auto_sync_mal_to_seasonals(self) -> bool:
@@ -412,10 +425,7 @@ class Config:
412
425
  # os.path.expanduser is equivalent to Path().expanduser()
413
426
  # But because pathlib doesn't have expandvars(), we resort
414
427
  # to using the os module inside the Path constructor
415
- if self._EXPAND_PATHS:
416
- return Path(os.path.expandvars(path)).expanduser()
417
-
418
- return Path(path)
428
+ return Path(os.path.expandvars(path)).expanduser()
419
429
  except RuntimeError:
420
430
  return fallback
421
431
 
@@ -429,8 +439,6 @@ class Config:
429
439
  def _create_config(self):
430
440
  self._get_config_path().mkdir(exist_ok=True, parents=True)
431
441
  self._config_file.touch()
432
-
433
- self._EXPAND_PATHS = False
434
442
 
435
443
  dump = ""
436
444
  # generate config based on attrs and default values of config class
@@ -455,8 +463,7 @@ class Config:
455
463
  + yaml.dump({attribute: val}, indent=4, default_flow_style=False)
456
464
  + "\n"
457
465
  )
458
-
459
- self._EXPAND_PATHS = True
466
+
460
467
  self._config_file.write_text(dump)
461
468
 
462
469
  @staticmethod
anipy_cli/mal_proxy.py CHANGED
@@ -82,7 +82,7 @@ class MyAnimeListProxy:
82
82
  config = Config()
83
83
  for e in mylist:
84
84
  if self.local_list.mappings.get(e.id, None):
85
- if e.my_list_status and config.mal_ignore_tag in e.my_list_status.tags:
85
+ if e.my_list_status and config.tracker_ignore_tag in e.my_list_status.tags:
86
86
  self.local_list.mappings.pop(e.id)
87
87
  else:
88
88
  self.local_list.mappings[e.id].mal_anime = e
@@ -112,7 +112,7 @@ class MyAnimeListProxy:
112
112
  status_catagories
113
113
  if status_catagories is not None
114
114
  else set(
115
- [MALMyListStatusEnum[s.upper()] for s in config.mal_status_categories]
115
+ [MALMyListStatusEnum[s.upper()] for s in config.tracker_status_categories]
116
116
  )
117
117
  )
118
118
 
@@ -120,7 +120,7 @@ class MyAnimeListProxy:
120
120
  mylist.extend(
121
121
  filter(
122
122
  lambda e: (
123
- config.mal_ignore_tag not in e.my_list_status.tags
123
+ config.tracker_ignore_tag not in e.my_list_status.tags
124
124
  if e.my_list_status
125
125
  else True
126
126
  ),
@@ -145,7 +145,7 @@ class MyAnimeListProxy:
145
145
  tags: Set[str] = set(),
146
146
  ) -> MALMyListStatus:
147
147
  config = Config()
148
- tags |= set(config.mal_tags)
148
+ tags |= set(config.tracker_tags)
149
149
  result = self.mal.update_anime_list(
150
150
  anime.id, status=status, watched_episodes=episode, tags=list(tags)
151
151
  )
@@ -183,9 +183,9 @@ class MyAnimeListProxy:
183
183
  adapter = MyAnimeListAdapter(self.mal, p)
184
184
  result = adapter.from_myanimelist(
185
185
  anime,
186
- config.mal_mapping_min_similarity,
187
- config.mal_mapping_use_filters,
188
- config.mal_mapping_use_alternatives,
186
+ config.tracker_mapping_min_similarity,
187
+ config.tracker_mapping_use_filters,
188
+ config.tracker_mapping_use_alternatives,
189
189
  )
190
190
 
191
191
  if result is not None:
@@ -212,8 +212,8 @@ class MyAnimeListProxy:
212
212
  adapter = MyAnimeListAdapter(self.mal, anime.provider)
213
213
  result = adapter.from_provider(
214
214
  anime,
215
- config.mal_mapping_min_similarity,
216
- config.mal_mapping_use_alternatives,
215
+ config.tracker_mapping_min_similarity,
216
+ config.tracker_mapping_use_alternatives,
217
217
  )
218
218
 
219
219
  if result:
@@ -1,5 +1,6 @@
1
1
  from anipy_cli.menus.menu import Menu
2
2
  from anipy_cli.menus.mal_menu import MALMenu
3
+ from anipy_cli.menus.anilist_menu import AniListMenu
3
4
  from anipy_cli.menus.seasonal_menu import SeasonalMenu
4
5
 
5
- __all__ = ["Menu", "MALMenu", "SeasonalMenu"]
6
+ __all__ = ["Menu", "MALMenu", "AniListMenu", "SeasonalMenu"]