Compare commits

..

33 Commits

Author SHA1 Message Date
Karl Hudgell
f55d917cc9 quick .5 fix 2024-03-02 11:23:02 +00:00
Karl Hudgell
475466617d update message 2023-08-08 15:44:12 +01:00
Karl Hudgell
02fa241ec6 fix for single episodes 2023-08-08 15:42:53 +01:00
3b599893bc
Merge pull request #16 from karl0ss/latestUpdates
Latest updates
2023-08-06 16:51:42 +01:00
664f5f4974
Merge branch 'master' into latestUpdates 2023-08-06 16:51:36 +01:00
Karl Hudgell
62712a3897 latest commit 2023-08-06 16:48:07 +01:00
Karl Hudgell
d865913154 latest update 2023-08-06 16:48:00 +01:00
2fc41cfa56
Merge pull request #12 from Arctic4161/master
Fix Backend.py
2023-05-23 17:20:59 +01:00
Arctic4161
5211c127e4
Merge pull request #3 from karl0ss/master
Update Fork
2022-11-21 22:16:45 -06:00
Arctic4161
fd1046f8a7
Update backend.py 2022-11-21 22:11:05 -06:00
78a394ffd5
Merge pull request #9 from karl0ss/CreateCLITool
Create cli tool
2022-06-28 08:50:02 +01:00
karl.hudgell
2d1eda3b92 upversion 2022-06-28 08:48:37 +01:00
karl.hudgell
8210e0b07b working CLI tool 2022-06-28 08:48:05 +01:00
karl.hudgell
fc19a690bd loadDownloadHistory 2022-06-21 12:32:46 +01:00
karl.hudgell
b002368705 ignore downloadHistory.json 2022-06-21 12:32:23 +01:00
karl.hudgell
ee82a26e76 handle special characters in show name 2022-06-21 12:22:59 +01:00
karl.hudgell
7c4a569678 update config.json 2022-06-21 12:09:19 +01:00
karl.hudgell
9ea3c6a6ce create new CLI to process users bookmarks 2022-06-21 12:09:10 +01:00
karl.hudgell
64acd0abb2 get_show_from_bookmark 2022-06-21 12:08:52 +01:00
karl.hudgell
a09ed8c802 ignore bookmarkList 2022-06-21 12:08:36 +01:00
karl.hudgell
a8d54be2d3 ignore app.log 2022-06-20 12:50:22 +01:00
karl.hudgell
0dffecc6ff ignore the launch.json 2022-06-20 12:50:07 +01:00
karl.hudgell
46001b041c initial commit of clovisNyu cli 2022-06-20 12:49:36 +01:00
Arctic4161
5a2d682cae
Merge pull request #1 from karl0ss/master
update my fork
2022-06-06 22:19:45 -05:00
1b2738d4b2
update to new domain 2022-03-13 17:35:54 +00:00
72cef9b292
Merge pull request #7 from digitalw00t/domainfix
remove fixed domain from test
2022-03-12 21:10:13 +00:00
Andrew Falgout
6ba9477a89
remove fixed domain from test 2022-03-12 14:50:49 -06:00
093437f464
Merge pull request #6 from RobinLaevaert/AddBetterLastEpisodeChecker
Add better last episode checker
2022-02-28 09:20:17 +00:00
Robin Laevaert
7a382de2f6 Add better last episode checker 2022-02-27 15:41:44 +01:00
karl.hudgell
02f275e13a 3.1.1 2022-02-23 08:47:45 +00:00
karl.hudgell
bc957b0607 replace litterals and cross platform cls 2022-02-23 08:47:31 +00:00
b3b02e040c
Merge pull request #5 from karl0ss/addLoggedInCheck
quick check for logged in user and some logs
2022-02-22 16:35:44 +00:00
karl.hudgell
bbec182b38 quick check for logged in user and some logs 2022-02-22 16:35:18 +00:00
10 changed files with 286 additions and 31 deletions

4
.gitignore vendored
View File

@ -5,3 +5,7 @@ __pycache__/
build/ build/
dist/ dist/
main.spec main.spec
.vscode/launch.json
app.log
bookmarkList.json
downloadHistory.json

3
CLIOutput/eng.bat Normal file
View File

@ -0,0 +1,3 @@
for /R %%a in ("*.mp4") do MP4Box -lang eng "%%a"
exit

View File

@ -4,6 +4,7 @@ import os
from backend import gogoanime, CustomMessage, config_check from backend import gogoanime, CustomMessage, config_check
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from colorama import Fore from colorama import Fore
import logging
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}] "
@ -15,8 +16,8 @@ except AttributeError:
def gogodownloader(config): def gogodownloader(config):
CURRENT_DOMAIN = config["CurrentGoGoAnimeDomain"] CURRENT_URL = config["CurrentGoGoAnimeURL"]
os.system("cls") os.system("cls" if os.name == "nt" else "clear")
while True: while True:
print( print(
f""" {Fore.LIGHTBLUE_EX} f""" {Fore.LIGHTBLUE_EX}
@ -39,16 +40,17 @@ def gogodownloader(config):
) )
while True: while True:
name = input(f"{IN}Enter anime name > ").lower() name = input(f"{IN}Enter anime name > ").lower()
logging.info("episode searched for " + name)
if "-" in name: if "-" in name:
title = name.replace("-", " ").title().strip() title = name.replace("-", " ").title().strip()
else: else:
title = name.title().strip() title = name.title().strip()
source = f"https://gogoanime.{CURRENT_DOMAIN}/category/{name}" source = f"https://{CURRENT_URL}/category/{name}"
with requests.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"})
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 break
else: else:
print(f"{ERR}Error 404: Anime not found. Please try again.") print(f"{ERR}Error 404: Anime not found. Please try again.")
@ -70,6 +72,7 @@ def gogodownloader(config):
break break
else: else:
print(f"{ERR}Invalid input. Please try again.") 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}Title: {Fore.LIGHTCYAN_EX}{title}")
print(f"{OK}Episode/s: {Fore.LIGHTCYAN_EX}{all_episodes}") print(f"{OK}Episode/s: {Fore.LIGHTCYAN_EX}{all_episodes}")
print(f"{OK}Quality: {Fore.LIGHTCYAN_EX}{episode_quality}") print(f"{OK}Quality: {Fore.LIGHTCYAN_EX}{episode_quality}")
@ -107,9 +110,9 @@ def gogodownloader(config):
CustomMessage( CustomMessage(
f"{ERR}episode_start or episode_end cannot be more than {all_episodes}" f"{ERR}episode_start or episode_end cannot be more than {all_episodes}"
).print_error() ).print_error()
elif episode_end <= episode_start: elif episode_end < episode_start:
CustomMessage( CustomMessage(
f"{ERR}episode_end cannot be less than or equal to episode_start" f"{ERR}episode_end cannot be less than episode_start"
).print_error() ).print_error()
else: else:
break break
@ -135,8 +138,8 @@ def gogodownloader(config):
episode_end, episode_end,
title, title,
) )
gogo.user_logged_in_check()
source = f"https://gogoanime.{CURRENT_DOMAIN}/{name}" source = f"https://{CURRENT_URL}/{name}"
with requests.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
@ -163,7 +166,7 @@ def gogodownloader(config):
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" if os.name == "nt" else "clear")
else: else:
break break

128
GoGoDownloaderCLI.py Normal file
View File

@ -0,0 +1,128 @@
import json
import io
import os
import re
from backend import *
def renameFile(filename: str):
"""_summary_
Args:
filename (str): _description_
Returns:
_type_: _description_
"""
newFileName = "".join(re.split("\(|\)|\[|\]", filename)[::2])
try:
os.rename(filename, newFileName)
return True
except OSError as err:
return err
def loadDownloadHistory():
"""Loads the downloadHistory.json, creates it if it doesn't exist
Returns:
object: download history list
"""
if os.path.isfile("./downloadHistory.json") and os.access(
"./downloadHistory.json", os.R_OK
):
return json.load(open("./downloadHistory.json"))
else:
with io.open(os.path.join("./", "downloadHistory.json"), "w") as db_file:
db_file.write(json.dumps([]))
return json.load(open("./downloadHistory.json"))
def writeShowToDownloadHistory(showName: str, downloadHistory: list):
"""Writes the showName and latestEpisode to the downloadHistory.json file
Args:
showName (str): _description_
downloadHistory (list): _description_
Returns:
_type_: _description_
"""
downloadHistory.append(showName)
with io.open(os.path.join("./", "downloadHistory.json"), "w") as db_file:
db_file.write(json.dumps(downloadHistory))
return json.load(open("./downloadHistory.json"))
def readDownloadHistory(fileNameObject: object, downloadHistory: list):
"""Reads the downloadHistory.json and checks if the fileName is present
Args:
fileNameObject (str): _description_
downloadHistory (list): _description_
Returns:
_type_: _description_
"""
dhFileName = (
fileNameObject["showName"] + " - " + str(fileNameObject["latestEpisode"])
)
if dhFileName not in downloadHistory:
writeShowToDownloadHistory(dhFileName, downloadHistory)
return False
else:
return True
def main():
dh = loadDownloadHistory()
config = config_check()
downloader = gogoanime(
config,
1,
config["CLIQuality"],
"a",
1,
1,
1,
config["CLIDownloadLocation"],
)
list = downloader.get_show_from_bookmark()
dl_links = {}
for ep in list:
if readDownloadHistory(ep, dh):
showName = ep["showName"] + " - " + str(ep["latestEpisode"])
print(f"{IN}{showName} already downloaded")
else:
print(
f"{IN}Scraping DL for "
+ ep["showName"]
+ " Ep "
+ str(ep["latestEpisode"])
)
dl_links[downloader.get_download_link(ep["downloadURL"])] = (
ep["showName"],
ep["latestEpisode"],
)
result = downloader.file_downloader(dl_links)
if config["CleanUpFileName"]:
for file in result.data:
renameFile(file)
if len(result.errors) > 0:
while len(result.errors) > 0:
print(f"{ERR}{len(result.errors)} links failed retrying.")
print(f"{IN}Re-Scraping Links")
dl_links.clear()
for ep in list:
dl_links[downloader.get_download_link(ep["downloadURL"])] = (
ep["showName"],
ep["latestEpisode"],
)
result = downloader.file_downloader(dl_links, overwrite_downloads=0)
if config["CleanUpFileName"]:
for file in result.data:
renameFile(file)
if __name__ == "__main__":
main()

40
GoGoDownloaderCLI.spec Normal file
View File

@ -0,0 +1,40 @@
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['GoGoDownloaderCLI.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='GoGoDownloaderCLI',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None )

View File

@ -18,7 +18,7 @@
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 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 Downloader** gets its content from [gogoanime](http://gogoanime3.net). If you get a **404** error, please look up the correct anime name on [gogoanime](http://gogoanime3.net). 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. 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.
@ -57,16 +57,20 @@ If you want to run from source, or are using Linux/Mac you can run directly from
## Usage ## Usage
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. The anime name is separated by "-". You can either type it manually, or go to [gogoanime.gg](https://gogoanime3.gg/) and search for the anime you want to download and copy the name from the URL.
### Examples ### Examples
##### One word title ##### One word title
- https://gogoanime.film/category/bakemonogatari >> bakemonogatari - https://gogoanime3.gg/category/bakemonogatari >> bakemonogatari
- https://gogoanime.film/category/steinsgate >> steinsgate - https://gogoanime3.gg/category/steinsgate >> steinsgate
##### Multiple word title ##### Multiple word title
- https://gogoanime.film/category/shadows-house >> shadows-house - https://gogoanime3.gg/category/shadows-house >> shadows-house
- https://gogoanime.film/category/kono-subarashii-sekai-ni-shukufuku-wo- >> kono-subarashii-sekai-ni-shukufuku-wo- - https://gogoanime3.gg/category/kono-subarashii-sekai-ni-shukufuku-wo- >> kono-subarashii-sekai-ni-shukufuku-wo-
# GoGoDownloader CLI
I have now also created the GoGoDownloader CLI, this tool can be used to run on a scheduled basis, it will login and get the latest episodes from your GoGoAnime bookmarks, and download the latest episode if it has not been downloaded yet.

View File

@ -7,6 +7,14 @@ from dataclasses import dataclass
from colorama import Fore from colorama import Fore
from parfive import Downloader from parfive import Downloader
from threading import Semaphore 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}] " OK = f"{Fore.RESET}[{Fore.GREEN}+{Fore.RESET}] "
@ -25,9 +33,11 @@ def config_check():
[object]: Config object [object]: Config object
""" """
if os.path.exists("./config.json"): if os.path.exists("./config.json"):
logging.info("Config.json loaded")
with open("./config.json", "r") as f: with open("./config.json", "r") as f:
CONFIG = json.load(f) CONFIG = json.load(f)
if not "GoGoAnime_Username" in CONFIG or len(CONFIG["GoGoAnime_Username"]) == 0: 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") print("GoGoAnime_Username not set in config.json")
exit(0) exit(0)
else: else:
@ -35,11 +45,18 @@ def config_check():
not "GoGoAnime_Password" in CONFIG not "GoGoAnime_Password" in CONFIG
or len(CONFIG["GoGoAnime_Password"]) == 0 or len(CONFIG["GoGoAnime_Password"]) == 0
): ):
logging.error("GoGoAnime_Password not set in config.json")
print("GoGoAnime_Password not set in config.json") print("GoGoAnime_Password not set in config.json")
exit(0) exit(0)
else: else:
logging.info(
"Config loaded and "
+ CONFIG["GoGoAnime_Username"]
+ " username found"
)
return CONFIG return CONFIG
else: else:
logging.error("config.json not found")
print("config.json file not found") print("config.json file not found")
exit(0) exit(0)
@ -77,18 +94,18 @@ class gogoanime:
def get_gogoanime_auth_cookie(self): def get_gogoanime_auth_cookie(self):
session = requests.session() session = requests.session()
page = session.get( page = session.get(
f"https://gogoanime.{self.config['CurrentGoGoAnimeDomain']}/login.html" f"https://{self.config['CurrentGoGoAnimeURL']}/login.html"
) )
soup = BeautifulSoup(page.content, "html.parser") soup = BeautifulSoup(page.content, "html.parser")
meta_path = soup.select('meta[name="csrf-token"]') meta_path = soup.select('meta[name="csrf-token"]')
csrf_token = meta_path[0].attrs["content"] csrf_token = meta_path[0].attrs["content"]
url = f"https://gogoanime.{self.config['CurrentGoGoAnimeDomain']}/login.html" url = f"https://{self.config['CurrentGoGoAnimeURL']}/login.html"
payload = f"email={self.config['GoGoAnime_Username']}&password={self.config['GoGoAnime_Password']}&_csrf={csrf_token}" payload = f"email={self.config['GoGoAnime_Username']}&password={self.config['GoGoAnime_Password']}&_csrf={csrf_token}"
headers = { 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", "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", "authority": "gogo-cdn.com",
"referer": f"https://gogoanime.{self.config['CurrentGoGoAnimeDomain']}/", "referer": f"https://{self.config['CurrentGoGoAnimeURL']}/",
"content-type": "application/x-www-form-urlencoded", "content-type": "application/x-www-form-urlencoded",
} }
session.headers = headers session.headers = headers
@ -100,16 +117,30 @@ class gogoanime:
else: else:
print("ldldl") print("ldldl")
def user_logged_in_check(
self,
):
page = requests.get(
f"https://{self.config['CurrentGoGoAnimeURL']}/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): def get_links(self, source=None):
if source is not None: if source is not None:
source_ep = f"https://gogoanime.{self.config['CurrentGoGoAnimeDomain']}/{self.name}-episode-" source_ep = f"https://{self.config['CurrentGoGoAnimeURL']}/{self.name}-episode-"
episode_links = [ episode_links = [
f"{source_ep}{i}" f"{source_ep}{i}"
for i in range(self.episode_start, self.episode_end + 1) for i in range(self.episode_start, self.episode_end + 1)
] ]
episode_links.insert(0, source) episode_links.insert(0, source)
else: else:
source_ep = f"https://gogoanime.{self.config['CurrentGoGoAnimeDomain']}/{self.name}-episode-" source_ep = f"https://{self.config['CurrentGoGoAnimeURL']}/{self.name}-episode-"
episode_links = [ episode_links = [
f"{source_ep}{i}" f"{source_ep}{i}"
for i in range(self.episode_start, self.episode_end + 1) for i in range(self.episode_start, self.episode_end + 1)
@ -166,22 +197,60 @@ class gogoanime:
("authority", "gogo-cdn.com"), ("authority", "gogo-cdn.com"),
( (
"referer", "referer",
f"https://gogoanime.{self.config['CurrentGoGoAnimeDomain']}/", f"https://{self.config['CurrentGoGoAnimeURL']}/",
), ),
] ]
), ),
) )
for link in file_list: for link in file_list:
if link is not None: if link is not None:
dl.enqueue_file( try:
link, dl.enqueue_file(
path=f"./{self.title}", link,
) path=f"./{self.title}",
)
except:
pass
files = dl.download() files = dl.download()
return files return files
def get_show_from_bookmark(self):
print(f"{IN}Loading shows from bookmarks")
bookmarkList = []
a = dict(auth=gogoanime.get_gogoanime_auth_cookie(self))
resp = requests.get(
f"https://{self.config['CurrentGoGoAnimeURL']}/user/bookmark",
cookies=a,
)
soup = BeautifulSoup(resp.text, "html.parser")
table = soup.find("div", attrs={"class": "article_bookmark"})
splitTableLines = table.text.split("Remove")
for rows in splitTableLines:
fullRow = " ".join(rows.split())
if "Anime name" in fullRow:
fullRow = fullRow.replace("Anime name Latest", "")
splitRow = fullRow.split("Latest")
elif fullRow == "Status":
break
else:
fullRow = fullRow.replace("Status ", "")
splitRow = fullRow.split("Latest")
animeName = splitRow[0].strip().encode("ascii", "ignore").decode()
animeName = re.sub("[^A-Za-z0-9 ]+", "", animeName)
animeDownloadName = animeName.replace(" ", "-").lower()
episodeNum = splitRow[-1].split()[-1]
bookmarkList.append(
{
"showName": animeName,
"latestEpisode": float(episodeNum),
"downloadURL": f"https://{self.config['CurrentGoGoAnimeURL']}/{animeDownloadName}-episode-{str(episodeNum)}",
}
)
with open("bookmarkList.json", "w") as f:
json.dump(bookmarkList, f)
return bookmarkList
@dataclass(init=True) @dataclass(init=True)
class CustomMessage(Exception): class CustomMessage(Exception):

View File

@ -2,6 +2,9 @@
"GoGoAnime_Username":"", "GoGoAnime_Username":"",
"GoGoAnime_Password":"", "GoGoAnime_Password":"",
"MaxConcurrentDownloads": 4, "MaxConcurrentDownloads": 4,
"CurrentGoGoAnimeDomain": "film", "CurrentGoGoAnimeURL": "gogoanime3.net",
"OverwriteDownloads": 0 "OverwriteDownloads": 0,
} "CLIQuality":"720",
"CLIDownloadLocation": "CLIOutput",
"CleanUpFileName": false
}

View File

@ -1 +1 @@
3.0.0 3.2.0

1
winRun.bat Normal file
View File

@ -0,0 +1 @@
cd C:\Users\Karl.Hudgell\Documents\GoGoDownloader && venv\Scripts\activate && python GoGoDownloaderCLI.py