2021-12-22 10:10:37 +01:00
|
|
|
import re
|
2022-05-09 15:42:13 +02:00
|
|
|
from time import sleep
|
|
|
|
import requests
|
2022-05-04 19:17:12 +02:00
|
|
|
import mangadlp.utils as utils
|
|
|
|
|
|
|
|
|
|
|
|
class Mangadex:
|
|
|
|
|
|
|
|
# api information
|
|
|
|
api_base_url = "https://api.mangadex.org"
|
|
|
|
img_base_url = "https://uploads.mangadex.org"
|
|
|
|
# get infos to initiate class
|
|
|
|
|
2022-05-09 15:42:13 +02:00
|
|
|
def __init__(self, manga_url_uuid, manga_lang, forcevol, verbose):
|
2022-05-04 19:17:12 +02:00
|
|
|
# static info
|
2022-05-09 15:42:13 +02:00
|
|
|
self.manga_url_uuid = manga_url_uuid
|
2022-05-04 19:17:12 +02:00
|
|
|
self.manga_lang = manga_lang
|
2022-05-09 15:42:13 +02:00
|
|
|
self.forcevol = forcevol
|
|
|
|
self.verbose = verbose
|
|
|
|
|
|
|
|
# api stuff
|
|
|
|
self.api_content_ratings = "contentRating[]=safe&contentRating[]=suggestive&contentRating[]=erotica&contentRating[]=pornographic"
|
|
|
|
self.api_language = f"translatedLanguage[]={self.manga_lang}"
|
|
|
|
self.api_additions = f"{self.api_language}&{self.api_content_ratings}"
|
2022-05-04 19:17:12 +02:00
|
|
|
|
|
|
|
# infos from functions
|
|
|
|
self.manga_uuid = self.get_manga_uuid()
|
2022-05-09 15:42:13 +02:00
|
|
|
self.manga_data = self.get_manga_data()
|
2022-05-04 19:17:12 +02:00
|
|
|
self.manga_title = self.get_manga_title()
|
|
|
|
self.manga_chapter_data = self.get_chapter_data()
|
|
|
|
|
2022-05-09 15:42:13 +02:00
|
|
|
# make initial request
|
|
|
|
def get_manga_data(self):
|
|
|
|
if self.verbose:
|
|
|
|
print(f"INFO: Getting manga data for: {self.manga_uuid}")
|
|
|
|
counter = 1
|
|
|
|
while counter < 3:
|
|
|
|
try:
|
|
|
|
manga_data = requests.get(
|
|
|
|
f"{self.api_base_url}/manga/{self.manga_uuid}"
|
|
|
|
)
|
|
|
|
except:
|
|
|
|
if counter >= 3:
|
|
|
|
print("ERR: Maybe the MangaDex API is down?")
|
|
|
|
exit(1)
|
|
|
|
else:
|
|
|
|
print("ERR: Mangadex API not reachable. Retrying")
|
|
|
|
sleep(2)
|
|
|
|
counter += 1
|
|
|
|
else:
|
|
|
|
break
|
|
|
|
# check if manga exists
|
|
|
|
if manga_data.json()["result"] != "ok":
|
|
|
|
print("ERR: Manga not found")
|
|
|
|
exit(1)
|
|
|
|
|
|
|
|
return manga_data
|
|
|
|
|
2022-05-04 19:17:12 +02:00
|
|
|
# get the uuid for the manga
|
|
|
|
def get_manga_uuid(self):
|
|
|
|
# isolate id from url
|
|
|
|
uuid_regex = re.compile(
|
|
|
|
"[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}"
|
|
|
|
)
|
|
|
|
# check for new mangadex id
|
2022-05-09 15:42:13 +02:00
|
|
|
if not uuid_regex.search(self.manga_url_uuid):
|
|
|
|
print("ERR: No valid UUID found")
|
2022-05-04 19:17:12 +02:00
|
|
|
exit(1)
|
2022-05-09 15:42:13 +02:00
|
|
|
manga_uuid = uuid_regex.search(self.manga_url_uuid)[0]
|
2022-05-04 19:17:12 +02:00
|
|
|
return manga_uuid
|
|
|
|
|
|
|
|
# get the title of the manga (and fix the filename)
|
|
|
|
def get_manga_title(self):
|
2022-05-09 15:42:13 +02:00
|
|
|
if self.verbose:
|
|
|
|
print(f"INFO: Getting manga title for: {self.manga_uuid}")
|
|
|
|
manga_data = self.manga_data.json()
|
2022-05-04 19:17:12 +02:00
|
|
|
try:
|
2022-05-09 15:42:13 +02:00
|
|
|
title = manga_data["data"]["attributes"]["title"][self.manga_lang]
|
2022-05-04 19:17:12 +02:00
|
|
|
except:
|
|
|
|
# search in alt titles
|
|
|
|
try:
|
|
|
|
alt_titles = {}
|
2022-05-09 15:42:13 +02:00
|
|
|
for title in manga_data["data"]["attributes"]["altTitles"]:
|
2022-05-04 19:17:12 +02:00
|
|
|
alt_titles.update(title)
|
|
|
|
title = alt_titles[self.manga_lang]
|
|
|
|
except: # no title on requested language found
|
2022-05-09 15:42:13 +02:00
|
|
|
print("ERR: Chapter in requested language not found.")
|
2022-05-04 19:17:12 +02:00
|
|
|
exit(1)
|
|
|
|
return utils.fix_name(title)
|
|
|
|
|
2022-05-09 15:42:13 +02:00
|
|
|
# check if chapters are available in requested language
|
|
|
|
def check_chapter_lang(self):
|
|
|
|
if self.verbose:
|
|
|
|
print(
|
|
|
|
f"INFO: Checking for chapters in specified language for: {self.manga_uuid}"
|
|
|
|
)
|
|
|
|
r = requests.get(
|
|
|
|
f"{self.api_base_url}/manga/{self.manga_uuid}/feed?limit=0&{self.api_additions}"
|
2022-05-04 19:17:12 +02:00
|
|
|
)
|
|
|
|
try:
|
2022-05-09 15:42:13 +02:00
|
|
|
total_chapters = r.json()["total"]
|
2022-05-04 19:17:12 +02:00
|
|
|
except:
|
|
|
|
print(
|
2022-05-09 15:42:13 +02:00
|
|
|
"ERR: Error retrieving the chapters list. Did you specify a valid language code?"
|
2022-05-04 19:17:12 +02:00
|
|
|
)
|
2022-05-09 15:42:13 +02:00
|
|
|
return 0
|
|
|
|
else:
|
|
|
|
if total_chapters == 0:
|
|
|
|
print("ERR: No chapters available to download!")
|
|
|
|
return 0
|
|
|
|
|
|
|
|
return total_chapters
|
|
|
|
|
|
|
|
# get chapter data like name, uuid etc
|
|
|
|
def get_chapter_data(self):
|
|
|
|
if self.verbose:
|
|
|
|
print(f"INFO: Getting chapter data for: {self.manga_uuid}")
|
|
|
|
api_sorting = "order[chapter]=asc&order[volume]=asc"
|
|
|
|
# check for chapters in specified lang
|
|
|
|
total_chapters = self.check_chapter_lang()
|
|
|
|
if total_chapters == 0:
|
2022-05-04 19:17:12 +02:00
|
|
|
exit(1)
|
2022-05-09 15:42:13 +02:00
|
|
|
|
|
|
|
chapter_data = {}
|
|
|
|
last_chapter = ["", ""]
|
2022-05-04 19:17:12 +02:00
|
|
|
offset = 0
|
2022-05-09 15:42:13 +02:00
|
|
|
while offset < total_chapters: # if more than 500 chapters
|
|
|
|
r = requests.get(
|
|
|
|
f"{self.api_base_url}/manga/{self.manga_uuid}/feed?{api_sorting}&limit=500&offset={offset}&{self.api_additions}"
|
2022-05-04 19:17:12 +02:00
|
|
|
)
|
2022-05-09 15:42:13 +02:00
|
|
|
for chapter in r.json()["data"]:
|
2022-05-04 19:17:12 +02:00
|
|
|
# chapter infos from feed
|
2022-05-09 15:42:13 +02:00
|
|
|
chapter_num = chapter["attributes"]["chapter"]
|
|
|
|
chapter_vol = chapter["attributes"]["volume"]
|
|
|
|
chapter_uuid = chapter["id"]
|
|
|
|
chapter_name = chapter["attributes"]["title"]
|
|
|
|
chapter_external = chapter["attributes"]["externalUrl"]
|
|
|
|
|
|
|
|
# check for chapter title and fix it
|
|
|
|
if chapter_name is None:
|
|
|
|
chapter_name = "No Title"
|
|
|
|
else:
|
|
|
|
chapter_name = utils.fix_name(chapter_name)
|
2022-05-04 19:17:12 +02:00
|
|
|
# check if the chapter is external (can't download them)
|
2022-05-09 15:42:13 +02:00
|
|
|
if chapter_external is not None:
|
|
|
|
continue
|
2022-05-04 19:17:12 +02:00
|
|
|
# name chapter "oneshot" if there is no chapter number
|
2022-05-09 15:42:13 +02:00
|
|
|
if chapter_num is None:
|
|
|
|
chapter_num = "Oneshot"
|
|
|
|
|
|
|
|
# check if its duplicate from the last entry
|
|
|
|
if last_chapter[0] == chapter_vol and last_chapter[1] == chapter_num:
|
|
|
|
continue
|
|
|
|
|
|
|
|
# export chapter data as a dict
|
|
|
|
chapter_index = (
|
|
|
|
chapter_num if not self.forcevol else f"{chapter_vol}:{chapter_num}"
|
|
|
|
)
|
|
|
|
chapter_data[chapter_index] = [
|
|
|
|
chapter_uuid,
|
|
|
|
chapter_vol,
|
|
|
|
chapter_num,
|
|
|
|
chapter_name,
|
|
|
|
]
|
|
|
|
# add last chapter to duplicate check
|
|
|
|
last_chapter = [chapter_vol, chapter_num]
|
|
|
|
|
|
|
|
# increase offset for mangas with more than 500 chapters
|
2022-05-04 19:17:12 +02:00
|
|
|
offset += 500
|
|
|
|
|
2022-05-09 15:42:13 +02:00
|
|
|
return chapter_data
|
2022-05-04 19:17:12 +02:00
|
|
|
|
|
|
|
# get images for the chapter (mangadex@home)
|
2022-05-09 21:24:25 +02:00
|
|
|
def get_chapter_images(self, chapter, wait_time):
|
2022-05-09 15:42:13 +02:00
|
|
|
if self.verbose:
|
|
|
|
print(f"INFO: Getting chapter images for: {self.manga_uuid}")
|
2022-05-04 19:17:12 +02:00
|
|
|
athome_url = f"{self.api_base_url}/at-home/server"
|
2022-05-09 15:42:13 +02:00
|
|
|
chapter_uuid = self.manga_chapter_data[chapter][0]
|
|
|
|
|
2022-05-04 19:17:12 +02:00
|
|
|
r = requests.get(f"{athome_url}/{chapter_uuid}")
|
2022-05-09 15:42:13 +02:00
|
|
|
api_data = r.json()
|
|
|
|
if api_data["result"] != "ok":
|
|
|
|
print(f"ERR: No chapter with the id {chapter_uuid} found")
|
|
|
|
elif api_data["chapter"]["data"] is None:
|
|
|
|
print(f"ERR: No chapter data found for chapter {chapter_uuid}")
|
2022-05-04 19:17:12 +02:00
|
|
|
|
2022-05-09 15:42:13 +02:00
|
|
|
chapter_hash = api_data["chapter"]["hash"]
|
|
|
|
chapter_img_data = api_data["chapter"]["data"]
|
2021-12-22 10:10:37 +01:00
|
|
|
|
2022-05-09 15:42:13 +02:00
|
|
|
# get list of image urls
|
|
|
|
image_urls = []
|
|
|
|
for image in chapter_img_data:
|
|
|
|
image_urls.append(f"{self.img_base_url}/data/{chapter_hash}/{image}")
|
2022-05-04 19:17:12 +02:00
|
|
|
|
2022-05-09 21:24:25 +02:00
|
|
|
sleep(wait_time)
|
2022-05-09 15:42:13 +02:00
|
|
|
return image_urls
|
2022-05-04 19:17:12 +02:00
|
|
|
|
|
|
|
# create list of chapters
|
2022-05-09 15:42:13 +02:00
|
|
|
def create_chapter_list(self):
|
|
|
|
if self.verbose:
|
|
|
|
print(f"INFO: Creating chapter list for: {self.manga_uuid}")
|
2022-05-04 19:17:12 +02:00
|
|
|
chapter_list = []
|
2022-05-09 15:42:13 +02:00
|
|
|
for chapter in self.manga_chapter_data.items():
|
|
|
|
chapter_info = self.get_chapter_infos(chapter[0])
|
|
|
|
chapter_number = chapter_info["chapter"]
|
|
|
|
volume_number = chapter_info["volume"]
|
|
|
|
if self.forcevol:
|
2022-05-04 19:17:12 +02:00
|
|
|
chapter_list.append(f"{volume_number}:{chapter_number}")
|
|
|
|
else:
|
|
|
|
chapter_list.append(chapter_number)
|
|
|
|
|
|
|
|
return chapter_list
|
|
|
|
|
2022-05-09 15:42:13 +02:00
|
|
|
# create filename for chapter
|
|
|
|
def get_filename(self, chapter):
|
|
|
|
if self.verbose:
|
|
|
|
print(f"INFO: Creating filename for: {self.manga_uuid}")
|
|
|
|
chapter_info = self.get_chapter_infos(chapter)
|
|
|
|
chapter_name = chapter_info["name"]
|
|
|
|
chapter_num = chapter_info["chapter"]
|
|
|
|
volume_number = chapter_info["volume"]
|
|
|
|
|
|
|
|
return utils.get_filename(
|
|
|
|
chapter_name, volume_number, chapter_num, self.forcevol
|
|
|
|
)
|
2022-05-04 19:17:12 +02:00
|
|
|
|
2022-05-09 15:42:13 +02:00
|
|
|
# create easy to access chapter infos
|
|
|
|
def get_chapter_infos(self, chapter):
|
|
|
|
if self.verbose:
|
|
|
|
print(
|
|
|
|
f"INFO: Getting chapter infos for: {self.manga_chapter_data[chapter][0]}"
|
|
|
|
)
|
|
|
|
chapter_uuid = self.manga_chapter_data[chapter][0]
|
|
|
|
chapter_vol = self.manga_chapter_data[chapter][1]
|
|
|
|
chapter_num = self.manga_chapter_data[chapter][2]
|
|
|
|
chapter_name = self.manga_chapter_data[chapter][3]
|
|
|
|
|
|
|
|
return {
|
|
|
|
"uuid": chapter_uuid,
|
|
|
|
"volume": chapter_vol,
|
|
|
|
"chapter": chapter_num,
|
|
|
|
"name": chapter_name,
|
|
|
|
}
|