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 typing import List, Dict, Optional 

22from toktokkie.enums import IdType 

23from toktokkie.exceptions import InvalidMetadata 

24from toktokkie.metadata.base.MetadataBase import MetadataBase 

25from toktokkie.metadata.tv.components.TvSeason import TvSeason 

26from toktokkie.metadata.tv.components.TvEpisode import TvEpisode 

27from toktokkie.metadata.tv.components.TvEpisodeRange import TvEpisodeRange 

28 

29 

30class TvExtras(MetadataBase, ABC): 

31 """ 

32 Extra properties and methods specific to tv series 

33 """ 

34 

35 @property 

36 def seasons(self) -> List[TvSeason]: 

37 """ 

38 :return: A list of TV seasons 

39 """ 

40 seasons_list = list(map( 

41 lambda x: TvSeason.from_json(self.directory_path, self.ids, x), 

42 self.json["seasons"] 

43 )) 

44 seasons_list.sort( 

45 key=lambda season: season.name.replace("Season ", "") 

46 ) 

47 return seasons_list 

48 

49 @seasons.setter 

50 def seasons(self, seasons: List[TvSeason]): 

51 """ 

52 Setter method for the seasons 

53 :param seasons: The seasons to set 

54 :return: None 

55 """ 

56 self.json["seasons"] = [] 

57 for season in seasons: 

58 print(season) 

59 self.json["seasons"].append(season.json) 

60 

61 def get_season(self, season_name: str) -> TvSeason: 

62 """ 

63 Retrieves a single season for a provided season name 

64 :param season_name: The name of the season 

65 :return: The season 

66 :raises KeyError: If the season could not be found 

67 """ 

68 for season in self.seasons: 

69 if season.name == season_name: 

70 return season 

71 raise KeyError(season_name) 

72 

73 @property 

74 def excludes(self) -> Dict[IdType, Dict[int, List[int]]]: 

75 """ 

76 Generates data for episodes to be excluded during renaming etc. 

77 :return A dictionary mapping episode anithemes to seasons and id types 

78 Form: {idtype: {season: [ep1, ep2]}} 

79 """ 

80 generated = {} # type: Dict[IdType, Dict[int, List[int]]] 

81 

82 for _id_type in self.json.get("excludes", {}): 

83 

84 id_type = IdType(_id_type) 

85 generated[id_type] = {} 

86 

87 for exclude in self.json["excludes"][_id_type]: 

88 

89 try: 

90 episode_range = TvEpisodeRange.from_json(exclude) 

91 episodes = episode_range.episodes 

92 except InvalidMetadata: 

93 episodes = [TvEpisode.from_json(exclude)] 

94 

95 for episode in episodes: 

96 if episode.season not in generated[id_type]: 

97 generated[id_type][episode.season] = [] 

98 generated[id_type][episode.season].append(episode.episode) 

99 

100 return generated 

101 

102 @property 

103 def season_start_overrides(self) -> Dict[IdType, Dict[int, int]]: 

104 """ 

105 :return: A dictionary mapping episodes that override a season starting 

106 point to ID types 

107 Form: {idtype: {season: episode}} 

108 """ 

109 return self.json.get("season_start_overrides", {}) 

110 

111 @property 

112 def multi_episodes(self) -> Dict[IdType, Dict[int, Dict[int, int]]]: 

113 """ 

114 :return: A dictionary mapping lists of multi-episodes to id types 

115 Form: {idtype: {season: {start: end}}} 

116 """ 

117 generated = {} # type: Dict[IdType, Dict[int, Dict[int, int]]] 

118 

119 for _id_type in self.json.get("multi_episodes", {}): 

120 

121 id_type = IdType(_id_type) 

122 generated[id_type] = {} 

123 

124 for multi_episode in self.json["multi_episodes"][_id_type]: 

125 episode_range = TvEpisodeRange.from_json(multi_episode) 

126 

127 season_number = episode_range.season 

128 start = episode_range.start_episode 

129 end = episode_range.end_episode 

130 

131 if episode_range.season not in generated[id_type]: 

132 generated[id_type][season_number] = {} 

133 

134 generated[id_type][season_number][start] = end 

135 

136 return generated 

137 

138 def add_multi_episode( 

139 self, 

140 id_type: IdType, 

141 season: int, 

142 start_episode: int, 

143 end_episode: int 

144 ): 

145 """ 

146 Adds a multi-episode 

147 :param id_type: The ID type 

148 :param season: The season of the multi episode 

149 :param start_episode: The start episode 

150 :param end_episode: The end episode 

151 :return: None 

152 """ 

153 if "multi_episodes" not in self.json: 

154 self.json["multi_episodes"] = {} 

155 if id_type.value not in self.json["multi_episodes"]: 

156 self.json["multi_episodes"][id_type.value] = [] 

157 

158 self.json["multi_episodes"][id_type.value].append({ 

159 "season": season, 

160 "start_episode": start_episode, 

161 "end_episode": end_episode 

162 }) 

163 

164 def add_exclude( 

165 self, 

166 id_type: IdType, 

167 season: int, 

168 episode: int, 

169 end_episode: Optional[int] = None 

170 ): 

171 """ 

172 Adds an excluded episode 

173 :param id_type: The ID type 

174 :param season: The season of the excluded episode 

175 :param episode: The excluded episode number 

176 :param end_episode: Optional end episode for multi-episode excludes 

177 :return: None 

178 """ 

179 if "excludes" not in self.json: 

180 self.json["excludes"] = {} 

181 if id_type.value not in self.json["excludes"]: 

182 self.json["excludes"][id_type.value] = [] 

183 

184 exclude = {"season": season} 

185 if end_episode is None: 

186 exclude.update({"episode": episode}) 

187 else: 

188 exclude.update({ 

189 "start_episode": episode, "end_episode": end_episode 

190 }) 

191 

192 self.json["excludes"][id_type.value].append(exclude) 

193 

194 def add_season_start_override( 

195 self, id_type: IdType, season: int, episode: int 

196 ): 

197 """ 

198 Adds a new season start override 

199 :param id_type: The ID type 

200 :param season: The season 

201 :param episode: The episode 

202 :return: None 

203 """ 

204 if "season_start_overrides" not in self.json: 

205 self.json["season_start_overrides"] = {} 

206 if id_type not in self.json["season_start_overrides"]: 

207 self.json["season_start_overrides"][id_type] = {} 

208 

209 self.json["season_start_overrides"][id_type][season] = episode