Merge pull request 'update to work again' (#4) from dev into master
All checks were successful
continuous-integration/drone/push Build is passing

Reviewed-on: #4
This commit is contained in:
Ivan Schaller 2022-05-09 15:43:11 +02:00
commit e62de962a7
8 changed files with 638 additions and 473 deletions

2
.gitignore vendored
View file

@ -9,3 +9,5 @@ downloads/
__pycache__/ __pycache__/
.pytest_cache/ .pytest_cache/
chaps.txt chaps.txt
venv/

12
CHANGELOG.md Normal file
View file

@ -0,0 +1,12 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
- Add support for new mangadex api
- Rewrite api section
- Add support for more sites

View file

@ -1,8 +1,10 @@
import mangadlp.main as MangaDLP import mangadlp.main as mangadlp
import argparse import argparse
def main(args): def main(args):
MangaDLP.main(args.url, mangadlp.main(
args.url_uuid,
args.lang, args.lang,
args.chapters, args.chapters,
args.read, args.read,
@ -11,76 +13,93 @@ def main(args):
args.forcevol, args.forcevol,
args.path, args.path,
args.wait, args.wait,
args.verbose) args.verbose,
)
if __name__ == '__main__': if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Script to download mangas from various sites') parser = argparse.ArgumentParser(
parser.add_argument('-u', '--url', description="Script to download mangas from various sites"
dest='url',
required=False,
help='URL of the manga',
action='store',
) )
parser.add_argument('-c', '--chapters', parser.add_argument(
dest='chapters', "-u",
"--url",
"--uuid",
dest="url_uuid",
required=False, required=False,
help='Chapters to download', help="URL or UUID of the manga",
action='store', action="store",
) )
parser.add_argument('-p', '--path', parser.add_argument(
dest='path', "-c",
"--chapters",
dest="chapters",
required=False,
help="Chapters to download",
action="store",
)
parser.add_argument(
"-p",
"--path",
dest="path",
required=False, required=False,
help='Download path. Defaults to "<script_dir>/downloads"', help='Download path. Defaults to "<script_dir>/downloads"',
action='store', action="store",
default='downloads', default="downloads",
) )
parser.add_argument('-l', '--language', parser.add_argument(
dest='lang', "-l",
"--language",
dest="lang",
required=False, required=False,
help='Manga language. Defaults to "en" --> english', help='Manga language. Defaults to "en" --> english',
action='store', action="store",
default='en', default="en",
) )
parser.add_argument('--read', parser.add_argument(
dest='read', "--read",
dest="read",
required=False, required=False,
help='Path of file with manga links to download. One per line', help="Path of file with manga links to download. One per line",
action='store', action="store",
) )
parser.add_argument('--list', parser.add_argument(
dest='list', "--list",
dest="list",
required=False, required=False,
help='List all available chapters. Defaults to false', help="List all available chapters. Defaults to false",
action='store_true', action="store_true",
) )
parser.add_argument('--nocbz', parser.add_argument(
dest='nocbz', "--nocbz",
dest="nocbz",
required=False, required=False,
help='Dont pack it to a cbz archive. Defaults to false', help="Dont pack it to a cbz archive. Defaults to false",
action='store_true', action="store_true",
) )
parser.add_argument('--forcevol', parser.add_argument(
dest='forcevol', "--forcevol",
dest="forcevol",
required=False, required=False,
help='Force naming of volumes. For mangas where chapters reset each volume', help="Force naming of volumes. For mangas where chapters reset each volume",
action='store_true', action="store_true",
) )
parser.add_argument('--wait', parser.add_argument(
dest='wait', "--wait",
dest="wait",
required=False, required=False,
type=float, type=float,
help='Time to wait for each picture to download in seconds(float). Defaults 0.5', help="Time to wait for each picture to download in seconds(float). Defaults 0.5",
) )
parser.add_argument('--verbose', parser.add_argument(
dest='verbose', "--verbose",
dest="verbose",
required=False, required=False,
help='Verbose logging. Defaults to false', help="Verbose logging. Defaults to false",
action='store_true', action="store_true",
) )
#parser.print_help() # parser.print_help()
args = parser.parse_args() args = parser.parse_args()
main(args) main(args)

View file

@ -1,146 +1,242 @@
import requests
import re import re
import mangadlp.utils as MUtils from time import sleep
import requests
import mangadlp.utils as utils
class Mangadex(): class Mangadex:
# api information # api information
api_base_url = 'https://api.mangadex.org' api_base_url = "https://api.mangadex.org"
img_base_url = 'https://uploads.mangadex.org' img_base_url = "https://uploads.mangadex.org"
# get infos to initiate class # get infos to initiate class
def __init__(self, manga_url, manga_lang):
self.manga_url = manga_url
self.manga_lang = manga_lang
self.manga_uuid = self.get_manga_uuid()
self.manga_title = self.get_manga_title(self.manga_uuid)
self.manga_chapter_data = self.get_manga_chapters(self.manga_uuid)
def __init__(self, manga_url_uuid, manga_lang, forcevol, verbose):
# static info
self.manga_url_uuid = manga_url_uuid
self.manga_lang = manga_lang
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}"
# infos from functions
self.manga_uuid = self.get_manga_uuid()
self.manga_data = self.get_manga_data()
self.manga_title = self.get_manga_title()
self.manga_chapter_data = self.get_chapter_data()
# 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
# get the uuid for the manga # get the uuid for the manga
def get_manga_uuid(self): def get_manga_uuid(self):
# isolate id from url # 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}') 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 # check for new mangadex id
if uuid_regex.search(self.manga_url): if not uuid_regex.search(self.manga_url_uuid):
manga_uuid = uuid_regex.search(self.manga_url)[0] print("ERR: No valid UUID found")
else:
print('No valid uuid found')
exit(1) exit(1)
# check if the manga exists manga_uuid = uuid_regex.search(self.manga_url_uuid)[0]
try:
req = requests.get(f'{self.api_base_url}/manga/{manga_uuid}')
except:
print('Error. Maybe the MangaDex API is down?')
exit(1)
else:
# check mangadex status
response = req.json()['result']
if not response == 'ok':
print('Manga not found')
exit(1)
return manga_uuid return manga_uuid
# get the title of the manga (and fix the filename) # get the title of the manga (and fix the filename)
def get_manga_title(self, manga_uuid): def get_manga_title(self):
req = requests.get(f'{self.api_base_url}/manga/{manga_uuid}') if self.verbose:
api_resp = req.json() print(f"INFO: Getting manga title for: {self.manga_uuid}")
manga_data = self.manga_data.json()
try: try:
title = api_resp['data']['attributes']['title'][self.manga_lang] title = manga_data["data"]["attributes"]["title"][self.manga_lang]
except: except:
# search in alt titles # search in alt titles
try: try:
alt_titles = {} alt_titles = {}
for title in api_resp['data']['attributes']['altTitles']: for title in manga_data["data"]["attributes"]["altTitles"]:
alt_titles.update(title) alt_titles.update(title)
title = alt_titles[self.manga_lang] title = alt_titles[self.manga_lang]
except: # no title on requested language found except: # no title on requested language found
print('Chapter in requested language not found.') print("ERR: Chapter in requested language not found.")
exit(1) exit(1)
return utils.fix_name(title)
return MUtils.fix_name(title) # check if chapters are available in requested language
def check_chapter_lang(self):
if self.verbose:
# get all chapter data for further parsing print(
def get_manga_chapters(self, manga_uuid): f"INFO: Checking for chapters in specified language for: {self.manga_uuid}"
content_ratings = 'contentRating[]=safe&contentRating[]=suggestive&contentRating[]=erotica&contentRating[]=pornographic' )
chap_data_list = [] r = requests.get(
req = requests.get(f'{self.api_base_url}/manga/{manga_uuid}/feed?limit=0&translatedLanguage[]={self.manga_lang}&{content_ratings}') f"{self.api_base_url}/manga/{self.manga_uuid}/feed?limit=0&{self.api_additions}"
)
try: try:
total = req.json()['total'] total_chapters = r.json()["total"]
except: except:
print('Error retrieving the chapters list. Did you specify a valid language code?') print(
"ERR: Error retrieving the chapters list. Did you specify a valid language code?"
)
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:
exit(1) exit(1)
if total == 0:
print('No chapters available to download!') chapter_data = {}
exit(0) last_chapter = ["", ""]
last_chap = ['', '']
offset = 0 offset = 0
while offset < total: # if more than 500 chapters while offset < total_chapters: # if more than 500 chapters
req = requests.get(f'{self.api_base_url}/manga/{manga_uuid}/feed?order[chapter]=asc&order[volume]=asc&limit=500&translatedLanguage[]={self.manga_lang}&offset={offset}&{content_ratings}') r = requests.get(
for chapter in req.json()['data']: f"{self.api_base_url}/manga/{self.manga_uuid}/feed?{api_sorting}&limit=500&offset={offset}&{self.api_additions}"
chap_num = chapter['attributes']['chapter'] )
chap_vol = chapter['attributes']['volume'] for chapter in r.json()["data"]:
chap_uuid = chapter['id'] # chapter infos from feed
chap_hash = chapter['attributes']['hash'] chapter_num = chapter["attributes"]["chapter"]
chap_data = chapter['attributes']['data'] chapter_vol = chapter["attributes"]["volume"]
chap_name = chapter['attributes']['title'] chapter_uuid = chapter["id"]
if not chap_name == None: chapter_name = chapter["attributes"]["title"]
chap_name = MUtils.fix_name(chap_name) chapter_external = chapter["attributes"]["externalUrl"]
# check if the chapter is external (cant download them)
chap_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)
# check if the chapter is external (can't download them)
if chapter_external is not None:
continue
# name chapter "oneshot" if there is no chapter number # name chapter "oneshot" if there is no chapter number
if chap_external == None and chap_num == None: if chapter_num is None:
# check for duplicates chapter_num = "Oneshot"
if last_chap[0] == chap_vol and last_chap[1] == chap_num:
# check if its duplicate from the last entry
if last_chapter[0] == chapter_vol and last_chapter[1] == chapter_num:
continue continue
chap_data_list.append([chap_vol, 'Oneshot', chap_uuid, chap_hash, chap_name, chap_data])
# else add chapter number # export chapter data as a dict
elif chap_external == None: chapter_index = (
# check for duplicates chapter_num if not self.forcevol else f"{chapter_vol}:{chapter_num}"
if last_chap[0] == chap_vol and last_chap[1] == chap_num: )
continue chapter_data[chapter_index] = [
chap_data_list.append([chap_vol, chap_num, chap_uuid, chap_hash, chap_name, chap_data]) chapter_uuid,
last_chap = [chap_vol, chap_num] 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
offset += 500 offset += 500
return chap_data_list return chapter_data
# get images for the chapter (mangadex@home)
def get_chapter_images(self, chapter):
if self.verbose:
print(f"INFO: Getting chapter images for: {self.manga_uuid}")
athome_url = f"{self.api_base_url}/at-home/server"
chapter_uuid = self.manga_chapter_data[chapter][0]
def get_chapter_index(self, chapter, forcevol): r = requests.get(f"{athome_url}/{chapter_uuid}")
# get index of chapter api_data = r.json()
if forcevol: if api_data["result"] != "ok":
chapter_index = next(c for c in self.manga_chapter_data if f'{c[0]}:{c[1]}' == chapter) print(f"ERR: No chapter with the id {chapter_uuid} found")
else: elif api_data["chapter"]["data"] is None:
chapter_index = next(c for c in self.manga_chapter_data if c[1] == chapter) print(f"ERR: No chapter data found for chapter {chapter_uuid}")
return chapter_index chapter_hash = api_data["chapter"]["hash"]
chapter_img_data = api_data["chapter"]["data"]
# 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}")
return image_urls
# create list of chapters # create list of chapters
def create_chapter_list(self, chapter_data, forcevol): def create_chapter_list(self):
if self.verbose:
print(f"INFO: Creating chapter list for: {self.manga_uuid}")
chapter_list = [] chapter_list = []
for chap in chapter_data: for chapter in self.manga_chapter_data.items():
volume_number = chap[0] chapter_info = self.get_chapter_infos(chapter[0])
chapter_number = chap[1] chapter_number = chapter_info["chapter"]
if forcevol: volume_number = chapter_info["volume"]
chapter_list.append(f'{volume_number}:{chapter_number}') if self.forcevol:
chapter_list.append(f"{volume_number}:{chapter_number}")
else: else:
chapter_list.append(chapter_number) chapter_list.append(chapter_number)
return chapter_list return chapter_list
# 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"]
# get list of image urls return utils.get_filename(
def get_img_urls(self, images, chapter_hash): chapter_name, volume_number, chapter_num, self.forcevol
img_urls = [] )
for img in images:
img_urls.append(f'{self.img_base_url}/data/{chapter_hash}/{img}')
return img_urls
# 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,
}

View file

@ -1,34 +1,33 @@
import shutil import shutil
import requests
from time import sleep
from pathlib import Path from pathlib import Path
from time import sleep
import requests
# download images
def download_chapter(image_urls, chapter_path, md_wait=0.5, md_verbose=False): def download_chapter(image_urls, chapter_path, md_wait=0.5, md_verbose=False):
# download images
img_num = 1 img_num = 1
for img in image_urls: for img in image_urls:
# set image path # set image path
image_path = Path(f'{chapter_path}/{img_num:03d}') image_path = Path(f"{chapter_path}/{img_num:03d}")
try: try:
#print('Try getting ' + img) # print('Try getting ' + img)
req = requests.get(img, stream = True) req = requests.get(img, stream=True)
except: except:
print(f'Request for image {img} failed, retrying') print(f"ERR: Request for image {img} failed, retrying")
sleep(md_wait) sleep(md_wait)
req = requests.get(img, stream = True) req = requests.get(img, stream=True)
if req.status_code == 200: if req.status_code == 200:
req.raw.decode_content = True req.raw.decode_content = True
with image_path.open('wb') as file: with image_path.open("wb") as file:
shutil.copyfileobj(req.raw, file) shutil.copyfileobj(req.raw, file)
# verbose logging # verbose logging
if md_verbose: if md_verbose:
print(f' Downloaded image {img_num}') print(f"INFO: Downloaded image {img_num}")
img_num += 1 img_num += 1
sleep(0.5) sleep(0.5)
else: else:
print('Image {img} could not be downloaded. Exiting') print(f"ERR: Image {img} could not be downloaded. Exiting")
exit(1) exit(1)

View file

@ -1,26 +1,29 @@
from pathlib import Path
import re import re
from mangadlp import api from pathlib import Path
import mangadlp.utils as MUtils
import mangadlp.downloader as MDownloader import mangadlp.downloader as downloader
import mangadlp.utils as utils
# supported api's # supported api's
from mangadlp.api.mangadex import Mangadex from mangadlp.api.mangadex import Mangadex
def main(manga_url='', def main(
manga_language='en', manga_url_uuid="",
manga_language="en",
manga_chapters=None, manga_chapters=None,
manga_readlist='', manga_readlist="",
manga_list_chapters=False, manga_list_chapters=False,
manga_nocbz=False, manga_nocbz=False,
manga_forcevol=False, manga_forcevol=False,
download_path='downloads', download_path="downloads",
download_wait=0.5, download_wait=0.5,
log_verbose=False): log_verbose=False,
'''Download Mangas from supported sites\n ):
"""Download Mangas from supported sites\n
Args:\n Args:\n
url (str) -- Manga URL to Download. No defaults\n url (str) -- Manga URL or UUID to Download. No defaults\n
lang (str) -- Language to download chapters in. Defaults to "en" -> english\n lang (str) -- Language to download chapters in. Defaults to "en" -> english\n
chapter (str) -- Chapters to download "all" for every chapter available. Defaults to none\n chapter (str) -- Chapters to download "all" for every chapter available. Defaults to none\n
readlist (str) -- List of chapters to read in. One link per line. No defaults\n readlist (str) -- List of chapters to read in. One link per line. No defaults\n
@ -33,48 +36,70 @@ def main(manga_url='',
Returns:\n Returns:\n
nothing\n nothing\n
''' """
# prechecks userinput/options # prechecks userinput/options
if not manga_list_chapters and manga_chapters == None: if not manga_list_chapters and manga_chapters is None:
# no chapters to download were given # no chapters to download were given
print(f'You need to specify one or more chapters to download. To see all chapters use "--list"') print(
f'ERR: You need to specify one or more chapters to download. To see all chapters use "--list"'
)
exit(1) exit(1)
# no url and no readin list given # no url and no readin list given
elif not manga_url and not manga_readlist: elif not manga_url_uuid and not manga_readlist:
print(f'You need to specify a manga url with "-u" or a list with "--read"') print(
f'ERR: You need to specify a manga url/uuid with "-u" or a list with "--read"'
)
exit(1) exit(1)
# url and readin list given # url and readin list given
elif manga_url and manga_readlist: elif manga_url_uuid and manga_readlist:
print(f'You can only use "-u" or "--read". Dont specify both') print(f'ERR: You can only use "-u" or "--read". Dont specify both')
exit(1) exit(1)
# check if readin file was specified # check if readin file was specified
if manga_readlist: if manga_readlist:
# loop trough every chapter in readin file # loop trough every chapter in readin file
for url in readin_list(manga_readlist): for url in readin_list(manga_readlist):
ApiUsed = check_api(url) api_used = check_api(url)
if not ApiUsed: if not api_used:
continue continue
if log_verbose:
print(f'Api used: {ApiUsed}')
# get manga # get manga
get_manga(ApiUsed, url, manga_language, manga_chapters, manga_list_chapters, manga_nocbz, manga_forcevol, download_path, download_wait, log_verbose) get_manga(
api_used,
url,
manga_language,
manga_chapters,
manga_list_chapters,
manga_nocbz,
manga_forcevol,
download_path,
download_wait,
log_verbose,
)
else: else:
# single manga # single manga
ApiUsed = check_api(manga_url) api_used = check_api(manga_url_uuid)
if not ApiUsed: if not api_used:
exit(1) exit(1)
if log_verbose:
print(f'Api used: {ApiUsed}')
# get manga # get manga
get_manga(ApiUsed, manga_url, manga_language, manga_chapters, manga_list_chapters, manga_nocbz, manga_forcevol, download_path, download_wait, log_verbose) get_manga(
api_used,
manga_url_uuid,
manga_language,
manga_chapters,
manga_list_chapters,
manga_nocbz,
manga_forcevol,
download_path,
download_wait,
log_verbose,
)
# read in the list of links from a file # read in the list of links from a file
def readin_list(manga_readlist): def readin_list(manga_readlist):
url_file = Path(manga_readlist) url_file = Path(manga_readlist)
url_list = [] url_list = []
with url_file.open('r') as file: with url_file.open("r") as file:
for line in file: for line in file:
url_list.append(line.rstrip()) url_list.append(line.rstrip())
@ -84,87 +109,93 @@ def readin_list(manga_readlist):
# check the api which needs to be used # check the api which needs to be used
def check_api(manga_url): def check_api(manga_url):
# apis to check # apis to check
api_mangadex = re.compile('mangadex.org') api_mangadex = re.compile("mangadex.org")
api_test = re.compile('test.test') api_mangadex2 = re.compile(
"[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}"
)
api_test = re.compile("test.test")
# check url for match # check url for match
if api_mangadex.search(manga_url): if api_mangadex.search(manga_url) or api_mangadex2.search(manga_url):
return Mangadex return Mangadex
# this is only for testing multiple apis # this is only for testing multiple apis
elif api_test.search(manga_url): elif api_test.search(manga_url):
pass pass
# no supported api found # no supported api found
else: else:
print(f'No supported api in link found\n{manga_url}') print(f"ERR: No supported api in link/uuid found\n{manga_url}")
return False return False
# main function to get the chapters # main function to get the chapters
def get_manga(ApiUsed, manga_url, manga_language, manga_chapters, manga_list_chapters, manga_nocbz, manga_forcevol, download_path, download_wait, log_verbose): def get_manga(
api_used,
manga_url,
manga_language,
manga_chapters,
manga_list_chapters,
manga_nocbz,
manga_forcevol,
download_path,
download_wait,
log_verbose,
):
# show api used
if log_verbose:
print(f"INFO: API used: {api_used}")
# init api # init api
Api = ApiUsed(manga_url, manga_language) Api = api_used(manga_url, manga_language, manga_forcevol, log_verbose)
# get manga title and uuid # get manga title and uuid
manga_uuid = Api.manga_uuid manga_uuid = Api.manga_uuid
manga_title = Api.manga_title manga_title = Api.manga_title
# get chapter data
manga_chapter_data = Api.manga_chapter_data
# crate chapter list # crate chapter list
manga_chapter_list = Api.create_chapter_list(manga_chapter_data, manga_forcevol) manga_chapter_list = Api.create_chapter_list()
# print infos # show infos
print('\n=========================================') print_divider = "========================================="
print(f'Manga Name: {manga_title}') print(f"\n{print_divider}")
print(f'UUID: {manga_uuid}') print(f"INFO: Manga Name: {manga_title}")
print(f'Total chapters: {len(manga_chapter_list)}') print(f"INFO: Manga UUID: {manga_uuid}")
print(f"INFO: Total chapters: {len(manga_chapter_list)}")
# list chapters if manga_list_chapters is true # list chapters if manga_list_chapters is true
if manga_list_chapters: if manga_list_chapters:
print(f'Available Chapters:\n{", ".join(manga_chapter_list)}') print(f'INFO: Available Chapters:\n{", ".join(manga_chapter_list)}')
print('=========================================\n') print(f"{print_divider}\n")
return return
# check chapters to download if it not all # check chapters to download if not all
chapters_to_download = [] if manga_chapters.lower() == "all":
if manga_chapters.lower() == 'all':
chapters_to_download = manga_chapter_list chapters_to_download = manga_chapter_list
else: else:
chapters_to_download = MUtils.get_chapter_list(manga_chapters) chapters_to_download = utils.get_chapter_list(manga_chapters)
# show chapters to download # show chapters to download
print(f'Chapters selected:\n{", ".join(chapters_to_download)}') print(f'INFO: Chapters selected:\n{", ".join(chapters_to_download)}')
print('=========================================\n') print(f"{print_divider}\n")
# create manga folder # create manga folder
manga_path = Path(f'{download_path}/{manga_title}') manga_path = Path(f"{download_path}/{manga_title}")
manga_path.mkdir(parents=True, exist_ok=True) manga_path.mkdir(parents=True, exist_ok=True)
# main download loop # main download loop
for chapter in chapters_to_download: for chapter in chapters_to_download:
# get index of chapter # get chapter infos
chapter_index = Api.get_chapter_index(chapter, manga_forcevol) chapter_infos = Api.get_chapter_infos(chapter)
# default mapping of chapter data # get image urls for chapter
chapter_vol = chapter_index[0] chapter_image_urls = Api.get_chapter_images(chapter)
chapter_num = chapter_index[1]
chapter_uuid = chapter_index[2]
chapter_hash = chapter_index[3]
chapter_name = chapter_index[4]
chapter_img_data = chapter_index[5]
# create image urls from img data
image_urls = Api.get_img_urls(chapter_img_data, chapter_hash)
# get filename for chapter # get filename for chapter
chapter_filename = MUtils.get_filename(chapter_name, chapter_vol, chapter_num, manga_forcevol) chapter_filename = Api.get_filename(chapter)
# set download path for chapter # set download path for chapter
chapter_path = manga_path / chapter_filename chapter_path = manga_path / chapter_filename
# check if chapter already exists. # check if chapter already exists.
# check for folder if option nocbz is given. if nocbz is not given, the folder will be overwritten # check for folder if option nocbz is given. if nocbz is not given, the folder will be overwritten
if MUtils.check_existence(chapter_path, manga_nocbz) and manga_forcevol:
print(f'- Vol {chapter_vol} Chapter {chapter_num} already exists. Skipping\n') if utils.check_existence(chapter_path, manga_nocbz):
continue print(f"INFO: '{chapter_filename}' already exists. Skipping\n")
elif MUtils.check_existence(chapter_path, manga_nocbz):
print(f'- Chapter {chapter_num} already exists. Skipping\n')
continue continue
# create chapter folder (skips it if it already exists) # create chapter folder (skips it if it already exists)
@ -172,48 +203,46 @@ def get_manga(ApiUsed, manga_url, manga_language, manga_chapters, manga_list_cha
# verbose log # verbose log
if log_verbose: if log_verbose:
print(f'Chapter UUID: {chapter_uuid}') print(f"INFO: Chapter UUID: {chapter_infos['uuid']}")
print(f'Filename: {chapter_path}\n' if manga_nocbz else f'Filename: {chapter_path}.cbz\n') print(
print(f'Image URLS: {image_urls}') f"INFO: Filename: '{chapter_filename}'\n"
print(f'DEBUG: Downloading Volume {chapter_vol}') if manga_nocbz
else f"INFO: Filename: '{chapter_filename}.cbz'\n"
)
print(f"INFO: Image URLS: {chapter_image_urls}")
# log # log
if manga_forcevol: print(f"INFO: Downloading: '{chapter_filename}'")
print(f'+ Downloading Volume {chapter_vol} Chapter {chapter_num}')
else:
print(f'+ Downloading Chapter {chapter_num}')
# download images # download images
try: try:
MDownloader.download_chapter(image_urls, chapter_path, download_wait, log_verbose) downloader.download_chapter(
except: chapter_image_urls, chapter_path, download_wait, log_verbose
if manga_forcevol: )
print(f'Cant download volume {chapter_vol} chapter {chapter_num}. Exiting') except KeyboardInterrupt:
else: print("ERR: Stopping")
print(f'Cant download chapter {chapter_num}. Exiting')
exit(1) exit(1)
except:
print(f"ERR: Cant download: '{chapter_filename}'. Exiting")
else: else:
# Done with chapter # Done with chapter
if manga_forcevol: print(f"INFO: Successfully downloaded: '{chapter_filename}'")
print(f'Successfully downloaded volume {chapter_vol} chapter {chapter_num}')
else:
print(f'Successfully downloaded chapter {chapter_num}')
# make cbz of folder # make cbz of folder
if not manga_nocbz: if not manga_nocbz:
print('\n+ Creating .cbz archive') print("INFO: Creating .cbz archive")
try: try:
MUtils.make_archive(chapter_path) utils.make_archive(chapter_path)
except: except:
print('Could not make cbz archive') print("ERR: Could not make cbz archive")
exit(1) exit(1)
# done with chapter # done with chapter
print('Done with chapter') print("INFO: Done with chapter")
print('------------------------------\n') print("-----------------------------------------\n")
# done with manga # done with manga
print('=============================') print(f"{print_divider}")
print(f'Done with manga: {manga_title}') print(f"INFO: Done with manga: {manga_title}")
print('=============================\n') print(f"{print_divider}\n")

View file

@ -3,22 +3,23 @@ import shutil
from zipfile import ZipFile from zipfile import ZipFile
import re import re
# create a cbz archive
def make_archive(chapter_path): def make_archive(chapter_path):
image_folder = Path(chapter_path) image_folder = Path(chapter_path)
zip_path = Path(f'{chapter_path}.zip') zip_path = Path(f"{chapter_path}.zip")
with ZipFile(f'{image_folder}.zip', 'w') as zip_archive: with ZipFile(f"{image_folder}.zip", "w") as zip_archive:
for file in image_folder.iterdir(): for file in image_folder.iterdir():
zip_archive.write(file, file.name) zip_archive.write(file, file.name)
zip_path.rename(zip_path.with_suffix('.cbz')) zip_path.rename(zip_path.with_suffix(".cbz"))
shutil.rmtree(image_folder) shutil.rmtree(image_folder)
# check if the file already exists
def check_existence(chapter_path, manga_nocbz): def check_existence(chapter_path, manga_nocbz):
# check for folder if option nocbz is given. if nocbz is not given, the folder will be overwritten # check for folder if option nocbz is given. if nocbz is not given, the folder will be overwritten
chapter_path = Path(chapter_path) chapter_path = Path(chapter_path)
cbz_path = chapter_path.parent / f'{chapter_path.name}.cbz' cbz_path = chapter_path.parent / f"{chapter_path.name}.cbz"
if manga_nocbz and chapter_path.exists(): if manga_nocbz and chapter_path.exists():
return True return True
# check for cbz archive # check for cbz archive
@ -28,18 +29,19 @@ def check_existence(chapter_path, manga_nocbz):
return False return False
# create a list of chapters
def get_chapter_list(chapters): def get_chapter_list(chapters):
chapter_list = [] chapter_list = []
for chapter in chapters.split(','): for chapter in chapters.split(","):
if '-' in chapter and ':' in chapter: if "-" in chapter and ":" in chapter:
lower = chapter.split('-')[0].split(':') lower = chapter.split("-")[0].split(":")
upper = chapter.split('-')[1].split(':') upper = chapter.split("-")[1].split(":")
for n in range(int(lower[1]), int(upper[1])+1): for n in range(int(lower[1]), int(upper[1]) + 1):
chapter_list.append(str(f'{lower[0]}:{n}')) chapter_list.append(str(f"{lower[0]}:{n}"))
elif '-' in chapter: elif "-" in chapter:
lower = chapter.split('-')[0] lower = chapter.split("-")[0]
upper = chapter.split('-')[1] upper = chapter.split("-")[1]
for n in range(int(lower), int(upper)+1): for n in range(int(lower), int(upper) + 1):
chapter_list.append(str(n)) chapter_list.append(str(n))
else: else:
chapter_list.append(chapter) chapter_list.append(chapter)
@ -47,27 +49,32 @@ def get_chapter_list(chapters):
return chapter_list return chapter_list
def fix_name(name): # remove illegal characters etc
def fix_name(filename):
# remove illegal characters # remove illegal characters
name = re.sub('[/<>:"\\|?*!.]', '', name) filename = re.sub("[\\\/\<\>\:\;'\"\|\?\*\!\@]", ".", filename)
# remove trailing space # remove multiple dots
name = re.sub('[ \t]+$', '', name) filename = re.sub("([\.]{2,})", ".", filename)
# remove dot(s) at the beginning and end of the filename
filename = re.sub("(^[\.]{1,})|([\.]{1,}$)", "", filename)
# remove trailing and beginning spaces
filename = re.sub("([ \t]+$)|(^[ \t]+)", "", filename)
return name return filename
# create name for chapter
def get_filename(chapter_name, chapter_vol, chapter_num, manga_forcevol): def get_filename(chapter_name, chapter_vol, chapter_num, manga_forcevol):
# filename for chapter # filename for chapter
if chapter_name == 'Oneshot' or chapter_num == 'Oneshot': if chapter_name == "Oneshot" or chapter_num == "Oneshot":
chapter_filename = 'Oneshot' chapter_filename = "Oneshot"
elif not chapter_name and manga_forcevol: elif not chapter_name and manga_forcevol:
chapter_filename = f'Vol. {chapter_vol} Ch. {chapter_num}' chapter_filename = f"Vol. {chapter_vol} Ch. {chapter_num}"
elif not chapter_name: elif not chapter_name:
chapter_filename = f'Ch. {chapter_num}' chapter_filename = f"Ch. {chapter_num}"
elif manga_forcevol: elif manga_forcevol:
chapter_filename = f'Vol. {chapter_vol} Ch. {chapter_num} - {chapter_name}' chapter_filename = f"Vol. {chapter_vol} Ch. {chapter_num} - {chapter_name}"
else: else:
chapter_filename = f'Ch. {chapter_num} - {chapter_name}' chapter_filename = f"Ch. {chapter_num} - {chapter_name}"
return chapter_filename return chapter_filename

View file

@ -1,2 +1,3 @@
https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu
https://mangadex.org/title/bd6d0982-0091-4945-ad70-c028ed3c0917/mushoku-tensei-isekai-ittara-honki-dasu https://mangadex.org/title/bd6d0982-0091-4945-ad70-c028ed3c0917/mushoku-tensei-isekai-ittara-honki-dasu
37f5cce0-8070-4ada-96e5-fa24b1bd4ff9