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 stockstert. 

5 

6stockstert 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 

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

18LICENSE""" 

19 

20 

21import json 

22import requests 

23from typing import List, Dict, Any, Optional 

24 

25 

26def load_anilist( 

27 username: str, 

28 media_type: str, 

29 list_name: Optional[str] = None 

30) -> List[Dict[str, Any]]: 

31 """ 

32 Loads the anilist for a user 

33 :param username: The username 

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

35 :param list_name: Optionalyy restrict to a specific list 

36 :return: The anilist 

37 """ 

38 print(list_name) 

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

40 query = """ 

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

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

43 lists { 

44 name 

45 entries { 

46 progress 

47 media { 

48 coverImage { 

49 medium 

50 } 

51 id 

52 chapters 

53 episodes 

54 status 

55 title { 

56 english 

57 romaji 

58 } 

59 nextAiringEpisode { 

60 episode 

61 } 

62 } 

63 } 

64 } 

65 } 

66 } 

67 """ 

68 resp = graphql.query(query, { 

69 "username": username, 

70 "media_type": media_type.upper() 

71 }) 

72 if resp is None: 

73 return [] 

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

75 

76 entries = [] # type: List[Dict[str, Any]] 

77 for _list in user_lists: 

78 if list_name is None or _list["name"] == list_name: 

79 entries += _list["entries"] 

80 

81 return entries 

82 

83 

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

85 """ 

86 Guesses the latest chapter number based on anilist user activity 

87 :param anilist_id: The anilist ID to check 

88 :return: The latest chapter number 

89 """ 

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

91 query = """ 

92 query ($id: Int) { 

93 Page(page: 1) { 

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

95 ... on ListActivity { 

96 progress 

97 userId 

98 } 

99 } 

100 } 

101 } 

102 """ 

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

104 if resp is None: 

105 return None 

106 

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

108 

109 progresses = [] 

110 for entry in data: 

111 progress = entry["progress"] 

112 if progress is not None: 

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

114 progresses.append(int(progress)) 

115 

116 progresses = progresses[0:20] 

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

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

119 best_guess = progresses[0] 

120 

121 return best_guess 

122 

123 

124class GraphQlClient: 

125 """ 

126 A simple API wrapper for GraphQL APIs 

127 """ 

128 

129 def __init__(self, api_url: str): 

130 """ 

131 Initializes the GraphQL API wrapper 

132 :param api_url: The API endpoint URL 

133 """ 

134 self.api_url = api_url 

135 

136 def query( 

137 self, 

138 query_string: str, 

139 variables: Optional[Dict[str, Any]] 

140 ) -> Optional[Dict[str, Any]]: 

141 """ 

142 Executes a GraphQL query 

143 :param query_string: The query string to use 

144 :param variables: The variables to send 

145 :return: The response JSON, or None if an error occurred. 

146 """ 

147 if variables is None: 

148 variables = {} 

149 

150 resp = requests.post(self.api_url, json={ 

151 "query": query_string, 

152 "variables": variables 

153 }) 

154 if not resp.status_code < 300: 

155 return None 

156 else: 

157 return json.loads(resp.text)