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>
4This file is part of stockstert.
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.
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.
16You should have received a copy of the GNU General Public License
17along with stockstert. If not, see <http://www.gnu.org/licenses/>.
18LICENSE"""
21import json
22import requests
23from typing import List, Dict, Any, Optional
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"]
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"]
81 return entries
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
107 data = resp["data"]["Page"]["activities"]
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))
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]
121 return best_guess
124class GraphQlClient:
125 """
126 A simple API wrapper for GraphQL APIs
127 """
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
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 = {}
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)