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 2020 Hermann Krumrey <hermann@krumreyh.com> 

3 

4This file is part of otaku-info-web. 

5 

6otaku-info-web 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 

11otaku-info-web 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 otaku-info-web. If not, see <http://www.gnu.org/licenses/>. 

18LICENSE""" 

19 

20from typing import Optional, List 

21from puffotter.graphql import GraphQlClient 

22from otaku_info_web.utils.enums import MediaType 

23from otaku_info_web.utils.anilist.AnilistItem \ 

24 import AnilistItem, AnilistUserItem 

25 

26 

27MEDIA_QUERY = """ 

28 id 

29 chapters 

30 episodes 

31 status 

32 format 

33 title { 

34 english 

35 romaji 

36 } 

37 coverImage { 

38 large 

39 } 

40 nextAiringEpisode { 

41 episode 

42 } 

43 relations { 

44 edges { 

45 node { 

46 id 

47 type 

48 } 

49 relationType 

50 } 

51 } 

52""" 

53 

54 

55def guess_latest_manga_chapter(anilist_id: int) -> Optional[int]: 

56 """ 

57 Guesses the latest chapter number based on anilist user activity 

58 :param anilist_id: The anilist ID to check 

59 :return: The latest chapter number 

60 """ 

61 graphql = GraphQlClient("https://graphql.anilist.co") 

62 query = """ 

63 query ($id: Int) { 

64 Page(page: 1) { 

65 activities(mediaId: $id, sort: ID_DESC) { 

66 ... on ListActivity { 

67 progress 

68 userId 

69 status 

70 media { 

71 chapters 

72 } 

73 } 

74 } 

75 } 

76 } 

77 """ 

78 resp = graphql.query(query, {"id": anilist_id}) 

79 if resp is None: 79 ↛ 80line 79 didn't jump to line 80, because the condition on line 79 was never true

80 return None 

81 

82 data = resp["data"]["Page"]["activities"] 

83 

84 progresses = [] 

85 for entry in data: 

86 progress = entry["progress"] 

87 status = entry["status"] 

88 chapters = entry["media"]["chapters"] 

89 

90 if status == "completed": 90 ↛ 91line 90 didn't jump to line 91, because the condition on line 90 was never true

91 progresses.append(chapters) 

92 elif progress is not None: 

93 progress = entry["progress"].split(" - ")[-1] 

94 progresses.append(int(progress)) 

95 

96 progresses = progresses[0:20] 

97 progresses.sort(key=lambda x: progresses.count(x), reverse=True) 

98 progresses = sorted(progresses, key=progresses.count, reverse=True) 

99 

100 try: 

101 return progresses[0] 

102 except IndexError: 

103 return None 

104 

105 

106def load_anilist( 

107 username: str, 

108 media_type: MediaType 

109) -> List[AnilistUserItem]: 

110 """ 

111 Loads the anilist for a user 

112 :param username: The username 

113 :param media_type: The media type, either MANGA or ANIME 

114 :return: The anilist list items for the user and media type 

115 """ 

116 graphql = GraphQlClient("https://graphql.anilist.co") 

117 query = """ 

118 query ($username: String, $media_type: MediaType) { 

119 MediaListCollection(userName: $username, type: $media_type) { 

120 lists { 

121 name 

122 entries { 

123 progress 

124 score 

125 status 

126 media {@{MEDIA_QUERY}} 

127 } 

128 } 

129 } 

130 } 

131 """.replace("@{MEDIA_QUERY}", MEDIA_QUERY) 

132 resp = graphql.query(query, { 

133 "username": username, 

134 "media_type": media_type.value.upper() 

135 }) 

136 if resp is None: 136 ↛ 137line 136 didn't jump to line 137, because the condition on line 136 was never true

137 return [] 

138 user_lists = resp["data"]["MediaListCollection"]["lists"] 

139 

140 anilist_items: List[AnilistUserItem] = [] 

141 for entries, list_name in [ 

142 (y["entries"], y["name"]) for y in user_lists 

143 ]: 

144 for entry in entries: 

145 entry["list_name"] = list_name 

146 anilist_items.append(AnilistUserItem.from_query(media_type, entry)) 

147 

148 return anilist_items 

149 

150 

151def load_media_info(anilist_id: int, media_type: MediaType) \ 

152 -> Optional[AnilistItem]: 

153 """ 

154 Loads information for a single anilist media item 

155 :param anilist_id: The anilist media ID 

156 :param media_type: The media type 

157 :return: The fetched AnilistItem 

158 """ 

159 graphql = GraphQlClient("https://graphql.anilist.co") 

160 query = """ 

161 query ($id: Int, $media_type: MediaType) { 

162 Media(id: $id, type: $media_type) { 

163 @{MEDIA_QUERY} 

164 } 

165 } 

166 """.replace("@{MEDIA_QUERY}", MEDIA_QUERY) 

167 resp = graphql.query( 

168 query, 

169 {"id": anilist_id, "media_type": media_type.value.upper()} 

170 ) 

171 if resp is None: 171 ↛ 172line 171 didn't jump to line 172, because the condition on line 171 was never true

172 return None 

173 else: 

174 return AnilistItem.from_query(media_type, resp["data"]["Media"])