mirror of
				https://github.com/karl0ss/GoGoDownloader.git
				synced 2025-11-04 08:31:04 +00:00 
			
		
		
		
	clean repo
This commit is contained in:
		
							parent
							
								
									1fa2e28b70
								
							
						
					
					
						commit
						3262b2c69e
					
				
							
								
								
									
										138
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										138
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,138 +0,0 @@
 | 
				
			|||||||
# 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/
 | 
					 | 
				
			||||||
							
								
								
									
										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-
 | 
					 | 
				
			||||||
										
											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
										
									
								
								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()
 | 
					 | 
				
			||||||
							
								
								
									
										167
									
								
								src/bitanime.py
									
									
									
									
									
								
							
							
						
						
									
										167
									
								
								src/bitanime.py
									
									
									
									
									
								
							@ -1,167 +0,0 @@
 | 
				
			|||||||
import requests as req
 | 
					 | 
				
			||||||
import ctypes
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
import concurrent.futures
 | 
					 | 
				
			||||||
from backend import Download, CustomMessage, get_download_links
 | 
					 | 
				
			||||||
from tqdm.contrib.concurrent import thread_map
 | 
					 | 
				
			||||||
from bs4 import BeautifulSoup
 | 
					 | 
				
			||||||
from colorama import Fore
 | 
					 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
import subprocess
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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}] "
 | 
					 | 
				
			||||||
CURRENT_DOMAIN = "film"
 | 
					 | 
				
			||||||
try:
 | 
					 | 
				
			||||||
    ctypes.windll.kernel32.SetConsoleTitleW("BitAnime")
 | 
					 | 
				
			||||||
except AttributeError:
 | 
					 | 
				
			||||||
    pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def bitanime():
 | 
					 | 
				
			||||||
    os.system("cls")
 | 
					 | 
				
			||||||
    while True:
 | 
					 | 
				
			||||||
        print(
 | 
					 | 
				
			||||||
            f""" {Fore.LIGHTBLUE_EX}
 | 
					 | 
				
			||||||
                   ____  _ _      _          _
 | 
					 | 
				
			||||||
                  | __ )(_) |_   / \   _ __ (_)_ __ ___   ___
 | 
					 | 
				
			||||||
                  |  _ \| | __| / _ \ | '_ \| | '_ ` _ \ / _ \\
 | 
					 | 
				
			||||||
                  | |_) | | |_ / ___ \| | | | | | | | | |  __/
 | 
					 | 
				
			||||||
                  |____/|_|\__/_/   \_\_| |_|_|_| |_| |_|\___|
 | 
					 | 
				
			||||||
                              {Fore.LIGHTYELLOW_EX}
 | 
					 | 
				
			||||||
                                  By: sh1nobu
 | 
					 | 
				
			||||||
                  Github: https://github.com/sh1nobuu/BitAnime
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        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 req.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 = "SDP"
 | 
					 | 
				
			||||||
                break
 | 
					 | 
				
			||||||
            elif quality == "2":
 | 
					 | 
				
			||||||
                episode_quality = "SHD"
 | 
					 | 
				
			||||||
                break
 | 
					 | 
				
			||||||
            elif quality == "3":
 | 
					 | 
				
			||||||
                episode_quality = "HDP"
 | 
					 | 
				
			||||||
                break
 | 
					 | 
				
			||||||
            elif quality == "4":
 | 
					 | 
				
			||||||
                episode_quality = "FullHDP"
 | 
					 | 
				
			||||||
                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
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        source = f"https://gogoanime.{CURRENT_DOMAIN}/{name}"
 | 
					 | 
				
			||||||
        with req.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),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        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")
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            break
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == "__main__":
 | 
					 | 
				
			||||||
    bitanime()
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user