From bf777d1a29d565641d25980137fedac3e160ae72 Mon Sep 17 00:00:00 2001 From: Karl Hudgell Date: Tue, 18 Jan 2022 20:55:11 +0000 Subject: [PATCH] gogo initial commit --- .gitignore | 4 ++ backend.py | 130 +++++++++++++++++++++++++++++++++++ config.json.default | 5 ++ main.py | 163 ++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 25 +++++++ 5 files changed, 327 insertions(+) create mode 100644 .gitignore create mode 100644 backend.py create mode 100644 config.json.default create mode 100644 main.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3a51d3f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +venv/ +*.mp4 +config.json +__pycache__/ diff --git a/backend.py b/backend.py new file mode 100644 index 0000000..c4d1935 --- /dev/null +++ b/backend.py @@ -0,0 +1,130 @@ +import requests +import json +import os +from bs4 import BeautifulSoup +from dataclasses import dataclass +from colorama import Fore +from parfive import Downloader +from threading import Semaphore + + +OK = f"{Fore.RESET}[{Fore.GREEN}+{Fore.RESET}] " +ERR = f"{Fore.RESET}[{Fore.RED}-{Fore.RESET}] " +IN = f"{Fore.RESET}[{Fore.LIGHTBLUE_EX}>{Fore.RESET}] " + +global CONFIG + +screenlock = Semaphore(value=1) + + +def config_check(): + if os.path.exists("./config.json"): + with open("./config.json", "r") as f: + CONFIG = json.load(f) + if not "GoGoAnimeAuthKey" in CONFIG or len(CONFIG["GoGoAnimeAuthKey"]) == 0: + print("GoGoAnimeAuthKey not set in config.json") + exit(0) + else: + return CONFIG + else: + print("config.json file not found") + exit(0) + + +CURRENT_DOMAIN = "film" + + +@dataclass(init=True) +class Download: + name: str + episode_quality: str + folder: str + all_episodes: int + episode_start: int + episode_end: int + config: object + printed: bool = False + + def get_links(self, source=None): + if source is not None: + source_ep = f"https://gogoanime.{self.config['CurrentGoGoAnimeDomain']}/{self.name}-episode-" + episode_links = [ + f"{source_ep}{i}" + for i in range(self.episode_start, self.episode_end + 1) + ] + episode_links.insert(0, source) + else: + source_ep = f"https://gogoanime.{self.config['CurrentGoGoAnimeDomain']}/{self.name}-episode-" + episode_links = [ + f"{source_ep}{i}" + for i in range(self.episode_start, self.episode_end + 1) + ] + return episode_links + + +def get_download_link(config, url, episode_quality): + + page = requests.get( + url, + cookies=dict(auth=config["GoGoAnimeAuthKey"]), + ) + + soup = BeautifulSoup(page.content, "html.parser") + + for link in soup.find_all("a", href=True): + if episode_quality in link.text: + return link["href"] + + +def file_downloader(file_list: dict, title: str, config: object): + dl = Downloader( + max_conn=config["MaxConcurrentDownloads"], + overwrite=False, + headers=dict( + [ + ( + "User-Agent", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36", + ), + ("authority", "gogo-cdn.com"), + ("referer", f"https://gogoanime.{config['CurrentGoGoAnimeDomain']}/"), + ] + ), + ) + + for link in file_list: + dl.enqueue_file( + link, + path=f"./{title}", + ) + + files = dl.download() + return files + + +@dataclass(init=True) +class CustomMessage(Exception): + """Custom message that will accept message as a parameter and it will print it on the console.""" + + message: str = None + episode_quality: str = None + workingepisode: str = None + + def print_error(self): + screenlock.acquire() + print(ERR, self.message, end=" ") + screenlock.release() + + def qual_not_found(self): + screenlock.acquire() + print( + f"{ERR}Episode {self.workingepisode} {Fore.LIGHTCYAN_EX}{self.episode_quality}{Fore.RESET} quality not found." + ) + screenlock.release() + + def use_default_qual(self): + screenlock.acquire() + print( + f"{OK}Trying {Fore.LIGHTCYAN_EX}{self.episode_quality}{Fore.RESET} quality for Episode {self.workingepisode}." + ) + screenlock.release() diff --git a/config.json.default b/config.json.default new file mode 100644 index 0000000..9438ecf --- /dev/null +++ b/config.json.default @@ -0,0 +1,5 @@ +{ + "GoGoAnimeAuthKey": "", + "MaxConcurrentDownloads": 4, + "CurrentGoGoAnimeDomain": "film" +} \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..6747a80 --- /dev/null +++ b/main.py @@ -0,0 +1,163 @@ +import requests +import ctypes +import os +from backend import * +from bs4 import BeautifulSoup +from colorama import Fore + +OK = f"{Fore.RESET}[{Fore.GREEN}+{Fore.RESET}] " +ERR = f"{Fore.RESET}[{Fore.RED}-{Fore.RESET}] " +IN = f"{Fore.RESET}[{Fore.LIGHTBLUE_EX}>{Fore.RESET}] " +try: + ctypes.windll.kernel32.SetConsoleTitleW("GoGo Downloader") +except AttributeError: + pass + + +def gogodownloader(config): + CURRENT_DOMAIN = config["CurrentGoGoAnimeDomain"] + os.system("cls") + while True: + print( + f""" {Fore.LIGHTBLUE_EX} + + ______ ______ + / ____/___ / ____/___ + / / __/ __ \/ / __/ __ \ + / /_/ / /_/ / /_/ / /_/ / + \__________/\____/\____/ __ __ + / __ \____ _ ______ / /___ ____ _____/ /__ _____ + / / / / __ \ | /| / / __ \/ / __ \/ __ `/ __ / _ \/ ___/ + / /_/ / /_/ / |/ |/ / / / / / /_/ / /_/ / /_/ / __/ / + /_____/\____/|__/|__/_/ /_/_/\____/\__,_/\__,_/\___/_/ + + {Fore.RED} + By: Karl0ss + Forked From: sh1nobuu + Github: https://github.com/karl0ss/GoGoDownloader + """ + ) + while True: + name = input(f"{IN}Enter anime name > ").lower() + if "-" in name: + title = name.replace("-", " ").title().strip() + else: + title = name.title().strip() + source = f"https://gogoanime.{CURRENT_DOMAIN}/category/{name}" + with requests.get(source) as res: + if res.status_code == 200: + soup = BeautifulSoup(res.content, "html.parser") + all_episodes = soup.find("ul", {"id": "episode_page"}) + all_episodes = int(all_episodes.get_text().split("-")[-1].strip()) + break + else: + print(f"{ERR}Error 404: Anime not found. Please try again.") + while True: + quality = input( + f"{IN}Enter episode quality (1.SD/360P|2.SD/480P|3.HD/720P|4.FULLHD/1080P) > " + ) + if quality == "1" or quality == "": + episode_quality = "360" + break + elif quality == "2": + episode_quality = "480" + break + elif quality == "3": + episode_quality = "720" + break + elif quality == "4": + episode_quality = "1080" + break + else: + print(f"{ERR}Invalid input. Please try again.") + print(f"{OK}Title: {Fore.LIGHTCYAN_EX}{title}") + print(f"{OK}Episode/s: {Fore.LIGHTCYAN_EX}{all_episodes}") + print(f"{OK}Quality: {Fore.LIGHTCYAN_EX}{episode_quality}") + print(f"{OK}Link: {Fore.LIGHTCYAN_EX}{source}") + + folder = os.path.join(os.getcwd(), title) + if not os.path.exists(folder): + os.mkdir(folder) + + choice = "y" + + if all_episodes != 1: + while True: + choice = input( + f"{IN}Do you want to download all episode? (y/n) > " + ).lower() + if choice in ["y", "n"]: + break + else: + print(f"{ERR}Invalid input. Please try again.") + + episode_start = None + episode_end = None + + if choice == "n": + while True: + try: + episode_start = int(input(f"{IN}Episode start > ")) + episode_end = int(input(f"{IN}Episode end > ")) + if episode_start <= 0 or episode_end <= 0: + CustomMessage( + f"{ERR}episode_start or episode_end cannot be less than or equal to 0" + ).print_error() + elif episode_start >= all_episodes or episode_end > all_episodes: + CustomMessage( + f"{ERR}episode_start or episode_end cannot be more than {all_episodes}" + ).print_error() + elif episode_end <= episode_start: + CustomMessage( + f"{ERR}episode_end cannot be less than or equal to episode_start" + ).print_error() + else: + break + except ValueError: + print(f"{ERR}Invalid input. Please try again.") + + if episode_start is not None: + pass + else: + episode_start = 1 + if episode_end is not None: + pass + else: + episode_end = all_episodes + + download = Download( + name, + episode_quality, + folder, + all_episodes, + episode_start, + episode_end, + config, + ) + + source = f"https://gogoanime.{CURRENT_DOMAIN}/{name}" + with requests.get(source) as res: + soup = BeautifulSoup(res.content, "html.parser") + episode_zero = soup.find("h1", {"class": "entry-title"}) # value: 404 + + if choice == "n" or episode_zero is not None: + source = None + + dl_links = [] + episode_links = download.get_links(source) + + for link in episode_links: + dl_links.append(get_download_link(config, link, episode_quality)) + + file_downloader(dl_links, title, config) + + use_again = input(f"{IN}Do you want to use the app again? (y|n) > ").lower() + if use_again == "y": + os.system("cls") + else: + break + + +if __name__ == "__main__": + config = config_check() + gogodownloader(config) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..bafbca4 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,25 @@ +aiohttp==3.8.1 +aiosignal==1.2.0 +args==0.1.0 +async-timeout==4.0.2 +attrs==21.4.0 +beautifulsoup4==4.10.0 +black==21.12b0 +certifi==2021.10.8 +charset-normalizer==2.0.10 +click==8.0.3 +colorama==0.4.4 +frozenlist==1.2.0 +idna==3.3 +multidict==5.2.0 +mypy-extensions==0.4.3 +parfive==1.5.1 +pathspec==0.9.0 +platformdirs==2.4.1 +requests==2.27.1 +soupsieve==2.3.1 +tomli==1.2.3 +tqdm==4.62.3 +typing-extensions==4.0.1 +urllib3==1.26.8 +yarl==1.7.2