Hide keyboard shortcuts

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> 

3 

4This file is part of toktokkie. 

5 

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. 

10 

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. 

15 

16You should have received a copy of the GNU General Public License 

17along with toktokkie. If not, see <http://www.gnu.org/licenses/>. 

18LICENSE""" 

19 

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 

32 

33 

34class Renamer(MetadataBase, ABC): 

35 """ 

36 Class that's responsible to define renaming functionality 

37 """ 

38 

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() 

50 

51 operations = self.create_rename_operations() 

52 

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() 

59 

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 

67 

68 if not noconfirm: 

69 for operation in operations: 

70 print(operation) 

71 

72 prompt = yn_prompt("Proceed with renaming?") 

73 

74 if not prompt: 

75 self.logger.warning("Renaming aborted.") 

76 return 

77 

78 for operation in operations: 

79 operation.rename() 

80 

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 

88 

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 

97 

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 

111 

112 anilist_id = int(anilist_ids[0]) 

113 

114 if anilist_id == 0: 

115 return None 

116 

117 if _media_type in MetadataBase.literature_media_types(): 

118 media_type = AnilistMediaType.MANGA 

119 else: 

120 media_type = AnilistMediaType.ANIME 

121 

122 entry = AnilistApi().get_data(media_type, anilist_id) 

123 new_name = entry.title.get(TitleType.ENGLISH) 

124 year = entry.releasing_start.year 

125 

126 return replace_illegal_ntfs_chars(new_name), year 

127 

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 

138 

139 imdb_id = imdb_ids[0].replace("t", "") 

140 

141 if imdb_id == "0": 

142 return None 

143 

144 info = IMDb().get_movie(imdb_id).data 

145 

146 new_name = info["title"] 

147 year = info["year"] 

148 

149 return replace_illegal_ntfs_chars(new_name), year 

150 

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) 

162 

163 for id_type in id_type_priority: 

164 

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 

173 

174 if result is not None: 

175 return result[0], result[1] 

176 

177 return self.name, None