Merge pull request #1 from karl0ss/master

update my fork
This commit is contained in:
Arctic4161 2022-06-06 22:19:45 -05:00 committed by GitHub
commit 5a2d682cae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 359 additions and 434 deletions

143
.gitignore vendored
View File

@ -1,138 +1,7 @@
# 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/
ENV/
env.bak/
venv.bak/
# 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/
*.mp4
config.json
__pycache__/
build/
dist/
main.spec

View File

@ -1,50 +1,56 @@
import requests as req
import requests
import ctypes
import os
import concurrent.futures
from backend import Download, CustomMessage, get_download_links
from tqdm.contrib.concurrent import thread_map
from backend import gogoanime, CustomMessage, config_check
from bs4 import BeautifulSoup
from colorama import Fore
import sys
import subprocess
import logging
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("BitAnime")
ctypes.windll.kernel32.SetConsoleTitleW("GoGo Downloader")
except AttributeError:
pass
def bitanime():
os.system("cls")
def gogodownloader(config):
CURRENT_DOMAIN = config["CurrentGoGoAnimeDomain"]
os.system("cls" if os.name == "nt" else "clear")
while True:
print(
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:
name = input(f"{IN}Enter anime name > ").lower()
logging.info("episode searched for " + name)
if "-" in name:
title = name.replace("-", " ").title().strip()
else:
title = name.title().strip()
source = f"https://gogoanime.wiki/category/{name}"
with req.get(source) as res:
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())
all_episodes = int(list(filter(None, "-".join(all_episodes.get_text().splitlines()).split("-")))[-1].strip())
break
else:
print(f"{ERR}Error 404: Anime not found. Please try again.")
@ -53,24 +59,25 @@ def bitanime():
f"{IN}Enter episode quality (1.SD/360P|2.SD/480P|3.HD/720P|4.FULLHD/1080P) > "
)
if quality == "1" or quality == "":
episode_quality = "SDP"
episode_quality = "360"
break
elif quality == "2":
episode_quality = "SHD"
episode_quality = "480"
break
elif quality == "3":
episode_quality = "HDP"
episode_quality = "720"
break
elif quality == "4":
episode_quality = "FullHDP"
episode_quality = "1080"
break
else:
print(f"{ERR}Invalid input. Please try again.")
logging.info("quality selected " + episode_quality)
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)
@ -121,44 +128,49 @@ def bitanime():
else:
episode_end = all_episodes
download = Download(
name, episode_quality, folder, all_episodes, episode_start, episode_end
gogo = gogoanime(
config,
name,
episode_quality,
folder,
all_episodes,
episode_start,
episode_end,
title,
)
source = f"https://gogoanime.wiki/{name}"
with req.get(source) as res:
gogo.user_logged_in_check()
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
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)
)
dl_links = []
episode_links = gogo.get_links(source)
print(f"{OK}Scraping Links")
for link in episode_links:
dl_links.append(gogo.get_download_link(link))
result = gogo.file_downloader(dl_links)
if len(result.errors) > 0:
while len(result.errors) > 0:
print(f"{ERR}{len(result.errors)} links failed retrying.")
episode_links = gogo.get_links(source)
print(f"{OK}Re-Scraping Links")
dl_links.clear()
for link in episode_links:
dl_links.append(gogo.get_download_link(link))
result = gogo.file_downloader(dl_links, overwrite_downloads=0)
try:
os.startfile(folder)
except AttributeError:
opener = "open" if sys.platform == "darwin" else "xdg-open"
subprocess.call([opener, folder])
print("\n")
use_again = input(f"{IN}Do you want to use the app again? (y|n) > ").lower()
if use_again == "y":
os.system("cls")
os.system("cls" if os.name == "nt" else "clear")
else:
break
if __name__ == "__main__":
bitanime()
config = config_check()
gogodownloader(config)

View File

@ -1,55 +1,72 @@
<div align="center">
<img
style="width: 165px; height: 165px"
src="https://i.postimg.cc/VkSMVQrg/ba-logo.png"
title="BitAnime"
alt="BitAnime"
style="width: 300px; height: 300px"
src="https://github.com/karl0ss/GoGoDownloader/raw/master/img/gogo_logo.png"
title="GoGoDownloader"
alt="GoGoDownloader"
/>
<h3>BitAnime</h3>
<h3>GoGo Downloader</h3>
<h4>Forked from <a href="https://github.com/sh1nobuu/BitAnime">BitAnime</a></h4>
<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
## About GoGo Downloader
**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.
GoGo Downloader is based on the now broken **BitAnime**. I have had to rework quite a bit of the code to get it working again, and have ideas for some other improvements, I don't want to mess with the original codebase too much, hence **GoGo Downloader**.
**GoGo Downloader** gets its content from [gogoanime](https://gogoanime.film/). If you get a **404** error, please look up the correct anime name on [gogoanime](https://gogoanime.film/). The application will let you download all the episodes, or you can choose how many episodes you want to download.
GoGo Anime has changed the way they show download links, and this no longer works via BS4, as the recaptcha blocks the links, but if you are logged in, there are other routes to get to download links, I have taken one of these routes to restore the application.
## Features
- Download all qualities options from GoGoAnime
- Update the current GoGoAnime domain via config file (as they keep changing it)
- Specify the number of concurrent downloads via config file (Max is 6)
- Set file overwrite via config file (0 = Skip / 1 = Overwrite)
## Installation
You have 2 options here, you can download the exe on the releases page and run on Windows
```console
git clone https://github.com/Arctic4161/BitAnime.git
```
- Download the zip
- Extract and set your GoGoAnime Username and Password in the config.json
- Run the exe
If you want to run from source, or are using Linux/Mac you can run directly from source doing the following -
- `git clone https://github.com/karl0ss/GoGoDownloader.git`
- `pip install -r requirements.txt`
- Create config.json from config.json.default
- Add your GoGoAnime Username and Password to config.json (Can't be a Google account)
- Run the app with `python GoGoDownloader.py`
## Screenshot
<div align="center">
<img style="height:386px; width:688px;" src="https://i.postimg.cc/cLgf8994/ba-screenshot.png"
<img style="height:386px; width:688px;" src="https://github.com/karl0ss/GoGoDownloader/raw/master/img/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
```
**GoGo Downloader** is highly reliant on the python modules `requests`, `colorama`, `parfive`, and `BeautifulSoup`.
## 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.
The anime name is separated by "-". You can either type it manually, or go to [gogoanime.film](https://gogoanime.film/) 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
- https://gogoanime.film/category/bakemonogatari >> bakemonogatari
- https://gogoanime.film/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-
- https://gogoanime.film/category/shadows-house >> shadows-house
- https://gogoanime.film/category/kono-subarashii-sekai-ni-shukufuku-wo- >> kono-subarashii-sekai-ni-shukufuku-wo-

242
backend.py Normal file
View File

@ -0,0 +1,242 @@
import re
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
import logging
logging.basicConfig(
level=logging.INFO,
filename="app.log",
filemode="w",
format="%(name)s - %(levelname)s - %(message)s",
)
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():
"""Check for config.json and check required keys are set
Returns:
[object]: Config object
"""
if os.path.exists("./config.json"):
logging.info("Config.json loaded")
with open("./config.json", "r") as f:
CONFIG = json.load(f)
if not "GoGoAnime_Username" in CONFIG or len(CONFIG["GoGoAnime_Username"]) == 0:
logging.error("GoGoAnime_Username not set in config.json")
print("GoGoAnime_Username not set in config.json")
exit(0)
else:
if (
not "GoGoAnime_Password" in CONFIG
or len(CONFIG["GoGoAnime_Password"]) == 0
):
logging.error("GoGoAnime_Password not set in config.json")
print("GoGoAnime_Password not set in config.json")
exit(0)
else:
logging.info(
"Config loaded and "
+ CONFIG["GoGoAnime_Username"]
+ " username found"
)
return CONFIG
else:
logging.error("config.json not found")
print("config.json file not found")
exit(0)
def max_concurrent_downloads(max_conn: int):
"""Check max_concurrent_downloads value and restrict to below 6
Args:
max_conn (int): Max concurrent downloads to allow
Returns:
[int]: Max concurrent downloads allowed
"""
if max_conn > 6:
return 6
else:
return max_conn
CURRENT_DOMAIN = "film"
@dataclass(init=True)
class gogoanime:
config: object
name: str
episode_quality: str
folder: str
all_episodes: int
episode_start: int
episode_end: int
title: str
printed: bool = False
def get_gogoanime_auth_cookie(self):
session = requests.session()
page = session.get(
f"https://gogoanime.{self.config['CurrentGoGoAnimeDomain']}/login.html"
)
soup = BeautifulSoup(page.content, "html.parser")
meta_path = soup.select('meta[name="csrf-token"]')
csrf_token = meta_path[0].attrs["content"]
url = f"https://gogoanime.{self.config['CurrentGoGoAnimeDomain']}/login.html"
payload = f"email={self.config['GoGoAnime_Username']}&password={self.config['GoGoAnime_Password']}&_csrf={csrf_token}"
headers = {
"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.{self.config['CurrentGoGoAnimeDomain']}/",
"content-type": "application/x-www-form-urlencoded",
}
session.headers = headers
r = session.post(url, data=payload, headers=headers)
if r.status_code == 200:
return session.cookies.get_dict().get("auth")
else:
print("ldldl")
def user_logged_in_check(
self,
):
page = requests.get(
f"https://gogoanime.{self.config['CurrentGoGoAnimeDomain']}/one-piece-episode-1",
cookies=dict(auth=gogoanime.get_gogoanime_auth_cookie(self)),
)
soup = BeautifulSoup(page.content, "html.parser")
loginCheck = soup(text=re.compile("Logout"))
if len(loginCheck) == 0:
raise Exception(
"User is not logged in, make sure account has been activated"
)
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(self, url):
page = requests.get(
url,
cookies=dict(auth=gogoanime.get_gogoanime_auth_cookie(self)),
)
quality_arr = ["1080", "720", "640", "480"]
soup = BeautifulSoup(page.content, "html.parser")
try:
for link in soup.find_all(
"a", href=True, string=re.compile(self.episode_quality)
):
return link["href"]
else:
ep_num = url.rsplit("-", 1)[1]
print(
f"{self.episode_quality} not found for ep{ep_num} checking for next best"
)
for q in quality_arr:
for link in soup.find_all("a", href=True, string=re.compile(q)):
print(f"{q} found.")
return link["href"]
except:
print("No matching download found")
def file_downloader(self, file_list: dict, overwrite_downloads: bool = None):
"""[summary]
Args:
file_list (dict): [description]
overwrite_downloads (bool, optional): [description]. Defaults to None.
Returns:
[type]: [description]
"""
if overwrite_downloads is None:
overwrite = self.config["OverwriteDownloads"]
else:
overwrite = overwrite_downloads
dl = Downloader(
max_conn=max_concurrent_downloads(self.config["MaxConcurrentDownloads"]),
overwrite=overwrite,
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.{self.config['CurrentGoGoAnimeDomain']}/",
),
]
),
)
for link in file_list:
if link is not None:
dl.enqueue_file(
link,
path=f"./{self.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()

7
config.json.default Normal file
View File

@ -0,0 +1,7 @@
{
"GoGoAnime_Username":"",
"GoGoAnime_Password":"",
"MaxConcurrentDownloads": 4,
"CurrentGoGoAnimeDomain": "gg",
"OverwriteDownloads": 0
}

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

BIN
img/gogo_icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
img/gogo_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
img/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

View File

@ -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()

1
version.txt Normal file
View File

@ -0,0 +1 @@
3.1.1