mirror of
https://github.com/karl0ss/GoGoDownloader.git
synced 2025-04-26 11:39:22 +01:00
commit
99f808d37c
140
.gitignore
vendored
140
.gitignore
vendored
@ -1,138 +1,4 @@
|
|||||||
# Byte-compiled / optimized / DLL files
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
*$py.class
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
wheels/
|
|
||||||
share/python-wheels/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
MANIFEST
|
|
||||||
|
|
||||||
# PyInstaller
|
|
||||||
# Usually these files are written by a python script from a template
|
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
||||||
*.manifest
|
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.nox/
|
|
||||||
.coverage
|
|
||||||
.coverage.*
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
*.cover
|
|
||||||
*.py,cover
|
|
||||||
.hypothesis/
|
|
||||||
.pytest_cache/
|
|
||||||
cover/
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
db.sqlite3
|
|
||||||
db.sqlite3-journal
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
|
||||||
.scrapy
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
.pybuilder/
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Jupyter Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
# IPython
|
|
||||||
profile_default/
|
|
||||||
ipython_config.py
|
|
||||||
|
|
||||||
# pyenv
|
|
||||||
# For a library or package, you might want to ignore these files since the code is
|
|
||||||
# intended to run in multiple environments; otherwise, check them in:
|
|
||||||
# .python-version
|
|
||||||
|
|
||||||
# pipenv
|
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
||||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
||||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
||||||
# install all needed dependencies.
|
|
||||||
#Pipfile.lock
|
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
||||||
__pypackages__/
|
|
||||||
|
|
||||||
# Celery stuff
|
|
||||||
celerybeat-schedule
|
|
||||||
celerybeat.pid
|
|
||||||
|
|
||||||
# SageMath parsed files
|
|
||||||
*.sage.py
|
|
||||||
|
|
||||||
# Environments
|
|
||||||
.env
|
|
||||||
.venv
|
|
||||||
env/
|
|
||||||
venv/
|
venv/
|
||||||
ENV/
|
*.mp4
|
||||||
env.bak/
|
config.json
|
||||||
venv.bak/
|
__pycache__/
|
||||||
|
|
||||||
# Spyder project settings
|
|
||||||
.spyderproject
|
|
||||||
.spyproject
|
|
||||||
|
|
||||||
# Rope project settings
|
|
||||||
.ropeproject
|
|
||||||
|
|
||||||
# mkdocs documentation
|
|
||||||
/site
|
|
||||||
|
|
||||||
# mypy
|
|
||||||
.mypy_cache/
|
|
||||||
.dmypy.json
|
|
||||||
dmypy.json
|
|
||||||
|
|
||||||
# Pyre type checker
|
|
||||||
.pyre/
|
|
||||||
|
|
||||||
# pytype static type analyzer
|
|
||||||
.pytype/
|
|
||||||
|
|
||||||
# Cython debug symbols
|
|
||||||
cython_debug/
|
|
||||||
|
55
README.md
55
README.md
@ -1,55 +0,0 @@
|
|||||||
<div align="center">
|
|
||||||
<img
|
|
||||||
style="width: 165px; height: 165px"
|
|
||||||
src="https://i.postimg.cc/VkSMVQrg/ba-logo.png"
|
|
||||||
title="BitAnime"
|
|
||||||
alt="BitAnime"
|
|
||||||
/>
|
|
||||||
<h3>BitAnime</h3>
|
|
||||||
<p>
|
|
||||||
A Python script that allows you to download all of an anime's episodes at once.
|
|
||||||
</p>
|
|
||||||
<a href="https://github.com/Arctic4161/BitAnime/releases"> <strong>· Download executable version ·</strong></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## About BitAnime
|
|
||||||
|
|
||||||
**BitAnime** is a python script that allows you to download anime in large batches. It can also be used to download anime films. **BitAnime** gets its content from [gogoanime](https://gogoanime.pe/). If you get a **404** error, please look up the correct anime name on [gogoanime](https://gogoanime.pe/). The application will let you download all the episodes, or you can choose how many episodes you want to download.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```console
|
|
||||||
git clone https://github.com/Arctic4161/BitAnime.git
|
|
||||||
```
|
|
||||||
|
|
||||||
## Screenshot
|
|
||||||
|
|
||||||
<div align="center">
|
|
||||||
<img style="height:386px; width:688px;" src="https://i.postimg.cc/cLgf8994/ba-screenshot.png"
|
|
||||||
title="BitAnime in action" alt="BitAnime Screenshot">
|
|
||||||
<img style="height:386px; width:688px;" src="https://i.postimg.cc/G2qGDpfV/downloade.png" title="Katekyo Hitman Reborn" alt="Downloaded anime with BitAnime">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
**BitAnime** is highly reliant on the python modules `requests`, `colorama`, `tqdm`, and `BeautifulSoup`.
|
|
||||||
|
|
||||||
```console
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
The anime name is separated by "-". You can either type it manually, or go to [gogoanime.pe](https://gogoanime.pe/) and search for the anime you want to download and copy the name from the URL.
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
##### One word title
|
|
||||||
|
|
||||||
- https://gogoanime.pe/category/bakemonogatari >> bakemonogatari
|
|
||||||
- https://gogoanime.pe/category/steinsgate >> steinsgate
|
|
||||||
|
|
||||||
##### Multiple word title
|
|
||||||
|
|
||||||
- https://gogoanime.pe/category/shadows-house >> shadows-house
|
|
||||||
- https://gogoanime.pe/category/kono-subarashii-sekai-ni-shukufuku-wo- >> kono-subarashii-sekai-ni-shukufuku-wo-
|
|
130
backend.py
Normal file
130
backend.py
Normal file
@ -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()
|
5
config.json.default
Normal file
5
config.json.default
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"GoGoAnimeAuthKey": "",
|
||||||
|
"MaxConcurrentDownloads": 4,
|
||||||
|
"CurrentGoGoAnimeDomain": "film"
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
Binary file not shown.
Before Width: | Height: | Size: 27 KiB |
Binary file not shown.
Before Width: | Height: | Size: 652 KiB |
@ -1,37 +1,40 @@
|
|||||||
import requests as req
|
import requests
|
||||||
import ctypes
|
import ctypes
|
||||||
import os
|
import os
|
||||||
import concurrent.futures
|
from backend import *
|
||||||
from backend import Download, CustomMessage, get_download_links
|
|
||||||
from tqdm.contrib.concurrent import thread_map
|
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from colorama import Fore
|
from colorama import Fore
|
||||||
import sys
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
OK = f"{Fore.RESET}[{Fore.GREEN}+{Fore.RESET}] "
|
OK = f"{Fore.RESET}[{Fore.GREEN}+{Fore.RESET}] "
|
||||||
ERR = f"{Fore.RESET}[{Fore.RED}-{Fore.RESET}] "
|
ERR = f"{Fore.RESET}[{Fore.RED}-{Fore.RESET}] "
|
||||||
IN = f"{Fore.RESET}[{Fore.LIGHTBLUE_EX}>{Fore.RESET}] "
|
IN = f"{Fore.RESET}[{Fore.LIGHTBLUE_EX}>{Fore.RESET}] "
|
||||||
CURRENT_DOMAIN = "film"
|
|
||||||
try:
|
try:
|
||||||
ctypes.windll.kernel32.SetConsoleTitleW("BitAnime")
|
ctypes.windll.kernel32.SetConsoleTitleW("GoGo Downloader")
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def bitanime():
|
def gogodownloader(config):
|
||||||
|
CURRENT_DOMAIN = config["CurrentGoGoAnimeDomain"]
|
||||||
os.system("cls")
|
os.system("cls")
|
||||||
while True:
|
while True:
|
||||||
print(
|
print(
|
||||||
f""" {Fore.LIGHTBLUE_EX}
|
f""" {Fore.LIGHTBLUE_EX}
|
||||||
____ _ _ _ _
|
|
||||||
| __ )(_) |_ / \ _ __ (_)_ __ ___ ___
|
______ ______
|
||||||
| _ \| | __| / _ \ | '_ \| | '_ ` _ \ / _ \\
|
/ ____/___ / ____/___
|
||||||
| |_) | | |_ / ___ \| | | | | | | | | | __/
|
/ / __/ __ \/ / __/ __ \
|
||||||
|____/|_|\__/_/ \_\_| |_|_|_| |_| |_|\___|
|
/ /_/ / /_/ / /_/ / /_/ /
|
||||||
{Fore.LIGHTYELLOW_EX}
|
\__________/\____/\____/ __ __
|
||||||
By: sh1nobu
|
/ __ \____ _ ______ / /___ ____ _____/ /__ _____
|
||||||
Github: https://github.com/sh1nobuu/BitAnime
|
/ / / / __ \ | /| / / __ \/ / __ \/ __ `/ __ / _ \/ ___/
|
||||||
|
/ /_/ / /_/ / |/ |/ / / / / / /_/ / /_/ / /_/ / __/ /
|
||||||
|
/_____/\____/|__/|__/_/ /_/_/\____/\__,_/\__,_/\___/_/
|
||||||
|
|
||||||
|
{Fore.RED}
|
||||||
|
By: Karl0ss
|
||||||
|
Forked From: sh1nobuu
|
||||||
|
Github: https://github.com/karl0ss/GoGoDownloader
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
while True:
|
while True:
|
||||||
@ -41,7 +44,7 @@ def bitanime():
|
|||||||
else:
|
else:
|
||||||
title = name.title().strip()
|
title = name.title().strip()
|
||||||
source = f"https://gogoanime.{CURRENT_DOMAIN}/category/{name}"
|
source = f"https://gogoanime.{CURRENT_DOMAIN}/category/{name}"
|
||||||
with req.get(source) as res:
|
with requests.get(source) as res:
|
||||||
if res.status_code == 200:
|
if res.status_code == 200:
|
||||||
soup = BeautifulSoup(res.content, "html.parser")
|
soup = BeautifulSoup(res.content, "html.parser")
|
||||||
all_episodes = soup.find("ul", {"id": "episode_page"})
|
all_episodes = soup.find("ul", {"id": "episode_page"})
|
||||||
@ -54,16 +57,16 @@ def bitanime():
|
|||||||
f"{IN}Enter episode quality (1.SD/360P|2.SD/480P|3.HD/720P|4.FULLHD/1080P) > "
|
f"{IN}Enter episode quality (1.SD/360P|2.SD/480P|3.HD/720P|4.FULLHD/1080P) > "
|
||||||
)
|
)
|
||||||
if quality == "1" or quality == "":
|
if quality == "1" or quality == "":
|
||||||
episode_quality = "SDP"
|
episode_quality = "360"
|
||||||
break
|
break
|
||||||
elif quality == "2":
|
elif quality == "2":
|
||||||
episode_quality = "SHD"
|
episode_quality = "480"
|
||||||
break
|
break
|
||||||
elif quality == "3":
|
elif quality == "3":
|
||||||
episode_quality = "HDP"
|
episode_quality = "720"
|
||||||
break
|
break
|
||||||
elif quality == "4":
|
elif quality == "4":
|
||||||
episode_quality = "FullHDP"
|
episode_quality = "1080"
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
print(f"{ERR}Invalid input. Please try again.")
|
print(f"{ERR}Invalid input. Please try again.")
|
||||||
@ -123,39 +126,31 @@ def bitanime():
|
|||||||
episode_end = all_episodes
|
episode_end = all_episodes
|
||||||
|
|
||||||
download = Download(
|
download = Download(
|
||||||
name, episode_quality, folder, all_episodes, episode_start, episode_end
|
name,
|
||||||
|
episode_quality,
|
||||||
|
folder,
|
||||||
|
all_episodes,
|
||||||
|
episode_start,
|
||||||
|
episode_end,
|
||||||
|
config,
|
||||||
)
|
)
|
||||||
|
|
||||||
source = f"https://gogoanime.{CURRENT_DOMAIN}/{name}"
|
source = f"https://gogoanime.{CURRENT_DOMAIN}/{name}"
|
||||||
with req.get(source) as res:
|
with requests.get(source) as res:
|
||||||
soup = BeautifulSoup(res.content, "html.parser")
|
soup = BeautifulSoup(res.content, "html.parser")
|
||||||
episode_zero = soup.find("h1", {"class": "entry-title"}) # value: 404
|
episode_zero = soup.find("h1", {"class": "entry-title"}) # value: 404
|
||||||
|
|
||||||
if choice == "n" or episode_zero is not None:
|
if choice == "n" or episode_zero is not None:
|
||||||
source = None
|
source = None
|
||||||
|
|
||||||
|
dl_links = []
|
||||||
episode_links = download.get_links(source)
|
episode_links = download.get_links(source)
|
||||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
||||||
download_links = list(executor.map(get_download_links, episode_links))
|
|
||||||
download_urls = list(
|
|
||||||
executor.map(download.get_download_urls, download_links)
|
|
||||||
)
|
|
||||||
print(
|
|
||||||
f"{OK}Downloading {Fore.LIGHTCYAN_EX}{len(download_urls)}{Fore.RESET} episode/s"
|
|
||||||
)
|
|
||||||
thread_map(
|
|
||||||
download.download_episodes,
|
|
||||||
download_urls,
|
|
||||||
ncols=75,
|
|
||||||
total=len(download_urls),
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
for link in episode_links:
|
||||||
os.startfile(folder)
|
dl_links.append(get_download_link(config, link, episode_quality))
|
||||||
except AttributeError:
|
|
||||||
opener = "open" if sys.platform == "darwin" else "xdg-open"
|
file_downloader(dl_links, title, config)
|
||||||
subprocess.call([opener, folder])
|
|
||||||
print("\n")
|
|
||||||
use_again = input(f"{IN}Do you want to use the app again? (y|n) > ").lower()
|
use_again = input(f"{IN}Do you want to use the app again? (y|n) > ").lower()
|
||||||
if use_again == "y":
|
if use_again == "y":
|
||||||
os.system("cls")
|
os.system("cls")
|
||||||
@ -164,4 +159,5 @@ def bitanime():
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
bitanime()
|
config = config_check()
|
||||||
|
gogodownloader(config)
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
223
src/backend.py
223
src/backend.py
@ -1,223 +0,0 @@
|
|||||||
# Dependencies
|
|
||||||
import requests as req
|
|
||||||
import shutil
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from colorama import Fore
|
|
||||||
from random import choice
|
|
||||||
from requests.exceptions import Timeout
|
|
||||||
import time
|
|
||||||
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}] "
|
|
||||||
|
|
||||||
screenlock = Semaphore(value=1)
|
|
||||||
|
|
||||||
|
|
||||||
def random_headers():
|
|
||||||
desktop_agents = [
|
|
||||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Edg/94.0.992.47",
|
|
||||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36',
|
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36',
|
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36',
|
|
||||||
'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
|
|
||||||
'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36',
|
|
||||||
'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36',
|
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36']
|
|
||||||
return { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
|
||||||
"Accept-Language": "en-US,en;q=0.5",
|
|
||||||
"Accept-Encoding": "gzip, deflate, br",
|
|
||||||
"Connection": "keep-alive",
|
|
||||||
"Referer": "https://gogoplay1.com/",
|
|
||||||
'User-Agent': choice(desktop_agents)}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_download_links(episode_link):
|
|
||||||
with req.get(episode_link) as res:
|
|
||||||
soup = BeautifulSoup(res.content, "html.parser")
|
|
||||||
exist = soup.find("h1", {"class": "entry-title"})
|
|
||||||
workinglinkis = episode_link.split('-')
|
|
||||||
if exist is None:
|
|
||||||
# Episode link == 200
|
|
||||||
episode_link = soup.find("li", {"class": "dowloads"})
|
|
||||||
return [workinglinkis[-1], episode_link.a.get("href")]
|
|
||||||
else:
|
|
||||||
# Episode link == 404
|
|
||||||
episode_link = f"{episode_link}-"
|
|
||||||
with req.get(episode_link) as find:
|
|
||||||
soup = BeautifulSoup(find.content, "html.parser")
|
|
||||||
exist = soup.find("h1", {"class": "entry-title"})
|
|
||||||
if exist is None:
|
|
||||||
episode_link = soup.find("li", {"class": "dowloads"})
|
|
||||||
return [workinglinkis[-1], episode_link.a.get("href")]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(init=True)
|
|
||||||
class Download:
|
|
||||||
name: str
|
|
||||||
episode_quality: str
|
|
||||||
folder: str
|
|
||||||
all_episodes: int
|
|
||||||
episode_start: int
|
|
||||||
episode_end: int
|
|
||||||
printed: bool = False
|
|
||||||
|
|
||||||
def get_links(self, source=None):
|
|
||||||
if source is not None:
|
|
||||||
source_ep = f"https://gogoanime.wiki/{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.wiki/{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_urls(self, download_link):
|
|
||||||
episode_quality = self.episode_quality
|
|
||||||
workingepisode = download_link[0]
|
|
||||||
if episode_quality == "FullHDP":
|
|
||||||
episode_quality = "1080P - mp4"
|
|
||||||
elif episode_quality == "HDP":
|
|
||||||
episode_quality = "720P - mp4"
|
|
||||||
elif episode_quality == "SHD":
|
|
||||||
episode_quality = "480P - mp4"
|
|
||||||
elif episode_quality == "SDP":
|
|
||||||
episode_quality = "360P - mp4"
|
|
||||||
else:
|
|
||||||
episode_quality = "1080P - mp4"
|
|
||||||
with req.get(download_link[1], headers=random_headers(), timeout=3) as res:
|
|
||||||
soup = BeautifulSoup(res.content, "html.parser")
|
|
||||||
link = soup.find("div", {"class": "dowload"}, text=re.compile(episode_quality))
|
|
||||||
if link is None:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
with req.get(link.a.get("href"), headers=random_headers(), stream=True,
|
|
||||||
timeout=3) as workingit:
|
|
||||||
if workingit.status_code != 200:
|
|
||||||
link = None
|
|
||||||
elif workingit.headers['Content-Type'] != 'video/mp4':
|
|
||||||
link = None
|
|
||||||
except Timeout:
|
|
||||||
link = None
|
|
||||||
if link is None:
|
|
||||||
if episode_quality == "1080P - mp4":
|
|
||||||
episode_quality = "FullHDP"
|
|
||||||
time.sleep(1)
|
|
||||||
CustomMessage('None', episode_quality, workingepisode).qual_not_found()
|
|
||||||
episode_quality = "HDP"
|
|
||||||
time.sleep(1)
|
|
||||||
CustomMessage('None', episode_quality, workingepisode).use_default_qual()
|
|
||||||
episode_quality = "720P - mp4"
|
|
||||||
link = soup.find("div", {"class": "dowload"}, text=re.compile(episode_quality))
|
|
||||||
if link is None:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
with req.get(link.a.get("href"), headers=random_headers(), stream=True,
|
|
||||||
timeout=3) as workingit:
|
|
||||||
if workingit.status_code != 200:
|
|
||||||
link = None
|
|
||||||
elif workingit.headers['Content-Type'] != 'video/mp4':
|
|
||||||
link = None
|
|
||||||
except Timeout:
|
|
||||||
link = None
|
|
||||||
if link is None:
|
|
||||||
if episode_quality == "720P - mp4":
|
|
||||||
episode_quality = "HDP"
|
|
||||||
time.sleep(1)
|
|
||||||
CustomMessage('None', episode_quality, workingepisode).qual_not_found()
|
|
||||||
episode_quality = "SHD"
|
|
||||||
time.sleep(1)
|
|
||||||
CustomMessage('None', episode_quality, workingepisode).use_default_qual()
|
|
||||||
episode_quality = "480P - mp4"
|
|
||||||
link = soup.find("div", {"class": "dowload"}, text=re.compile(episode_quality))
|
|
||||||
if link is None:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
with req.get(link.a.get("href"), headers=random_headers(), stream=True,
|
|
||||||
timeout=3) as workingit:
|
|
||||||
if workingit.status_code != 200:
|
|
||||||
link = None
|
|
||||||
elif workingit.headers['Content-Type'] != 'video/mp4':
|
|
||||||
link = None
|
|
||||||
except Timeout:
|
|
||||||
link = None
|
|
||||||
if link is None:
|
|
||||||
if episode_quality == "480P - mp4":
|
|
||||||
episode_quality = "SHD"
|
|
||||||
time.sleep(1)
|
|
||||||
CustomMessage('None', episode_quality, workingepisode).qual_not_found()
|
|
||||||
episode_quality = "SDP"
|
|
||||||
time.sleep(1)
|
|
||||||
CustomMessage('None', episode_quality, workingepisode).use_default_qual()
|
|
||||||
episode_quality = "360P - mp4"
|
|
||||||
link = soup.find("div", {"class": "dowload"}, text=re.compile(episode_quality))
|
|
||||||
else:
|
|
||||||
pass
|
|
||||||
return [download_link[1].split("+")[-1], link.a.get("href")]
|
|
||||||
|
|
||||||
def download_episodes(self, url):
|
|
||||||
with req.get(url[1], headers=random_headers(), stream=True, timeout=10,
|
|
||||||
allow_redirects=True) as workingurl:
|
|
||||||
episode_name = "EP." + url[0] + ".mp4"
|
|
||||||
file_loc = os.path.join(self.folder, episode_name)
|
|
||||||
with open(file_loc, "w+b") as file:
|
|
||||||
shutil.copyfileobj(workingurl.raw, file, 8192)
|
|
||||||
|
|
||||||
size = os.stat(file_loc).st_size
|
|
||||||
count = 0
|
|
||||||
while int(size) < 5 and count < 5:
|
|
||||||
with req.get(url[1], headers=random_headers(), stream=True, timeout=10,
|
|
||||||
allow_redirects=True) as workingurl:
|
|
||||||
episode_name = "EP." + url[0] + ".mp4"
|
|
||||||
file_loc = os.path.join(self.folder, episode_name)
|
|
||||||
with open(file_loc, "w+b") as file:
|
|
||||||
shutil.copyfileobj(workingurl.raw, file, 8192)
|
|
||||||
count += 1
|
|
||||||
size = os.stat(file_loc).st_size
|
|
||||||
size = os.stat(file_loc).st_size
|
|
||||||
if int(size) < 5:
|
|
||||||
print("\n")
|
|
||||||
CustomMessage('Could not download episode ' + url[0]).print_error()
|
|
||||||
os.remove(file_loc)
|
|
||||||
|
|
||||||
|
|
||||||
@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()
|
|
Loading…
x
Reference in New Issue
Block a user