gogoanime-dl.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #!/usr/bin/env python
  2. import requests
  3. from bs4 import BeautifulSoup
  4. import sys
  5. import re
  6. import mimetypes
  7. import time
  8. import argparse
  9. from urllib.parse import urlparse
  10. import os
  11. from http.cookiejar import LWPCookieJar
  12. requests.packages.urllib3.disable_warnings()
  13. import subprocess
  14. # Needs to get changed every week or month or two
  15. INSTANCE = "gogoanime.hu"
  16. DOWNLOADER = "yt-dlp"
  17. # Put in here mpv ok
  18. PLAYER = "mpv"
  19. COMMAND = ['fzf', '--reverse']
  20. HEADERS = {
  21. "User-Agent": "Mozilla/5.0 (Linux; Android 7.0; 5060 Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36"
  22. }
  23. def get_arguments():
  24. parser = argparse.ArgumentParser(description='GOGOanime downloader')
  25. parser.add_argument('-s', '--search', type=str, metavar='KEYWORD', help='Search Term')
  26. parser.add_argument('-n', '--filename', type=str, metavar='FILENAME', help='File Naming Convention')
  27. parser.add_argument('-p', '--player', action="store_true", default=False, help='Play with player')
  28. parser.add_argument('link', nargs="?", type=str, metavar='URL', help='GOGO link')
  29. args = parser.parse_args()
  30. return args
  31. def fetch(url):
  32. request = requests.get(url)
  33. if request.status_code != 200:
  34. sys.exit(f"Could not get {url}")
  35. else:
  36. return request.text
  37. def search(keyword):
  38. search_url = f"https://{INSTANCE}/search.html?keyword={keyword}"
  39. data = fetch(search_url)
  40. soup = BeautifulSoup(data, "html.parser")
  41. # Grab all pages
  42. pages = soup.find("ul", {"class": "pagination-list"})
  43. if pages:
  44. # How to get href's
  45. # https://stackoverflow.com/questions/5815747/beautifulsoup-getting-href
  46. # How to make for loop to list
  47. # https://www.youtube.com/watch?v=kNTveFsQVHY
  48. pagination = [f"https://{INSTANCE}/{x['href']}" for x in pages.find_all(href=True)]
  49. else:
  50. pagination = [search_url]
  51. search_data = []
  52. for page in pagination:
  53. data = fetch(page)
  54. soup = BeautifulSoup(data, "html.parser")
  55. items = soup.find("ul", {"class": "items"}).find_all("div", {"class": "img"})
  56. for num, img_data in enumerate(items):
  57. metadata = img_data.find("a")
  58. title = metadata['title']
  59. link = metadata['href']
  60. image = metadata.find("img")['src']
  61. search_data.append({
  62. "name": f"{num+1}: {title}",
  63. "title": title,
  64. "link": f"https://{INSTANCE}{link}",
  65. "image": image,
  66. "alias": link.split("/")[-1]
  67. })
  68. return search_data
  69. def episode_list(name):
  70. #pagaste: https://github.com/justfoolingaround/animdl/blob/master/animdl/core/codebase/providers/gogoanime/__init__.py
  71. page = fetch(f"https://{INSTANCE}/category/{name}")
  72. soup = BeautifulSoup(page, 'html.parser')
  73. id = soup.find("input", {"class": "movie_id"})['value'].zfill(2)
  74. gogoanime = fetch(f"https://ajax.gogo-load.com/ajax/load-list-episode?ep_start=0&ep_end=10000000&id={id}&default_ep=0&alias={name}")
  75. soup = BeautifulSoup(gogoanime, 'html.parser')
  76. episodes = soup.find_all("li")
  77. data = []
  78. for episode in episodes:
  79. number = int(episode.find('div', attrs={'class':'name'}).text.split(" ")[-1])
  80. link = f"https://{INSTANCE}"+episode.find('a')['href'][1:]
  81. data.append({
  82. "number": str(number),
  83. "link": link
  84. })
  85. return data
  86. def fzf(data, key):
  87. titles = '\n'.join([x[key] for x in data])
  88. p = subprocess.run(COMMAND, input=titles, capture_output=True, text=True)
  89. if p.stdout == "":
  90. sys.exit("Please select something.")
  91. else:
  92. try:
  93. index = int(p.stdout) - 1
  94. except:
  95. index = int(p.stdout.split("\n")[0].split(":")[0]) - 1
  96. return data[index]
  97. def scrape(url):
  98. print(url)
  99. data = fetch(url)
  100. soup = BeautifulSoup(data, "html.parser")
  101. # I wish I could get season number or something
  102. title = soup.find("div", {"class": "title_name"}).h2.text[:-1]
  103. episode = soup.find("input", {"class": "default_ep"})['value'].zfill(2)
  104. iframe = soup.find("iframe")['src']
  105. if urlparse(iframe).netloc == "ww.9anime2.com":
  106. return {"response": iframe, "title": title}
  107. print(iframe)
  108. data = fetch(iframe)
  109. links = soup.find("div", {"class": "anime_muti_link"}).find_all("a")
  110. for li in links:
  111. video = li['data-video']
  112. print(video)
  113. host = urlparse(video).netloc
  114. # For now yt-dlp has support for mp4upload
  115. if host == "www.mp4upload.com":
  116. request = video
  117. # This code is so dogwater I didn't even make it
  118. #url = video
  119. #vid_id = url.split(".html")[0].split("embed-")[1].split("/")[-1]
  120. #headers = {'referer': "https://mp4upload.com"}
  121. #data = {
  122. # 'op': 'download2',
  123. # 'id': vid_id,
  124. # 'rand': '',
  125. # 'referer': 'https://mp4upload.com/',
  126. # 'method_free': '',
  127. # 'method_premium': ''
  128. #}
  129. #request = requests.post(url, headers=headers, data=data, stream=True, verify=False)
  130. elif host == "fembed9hd.com":
  131. id = video.split("/")[-1]
  132. raw = requests.post("https://layarkacaxxi.icu/api/source/"+id).json()
  133. url = raw["data"][len(raw["data"]) - 1]["file"]
  134. session = requests.Session()
  135. session.headers["User-Agent"] = HEADERS["User-Agent"]
  136. session.cookies = LWPCookieJar()
  137. head = session.head(url)
  138. request = head.headers.get("Location", url)
  139. return {
  140. "title": title,
  141. "response": request,
  142. "episode": episode
  143. }
  144. def download(response, title, play=False):
  145. invalid = '<>:"/\|?*'
  146. for char in invalid:
  147. title = title.replace(char, '')
  148. if type(response) == str:
  149. if play == True:
  150. os.system(f"{PLAYER} --title=\"{title}\" {response}")
  151. else:
  152. os.system(f"{DOWNLOADER} {response} -o \"{title}.%(ext)s\"")
  153. return
  154. extension = mimetypes.guess_all_extensions(response.headers['Content-Type'], strict=False)[0]
  155. filename = f'{title}{extension}'
  156. print(f"[download] Destination: {filename}")
  157. with open(filename, 'wb') as f:
  158. total = int(response.headers.get('content-length'))
  159. megabytes = f"{round(float(total) / 1024, 1)}MiB"
  160. if total is None:
  161. f.write(response.content)
  162. return
  163. downloaded = 0
  164. st = time.time()
  165. for data in response.iter_content(chunk_size=max(int(total/1000), 1024*1024)):
  166. downloaded += len(data)
  167. f.write(data)
  168. et = str(time.strftime("%H:%M:%S", time.gmtime(time.time() - st)))
  169. sys.stdout.write(f'\r[download] {round((downloaded / total) * 100)}% of {megabytes} in {et}')
  170. sys.stdout.flush()
  171. sys.stdout.write('\n')
  172. def main():
  173. args = get_arguments()
  174. if args.link:
  175. data = scrape(args.link)
  176. elif args.search:
  177. selection = fzf(episode_list(fzf(search(args.search), "name")["alias"]), "number")
  178. data = scrape(selection["link"])
  179. if args.filename:
  180. title = args.filename % data
  181. else:
  182. title = data["title"]
  183. print(data)
  184. print(title)
  185. if args.player:
  186. download(data["response"], title, True)
  187. else:
  188. download(data["response"], title)
  189. if __name__ == "__main__":
  190. main()