anime365.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. # -*- coding: utf-8 -*-
  2. import re
  3. try:
  4. import simplejson as json
  5. except ImportError:
  6. import json
  7. import requests
  8. from bs4 import BeautifulSoup as BSoup
  9. class PyAnime365():
  10. def __init__(self, login, password, localType = "voice"):
  11. self.MainURL = "https://smotret-anime.com"
  12. self.LocalType = localType + "Ru"
  13. self.LoginHeader = {
  14. u"User-Agent": u"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.174 YaBrowser/22.1.3.848 Yowser/2.5 Safari/537.36"
  15. }
  16. self.SessionStatus = False
  17. self.Session = self.createAccountSession(login, password)
  18. def createAccountSession(self, login, password):
  19. LoginURL = self.MainURL + "/users/login"
  20. LoginSession = requests.Session()
  21. LoginSession.headers.update(self.LoginHeader)
  22. CSRFResponse = LoginSession.get(LoginURL)
  23. CSRF = BSoup(CSRFResponse.content, "html5lib").find("input", type = "hidden").attrs["value"]
  24. LoginPayloadData = {
  25. "csrf": CSRF,
  26. "LoginForm[username]": login,
  27. "LoginForm[password]": password,
  28. "yt0": "",
  29. "dynpage": 1
  30. }
  31. LoginCheckResponse = LoginSession.post(LoginURL, data = LoginPayloadData)
  32. LoginCheckText = BSoup(LoginCheckResponse.content, "html5lib").find("li").text
  33. if "E-mail" in LoginCheckText:
  34. LoginSession.close()
  35. self.SessionStatus = False
  36. print("Invalid E-Mail or password")
  37. return requests
  38. else:
  39. self.SessionStatus = True
  40. return LoginSession
  41. def GetAccountID(self):
  42. MainPageResponse = self.Session.get(self.MainURL)
  43. MainPageHTML = BSoup(MainPageResponse.content, "html5lib")
  44. RegexID = re.search(r"users/([0-9]+)/list", str(MainPageHTML.select("#top-dropdown2 > li:nth-child(2) > a[href]")[0]))
  45. return RegexID.group(1)
  46. def ExtractVideoData(self, episodeURL):
  47. VideoElement = BSoup(self.Session.get(episodeURL).content, "html5lib").find("video", {"id": "main-video"})
  48. if not VideoElement:
  49. return {}
  50. VideoURL = json.loads(VideoElement.attrs["data-sources"])[0]["urls"][0]
  51. SubURL = (self.MainURL + VideoElement.attrs["data-subtitles"].replace("?willcache", "")) if self.LocalType == "subRu" else ""
  52. return {"video": VideoURL, "sub": SubURL}
  53. def GetAnimeByID(self, animeID):
  54. AnimeResponse = self.Session.get(self.MainURL + "/api/series?id={0}".format(animeID))
  55. AnimeJSON = json.loads(AnimeResponse.content)
  56. if "error" in AnimeJSON:
  57. return {}
  58. Anime = AnimeJSON["data"]
  59. AnimeTitle = {
  60. "id": animeID,
  61. "name": Anime["titles"]["romaji"],
  62. "russian": Anime["titles"]["ru"] if "ru" in Anime["titles"] else Anime["titles"]["romaji"],
  63. "poster": Anime["posterUrl"],
  64. "description": Anime["descriptions"][0]["value"] if "descriptions" in Anime else "Description Is Invalid"
  65. }
  66. return AnimeTitle
  67. def GetAnimeListByQuery(self, query):
  68. AnimeSearchResponse = self.Session.get(self.MainURL + "/api/series?query={0}".format(query))
  69. AnimeSearchJSON = json.loads(AnimeSearchResponse.content)["data"]
  70. if not AnimeSearchJSON:
  71. return []
  72. AnimeList = []
  73. for Anime in AnimeSearchJSON:
  74. AnimeTitle = {
  75. "id": Anime["id"],
  76. "name": Anime["titles"]["romaji"],
  77. "russian": Anime["titles"]["ru"] if "ru" in Anime["titles"] else Anime["titles"]["romaji"],
  78. "poster": Anime["posterUrl"],
  79. "description": Anime["descriptions"][0]["value"] if "descriptions" in Anime else "Description Is Invalid"
  80. }
  81. AnimeList.append(AnimeTitle)
  82. return AnimeList
  83. def GetTranslationListByID(self, animeID):
  84. AnimeTranslationsResponse = self.Session.get(self.MainURL + "/api/translations?seriesId={0}&type={1}".format(animeID, self.LocalType))
  85. AnimeTranslationsJSON = json.loads(AnimeTranslationsResponse.content)["data"]
  86. if not AnimeTranslationsJSON:
  87. return []
  88. AnimeTranslationsJSON = sorted(AnimeTranslationsJSON, key = lambda x: x["authorsSummary"])
  89. AnimeTranslationList = []
  90. AuthorsTranslation = {}
  91. CountEpisodes = int(AnimeTranslationsJSON[0]["series"]["numberOfEpisodes"])
  92. for Translation in AnimeTranslationsJSON:
  93. if not Translation["authorsSummary"]:
  94. continue
  95. if Translation["authorsSummary"] not in AuthorsTranslation:
  96. AuthorsTranslation[Translation["authorsSummary"]] = []
  97. AuthorTranslation = {
  98. "episode": Translation["episode"]["episodeInt"],
  99. "episodeURL": Translation["embedUrl"]
  100. }
  101. AuthorsTranslation[Translation["authorsSummary"]].append(AuthorTranslation)
  102. for Translation in AuthorsTranslation.items():
  103. if len(Translation[1]) >= round(CountEpisodes / 2):
  104. AnimeTranslation = {
  105. "author": Translation[0],
  106. "translation": sorted(Translation[1], key = lambda x: int(x["episode"]))
  107. }
  108. AnimeTranslationList.append(AnimeTranslation)
  109. return sorted(AnimeTranslationList, key = lambda x: len(x["translation"]), reverse = True)
  110. def GetUserList(self):
  111. AccID = self.GetAccountID()
  112. UserList = {
  113. "watching": [],
  114. "completed": [],
  115. "onhold": [],
  116. "dropped": [],
  117. "planned": []
  118. }
  119. for ListType in UserList.keys():
  120. UserListResponse = self.Session.get(self.MainURL + "/users/{0}/list/{1}".format(AccID, ListType))
  121. UserListHTML = BSoup(UserListResponse.content, "html5lib")
  122. AnimeList = UserListHTML.find_all("tr", class_ = "m-animelist-item")
  123. for Anime in AnimeList:
  124. UserList[ListType].append(Anime.attrs["data-id"])
  125. return UserList
  126. def GetOngoingList(self):
  127. OngoingResponse = self.Session.get(self.MainURL + "/ongoing?view=big-list")
  128. OngoingHTML = BSoup(OngoingResponse.content, "html5lib")
  129. Animes = OngoingHTML.find_all("h2", class_ = "line-1")
  130. AnimeList = []
  131. for Anime in Animes:
  132. AnimeID = Anime.find("a").attrs["href"].split("-")[-1]
  133. AnimeList.append(AnimeID)
  134. return AnimeList
  135. def GetRandomAnimeList(self):
  136. RandomAnimesResponse = self.Session.get(self.MainURL + "/random?view=big-list")
  137. RandomAnimesHTML = BSoup(RandomAnimesResponse.content, "html5lib")
  138. Animes = RandomAnimesHTML.find_all("h2", class_ = "line-1")
  139. AnimeList = []
  140. for Anime in Animes:
  141. AnimeID = Anime.find("a").attrs["href"].split("-")[-1]
  142. AnimeList.append(AnimeID)
  143. return AnimeList