commit 16540ce08440cef49543ad5240e47e6876233170
Author: sh1nobu <rvnpangpengwa@gmail.com>
Date:   Wed Sep 1 16:34:08 2021 +0800

    first commit

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d85d89c
--- /dev/null
+++ b/.gitignore
@@ -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/
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..622b02e
--- /dev/null
+++ b/README.md
@@ -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-
diff --git a/images/ba-logo.png b/images/ba-logo.png
new file mode 100644
index 0000000..cb8d0e6
Binary files /dev/null and b/images/ba-logo.png differ
diff --git a/images/ba-screenshot.PNG b/images/ba-screenshot.PNG
new file mode 100644
index 0000000..ec13c2b
Binary files /dev/null and b/images/ba-screenshot.PNG differ
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..079fb68
Binary files /dev/null and b/requirements.txt differ
diff --git a/src/backend.py b/src/backend.py
new file mode 100644
index 0000000..5ac4bfa
--- /dev/null
+++ b/src/backend.py
@@ -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)
diff --git a/src/bitanime.py b/src/bitanime.py
new file mode 100644
index 0000000..998da4d
--- /dev/null
+++ b/src/bitanime.py
@@ -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()