Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""LICENSE
2Copyright 2015 Hermann Krumrey <hermann@krumreyh.com>
4This file is part of toktokkie.
6toktokkie is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
11toktokkie is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
16You should have received a copy of the GNU General Public License
17along with toktokkie. If not, see <http://www.gnu.org/licenses/>.
18LICENSE"""
20from abc import ABC
21from imdb import IMDb
22from typing import List, Tuple, Optional, Dict
23from puffotter.prompt import yn_prompt
24from puffotter.os import replace_illegal_ntfs_chars
25from anime_list_apis.api.AnilistApi import AnilistApi
26from anime_list_apis.models.attributes.Title import TitleType
27from anime_list_apis.models.attributes.MediaType import MediaType as \
28 AnilistMediaType
29from toktokkie.enums import IdType, MediaType
30from toktokkie.metadata.base.MetadataBase import MetadataBase
31from toktokkie.metadata.base.components.RenameOperation import RenameOperation
34class Renamer(MetadataBase, ABC):
35 """
36 Class that's responsible to define renaming functionality
37 """
39 def rename(self, noconfirm: bool = False, skip_title: bool = False):
40 """
41 Renames the contained files according to the naming schema.
42 :param noconfirm: Skips the confirmation phase if True
43 :param skip_title: If True, will skip title renaming
44 :return: None
45 """
46 if skip_title:
47 should_title = self.name
48 else:
49 should_title = self.resolve_title_name()
51 operations = self.create_rename_operations()
53 if should_title != self.name:
54 if noconfirm or \
55 yn_prompt(f"Rename title of series to {should_title}?"):
56 self.name = should_title
57 # Reload with new title name
58 operations = self.create_rename_operations()
60 active_operations = list(filter(
61 lambda x: x.source != x.dest,
62 operations
63 ))
64 if len(active_operations) == 0:
65 self.logger.info("Files already named correctly, skipping.")
66 return
68 if not noconfirm:
69 for operation in operations:
70 print(operation)
72 prompt = yn_prompt("Proceed with renaming?")
74 if not prompt:
75 self.logger.warning("Renaming aborted.")
76 return
78 for operation in operations:
79 operation.rename()
81 def resolve_title_name(self) -> str:
82 """
83 If possible, will fetch the appropriate name for the
84 metadata based on IDs, falling back to the
85 directory name if this is not possible or supported.
86 """
87 return self.name # pragma: no cover
89 # noinspection PyMethodMayBeStatic
90 def create_rename_operations(self) -> List[RenameOperation]:
91 """
92 Performs rename operations on the content referenced by
93 this metadata object
94 :return: The rename operations for this metadata
95 """
96 return [] # pragma: no cover
98 @staticmethod
99 def load_anilist_title_and_year(
100 anilist_ids: List[str],
101 _media_type: MediaType,
102 ) -> Optional[Tuple[str, int]]:
103 """
104 Loads the title and year of an item using anilist IDs
105 :param anilist_ids: The anilist IDs to use
106 :param _media_type: The media type to use
107 :return: The title of the item and the year as a tuple
108 """
109 if len(anilist_ids) == 0:
110 return None
112 anilist_id = int(anilist_ids[0])
114 if anilist_id == 0:
115 return None
117 if _media_type in MetadataBase.literature_media_types():
118 media_type = AnilistMediaType.MANGA
119 else:
120 media_type = AnilistMediaType.ANIME
122 entry = AnilistApi().get_data(media_type, anilist_id)
123 new_name = entry.title.get(TitleType.ENGLISH)
124 year = entry.releasing_start.year
126 return replace_illegal_ntfs_chars(new_name), year
128 @staticmethod
129 def load_imdb_title_and_year(imdb_ids: List[str]) \
130 -> Optional[Tuple[str, int]]:
131 """
132 Loads the title and year of an item using IMDB IDs
133 :parameter imdb_ids: The IMDB IDs
134 :return: The title of the item and the year as a tuple
135 """
136 if len(imdb_ids) == 0:
137 return None
139 imdb_id = imdb_ids[0].replace("t", "")
141 if imdb_id == "0":
142 return None
144 info = IMDb().get_movie(imdb_id).data
146 new_name = info["title"]
147 year = info["year"]
149 return replace_illegal_ntfs_chars(new_name), year
151 def load_title_and_year(
152 self,
153 id_type_priority: List[IdType],
154 id_override: Optional[Dict[IdType, List[str]]] = None
155 ) -> Tuple[str, Optional[int]]:
156 """
157 Loads the title and year based on a custom order of id types
158 """
159 ids = self.ids
160 if id_override is not None:
161 ids.update(id_override)
163 for id_type in id_type_priority:
165 if id_type == IdType.IMDB:
166 result = self.load_imdb_title_and_year(ids[id_type])
167 elif id_type == IdType.ANILIST:
168 result = self.load_anilist_title_and_year(
169 ids[id_type], self.media_type()
170 )
171 else:
172 result = None
174 if result is not None:
175 return result[0], result[1]
177 return self.name, None