Skip to content
This repository has been archived by the owner on Apr 26, 2021. It is now read-only.

Commit

Permalink
Merge pull request #41 from veselysps/experimental
Browse files Browse the repository at this point in the history
Fix downloading and bump version to 0.3.1
  • Loading branch information
notmarek authored Aug 25, 2020
2 parents 6715d10 + 1a15a3f commit 78360d6
Show file tree
Hide file tree
Showing 58 changed files with 2,337 additions and 313 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,5 @@ dmypy.json

# Pyre type checker
.pyre/
"test.py"
"test.py"
.vscode/settings.json
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

Sakurajima is a Python API wrapper for [AniWatch](https://aniwatch.me).

## Disclaimer

Using this tool comes with a high risk of getting banned on AniWatch.

## Installation

Use the package manager [pip](https://pip.pypa.io/en/stable/) to install Sakurajima.
Expand Down
79 changes: 55 additions & 24 deletions Sakurajima/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import json
import base64
import random
from urllib.parse import unquote
from Sakurajima.models import (
Anime,
RecommendationEntry,
Expand All @@ -20,7 +21,7 @@
from Sakurajima.models.user_models import Friend, FriendRequestIncoming, FriendRequestOutgoing
from Sakurajima.utils.episode_list import EpisodeList
from Sakurajima.utils.network import Network

from Sakurajima.errors import AniwatchError

class Sakurajima:

Expand Down Expand Up @@ -67,6 +68,19 @@ def using_proxy(
proxy = random.choice(proxies).replace("\n", "")
return cls(username, userId, authToken, {"https": proxy})

@classmethod
def from_cookie(cls, cookie_file):
"""An alternate constructor that reads a cookie file and automatically extracts
the data neccasary to initialize Sakurajime
:param cookie_file: The file containing the cookie.
:type cookie_file: str
:rtype: :class:`Sakurajima`
"""
with open(cookie_file, "r") as cookie_file_handle:
cookie = json.loads(unquote(cookie_file_handle.read()))
return cls(cookie["username"], cookie["userid"], cookie["auth"])

def get_episode(self, episode_id, lang="en-US"):
"""Gets an AniWatchEpisode by its episode ID.
Expand All @@ -76,7 +90,7 @@ def get_episode(self, episode_id, lang="en-US"):
(English Subbed)
:type lang: str, optional
:return: An AniWatchEpisode object which has data like streams and lamguages.
:rtype: AniWatchEpisode
:rtype: :class:`AniWatchEpisode`
"""
data = {
"controller": "Anime",
Expand All @@ -96,7 +110,7 @@ def get_episodes(self, anime_id: int):
:return: An EpisodeList object. An EpisodeList is very similar to a normal list,
you can access item on a specific index the same way you would do for
a normal list. Check out the EpisodeList documentation for further details.
:rtype: EpisodeList
:rtype: :class:`EpisodeList`
"""
data = {
"controller": "Anime",
Expand All @@ -106,7 +120,7 @@ def get_episodes(self, anime_id: int):
return EpisodeList(
[
Episode(data_dict, self.network, self.API_URL, anime_id)
for data_dict in self.network.post(data)["episodes"]
for data_dict in self.network.post(data, f"/anime/{anime_id}")["episodes"]
]
)

Expand All @@ -120,7 +134,16 @@ def get_anime(self, anime_id: int):
:rtype: Anime
"""
data = {"controller": "Anime", "action": "getAnime", "detail_id": str(anime_id)}
return Anime(self.network.post(data)["anime"], network=self.network, api_url=self.API_URL,)
headers = {
"X-PATH": f"/anime/{anime_id}",
"REFERER": f"https://aniwatch.me/anime/{anime_id}"
}
json = self.network.post(data, headers)
if json.get("success", True) != True:
error = json["error"]
raise AniwatchError(error)
else:
return Anime(json["anime"], network=self.network, api_url=self.API_URL,)

def get_recommendations(self, anime_id: int):
"""Gets a list of recommendations for an anime.
Expand All @@ -138,7 +161,7 @@ def get_recommendations(self, anime_id: int):
}
return [
RecommendationEntry(data_dict, self.network)
for data_dict in self.network.post(data)["entries"]
for data_dict in self.network.post(data, f"/anime/{anime_id}")["entries"]
]

def get_relation(self, relation_id: int):
Expand Down Expand Up @@ -172,7 +195,7 @@ def get_seasonal_anime(self, index="null", year="null"):
"current_index": index,
"current_year": year,
}
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data)["entries"]]
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data, "/home")["entries"]]

def get_latest_releases(self):
"""Gets the latest anime releases. This includes currently airing
Expand All @@ -182,7 +205,7 @@ def get_latest_releases(self):
:rtype: list[Anime]
"""
data = {"controller": "Anime", "action": "getLatestReleases"}
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data)["entries"]]
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data, "/home")["entries"]]

def get_latest_uploads(self):
"""Gets latest uploads on "aniwatch.me". This includes animes that are not airing
Expand All @@ -192,7 +215,7 @@ def get_latest_uploads(self):
:rtype: list[Anime]
"""
data = {"controller": "Anime", "action": "getLatestUploads"}
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data)["entries"]]
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data, "/home")["entries"]]

def get_latest_anime(self):
"""Gets the latest animes on "aniwatch.me"
Expand All @@ -201,7 +224,7 @@ def get_latest_anime(self):
:rtype: list[Anime]
"""
data = {"controller": "Anime", "action": "getLatestAnime"}
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data)["entries"]]
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data, "/home")["entries"]]

def get_random_anime(self):
"""Gets a random anime from the aniwatch.me library.
Expand All @@ -210,7 +233,7 @@ def get_random_anime(self):
:rtype: Anime
"""
data = {"controller": "Anime", "action": "getRandomAnime"}
return Anime(self.network.post(data)["entries"][0], self.network, self.API_URL)
return Anime(self.network.post(data, "/random")["entries"][0], self.network, self.API_URL)

def get_airing_anime(self, randomize=False):
"""Gets currently airing anime arranged according to weekdays.
Expand All @@ -227,7 +250,7 @@ def get_airing_anime(self, randomize=False):
"action": "getAiringAnime",
"randomize": randomize,
}
airing_anime_response = self.network.post(data)["entries"]
airing_anime_response = self.network.post(data, "/airing")["entries"]
airing_anime = {}
for day, animes in airing_anime_response.items():
airing_anime[day] = [Anime(anime_dict, self.network, self.API_URL) for anime_dict in animes]
Expand All @@ -242,7 +265,7 @@ def get_popular_anime(self, page=1):
:rtype: list[Anime]
"""
data = {"controller": "Anime", "action": "getPopularAnime", "page": page}
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data)["entries"]]
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data, "/top")["entries"]]

def get_popular_seasonal_anime(self, page=1):
"""Gets popular anime of the current season.
Expand All @@ -253,7 +276,7 @@ def get_popular_seasonal_anime(self, page=1):
:rtype: list[Anime]
"""
data = {"controller": "Anime", "action": "getPopularSeasonals", "page": page}
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data)["entries"]]
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data, "/seasonal")["entries"]]

def get_popular_upcoming_anime(self, page=1):
"""Gets popular anime that have not started airing yet.
Expand All @@ -264,12 +287,12 @@ def get_popular_upcoming_anime(self, page=1):
:rtype: list[Anime]
"""
data = {"controller": "Anime", "action": "getPopularUpcomings", "page": page}
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data)["entries"]]
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data, "/home")["entries"]]

def get_hot_anime(self, page=1):
# TODO inspect this to figure out a correct description.
data = {"controller": "Anime", "action": "getHotAnime", "page": page}
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data)["entries"]]
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data, "/home")["entries"]]

def get_best_rated_anime(self, page=1):
"""Gets the highest rated animes on "aniwatch.me".
Expand All @@ -280,7 +303,7 @@ def get_best_rated_anime(self, page=1):
:rtype: list[Anime]
"""
data = {"controller": "Anime", "action": "getBestRatedAnime", "page": page}
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data)["entries"]]
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data, "/home")["entries"]]

def add_recommendation(self, anime_id: int, recommended_anime_id: int):
"""Submit a recommendation for an anime.
Expand Down Expand Up @@ -309,7 +332,7 @@ def get_stats(self):
:rtype: AniwatchStats
"""
data = {"controller": "XML", "action": "getStatsData"}
return AniwatchStats(self.network.post(data))
return AniwatchStats(self.network.post(data, "/stats"))

def get_user_overview(self, user_id):
"""Gets a brief user overview which includes stats like total hours watched,
Expand All @@ -325,8 +348,7 @@ def get_user_overview(self, user_id):
"action": "getOverview",
"profile_id": str(user_id),
}
print(self.network.post(data))
return UserOverview(self.network.post(data)["overview"])
return UserOverview(self.network.post(data, f"/profile/{user_id}")["overview"])

def get_user_chronicle(self, user_id, page=1):
"""Gets the user's chronicle. A chronicle tracks a user's watch history.
Expand All @@ -346,7 +368,7 @@ def get_user_chronicle(self, user_id, page=1):
"page": page,
}
return [
ChronicleEntry(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data)["chronicle"]
ChronicleEntry(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data, f"/profile/{user_id}")["chronicle"]
]

def get_user_anime_list(self):
Expand All @@ -364,7 +386,7 @@ def get_user_anime_list(self):
}
return [
UserAnimeListEntry(data_dict, self.network)
for data_dict in self.network.post(data)["animelist"]
for data_dict in self.network.post(data, f"/profile/{user_id}")["animelist"]
]

def get_user_media(self, page=1):
Expand All @@ -382,7 +404,7 @@ def get_user_media(self, page=1):
"profile_id": str(self.userId),
"page": page,
}
return [UserMedia(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data)["entries"]]
return [UserMedia(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data, f"/profile/{user_id}")["entries"]]

def send_image_to_discord(self, episode_id, base64_image, episode_time):
data = {
Expand Down Expand Up @@ -819,7 +841,16 @@ def search(self, query: str):
"maxEpisodes": 0,
"hasRelation": False,
}
return [Anime(data_dict, self.network, self.API_URL) for data_dict in self.network.post(data)]
headers = {
"X-PATH": "/search",
"REFERER": f"https://aniwatch.me/search"
}
json = self.network.post(data, headers)
if type(json) == dict and json.get("success", True) != True:
error = json["error"]
raise AniwatchError(error)
else:
return [Anime(data_dict, self.network, self.API_URL) for data_dict in json]

def get_media(self, anime_id: int):
"""Gets an anime's media.
Expand Down
3 changes: 3 additions & 0 deletions Sakurajima/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class AniwatchError(Exception):
def __init__(self, *args):
super().__init__(*args)
Loading

0 comments on commit 78360d6

Please sign in to comment.