first commit

This commit is contained in:
sh1nobu 2021-09-01 16:34:08 +08:00
commit 16540ce084
7 changed files with 377 additions and 0 deletions

141
.gitignore vendored Normal file
View File

@ -0,0 +1,141 @@
# 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/
# Executable files
exe/

54
README.md Normal file
View File

@ -0,0 +1,54 @@
<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/sh1nobuu/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/). This application can only download **1**-**99** episodes at the time. At the moment, the quality of the episodes that will be downloaded is different for every anime. For **older anime**, the quality will be **360p** to **480p**, for **newer anime** the quality will be **720p** to **1080p**.
## Installation
```console
git clone https://github.com/sh1nobuu/BitAnime.git
```
## Screenshot
<div align="center">
<img src="https://i.postimg.cc/q76DzZ5y/ba-screenshot.png"
title="BitAnime in action" alt="BitAnime Screenshot">
</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-

BIN
images/ba-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
images/ba-screenshot.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
requirements.txt Normal file

Binary file not shown.

68
src/backend.py Normal file
View File

@ -0,0 +1,68 @@
import requests
import os
import shutil
from bs4 import BeautifulSoup
folder_path = ""
def get_path(folder):
global folder_path
folder_path = folder
def get_links(name, episode_number, source=None):
if source is not None:
source_ep = f"https://gogoanime.pe/{name}-episode-"
episode_links = [f"{source_ep}{i}" for i in range(1, int(episode_number) + 1)]
episode_links.insert(0, source)
else:
source_ep = f"https://gogoanime.pe/{name}-episode-"
episode_links = [f"{source_ep}{i}" for i in range(1, int(episode_number) + 1)]
return episode_links
def get_download_links(episode_links):
download_links = []
for episode_link in episode_links:
episode_link_resp = requests.get(episode_link)
soup = BeautifulSoup(episode_link_resp.content, "html.parser")
links = soup.find("li", {"class": "dowloads"})
for link in links:
link = link.get("href")
download_links.append(link)
return download_links
def get_download_urls(download_links, bool):
download_urls = []
for link in download_links:
link = requests.get(link)
soup = BeautifulSoup(link.content, "html.parser")
download_link = soup.find_all("div", {"class": "dowload"})
download_urls.append(download_link[0].a.get("href"))
if bool:
conv_download_urls = {
episode_title: url for episode_title, url in enumerate(download_urls)
}
else:
conv_download_urls = {
episode_title + 1: url
for episode_title, url in enumerate(download_urls)
}
conv_download_urls = sorted(set(conv_download_urls.items()))
return conv_download_urls
def download_episodes(url):
header = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
}
url_resp = requests.get(url[1], headers=header, stream=True)
file_name = os.path.join(folder_path, f"{url[0]}.mp4")
with open(file_name, "wb") as file:
shutil.copyfileobj(url_resp.raw, file)

114
src/bitanime.py Normal file
View File

@ -0,0 +1,114 @@
# Dependencies
import requests
import ctypes
import os
import backend as bd
import colorama
from tqdm.contrib.concurrent import thread_map
from bs4 import BeautifulSoup
from colorama import Fore
colorama.init(autoreset=True)
ctypes.windll.kernel32.SetConsoleTitleW("BitAnime")
def bitanime():
again = True
while again:
print(
f""" {Fore.LIGHTBLUE_EX}
____ _ _ _ _
| __ )(_) |_ / \ _ __ (_)_ __ ___ ___
| _ \| | __| / _ \ | '_ \| | '_ ` _ \ / _ \\
| |_) | | |_ / ___ \| | | | | | | | | | __/
|____/|_|\__/_/ \_\_| |_|_|_| |_| |_|\___|
{Fore.LIGHTYELLOW_EX}
By: sh1nobu
Github: https://github.com/sh1nobuu/BitAnime
"""
)
"""
Ask user for input and then check if the anime provided exists or if not, loop
"""
check = True
while check:
name = input(f"Enter anime name >> ").lower()
if "-" in name:
title = name.replace("-", " ").title().strip()
else:
title = name.title().strip()
source = f"https://gogoanime.pe/category/{name}"
resp = requests.get(source)
if resp.status_code == 200:
print(f"{Fore.LIGHTGREEN_EX}====================================")
check = False
else:
print(
f"{Fore.LIGHTRED_EX}Error 404: Anime not found. Please try again."
)
check = True
"""
Get how many episode/s the anime has
"""
soup = BeautifulSoup(resp.content, "html.parser")
episode_number = soup.find("ul", {"id": "episode_page"})
episode_number = episode_number.get_text().split("-")[1].strip()
"""
Print the anime name, episode, and the link of the anime
"""
print(f"Title: {Fore.LIGHTCYAN_EX}{title}")
print(f"Episode/s: {Fore.LIGHTCYAN_EX}{episode_number}")
print(f"Link: {Fore.LIGHTCYAN_EX}{source}")
print(f"{Fore.LIGHTGREEN_EX}====================================")
"""
Create a download folder for the anime
"""
folder = os.path.join(os.getcwd(), title)
if not os.path.exists(folder):
os.mkdir(folder)
"""
Check if the anime has episode 0 or not
"""
source = f"https://gogoanime.pe/{name}"
resp = requests.get(source)
soup = BeautifulSoup(resp.content, "html.parser")
episode_zero = soup.find("h1", {"class": "entry-title"})
if episode_zero is None:
# Episode 0 does exist
episode_links = bd.get_links(name, episode_number, source)
download_links = bd.get_download_links(episode_links)
download_urls = bd.get_download_urls(download_links, True)
print(f"Downloading {Fore.LIGHTCYAN_EX}{len(download_urls)} episode/s")
print(f"{Fore.LIGHTGREEN_EX}====================================")
print(download_urls)
bd.get_path(folder)
thread_map(
bd.download_episodes, download_urls, ncols=75, total=len(download_urls)
)
os.startfile(folder)
else:
# Episode 0 does not exist
episode_links = bd.get_links(name, episode_number)
download_links = bd.get_download_links(episode_links)
download_urls = bd.get_download_urls(download_links, False)
print(
f"Downloading {Fore.LIGHTCYAN_EX}{len(download_urls)}{Fore.RESET} episode/s"
)
print(f"{Fore.LIGHTGREEN_EX}====================================")
bd.get_path(folder)
thread_map(
bd.download_episodes, download_urls, ncols=75, total=len(download_urls)
)
os.startfile(folder)
use_again = input("Do you want to download other anime? (y|n) >> ").lower()
if use_again == "y":
again = True
os.system("cls")
else:
again = False
if __name__ == "__main__":
bitanime()