diff --git a/docs/supportedsites.md b/docs/supportedsites.md index 47820537..2a77c006 100644 --- a/docs/supportedsites.md +++ b/docs/supportedsites.md @@ -667,6 +667,12 @@ Consider all listed sites to potentially be NSFW. Chapters, Manga + + MangaFreak + https://ww2.mangafreak.me/ + Chapters, Manga + + MangaPark https://mangapark.net/ diff --git a/gallery_dl/extractor/__init__.py b/gallery_dl/extractor/__init__.py index 4ec16766..5990fa7a 100644 --- a/gallery_dl/extractor/__init__.py +++ b/gallery_dl/extractor/__init__.py @@ -127,6 +127,7 @@ modules = [ "mangadex", "mangafire", "mangafox", + "mangafreak", "mangahere", "manganelo", "mangapark", diff --git a/gallery_dl/extractor/mangafreak.py b/gallery_dl/extractor/mangafreak.py new file mode 100644 index 00000000..4e015563 --- /dev/null +++ b/gallery_dl/extractor/mangafreak.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. + +"""Extractors for https://ww2.mangafreak.me/""" + +from .common import ChapterExtractor, MangaExtractor +from .. import text + +BASE_PATTERN = r"(?:https?://)?(?:ww[\dw]\.)?mangafreak\.me" + + +class MangafreakBase(): + """Base class for mangafreak extractors""" + category = "mangafreak" + root = "https://ww2.mangafreak.me" + + +class MangafreakChapterExtractor(MangafreakBase, ChapterExtractor): + """Extractor for mangafreak manga chapters""" + pattern = BASE_PATTERN + r"(/Read1_([^/?#]+)_((\d+)([a-z])?))" + example = "https://ww2.mangafreak.me/Read1_Onepunch_Man_1" + + def metadata(self, page): + manga = text.extr(page, "Read ", " Chapter ") + title = text.extr(page, 'selected="selected">', "<").partition(": ")[2] + _, manga_slug, chapter_string, chapter, minor = self.groups + + return { + "manga" : text.unescape(manga), + "manga_slug" : manga_slug, + "title" : text.unescape(title) if title else "", + "chapter" : text.parse_int(chapter), + "chapter_minor": "" if minor is None else minor, + "chapter_string": chapter_string, + "lang" : "en", + "language" : "English", + } + + def images(self, page): + base = "https://images.mangafreak.me/mangas/" + return [ + (base + path, None) + for path in text.extract_iter(page, 'src="' + base, '"') + ] + + +class MangafreakMangaExtractor(MangafreakBase, MangaExtractor): + """Extractor for mangafreak manga series""" + chapterclass = MangafreakChapterExtractor + pattern = BASE_PATTERN + r"(/Manga/([^/?#]+))" + example = "https://ww2.mangafreak.me/Manga/Onepunch_Man" + + def chapters(self, page): + table = text.extr(page, "<table>", "</table>") + if not table: + return () + + data = { + "manga" : text.unescape(text.extr(page, "<title>", " Manga")), + "manga_slug": self.groups[1], + "lang" : "en", + "language" : "English", + } + + results = [] + chapter_match = text.re(r"(\d+)(\w*)").match + for row in text.extract_iter(table, "<tr>", "</tr>"): + href = text.extr(row, '<a href="', '"') + if not href: + continue + url = self.root + href + chapter_string = href.rpartition("_")[2] + chapter, minor = chapter_match(chapter_string).groups() + title = text.extr(row, '">', '<').partition(" - ")[2] + results.append((url, { + "chapter" : text.parse_int(chapter), + "chapter_minor" : minor, + "chapter_string": chapter_string, + "title" : text.unescape(title) if title else "", + **data, + })) + return results diff --git a/scripts/supportedsites.py b/scripts/supportedsites.py index a731d171..9a167a45 100755 --- a/scripts/supportedsites.py +++ b/scripts/supportedsites.py @@ -115,6 +115,7 @@ CATEGORY_MAP = { "kabeuchi" : "かべうち", "kaliscan" : "KaliScan", "mangafire" : "MangaFire", + "mangafreak" : "MangaFreak", "mangareader" : "MangaReader", "mangataro" : "MangaTaro", "s3ndpics" : "S3ND", diff --git a/test/results/mangafreak.py b/test/results/mangafreak.py new file mode 100644 index 00000000..0478f8aa --- /dev/null +++ b/test/results/mangafreak.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. + +from gallery_dl.extractor import mangafreak + + +__tests__ = ( +{ + "#url" : "https://ww2.mangafreak.me/Read1_Onepunch_Man_1", + "#class" : mangafreak.MangafreakChapterExtractor, + "#pattern" : r"https://images\.mangafreak\.me/mangas/onepunch_man/onepunch_man_1/onepunch_man_1_\d+\.jpg", + "#count" : 24, + + "chapter" : 1, + "chapter_minor": "", + "chapter_string": "1", + "lang" : "en", + "language" : "English", + "manga" : "Onepunch Man", + "manga_slug" : "Onepunch_Man", +}, + +{ + "#url" : "https://ww2.mangafreak.me/Read1_Onepunch_Man_167e", + "#class" : mangafreak.MangafreakChapterExtractor, + + "chapter" : 167, + "chapter_minor": "e", + "chapter_string": "167e", +}, + +{ + "#url" : "https://ww2.mangafreak.me/Read1_Sss_Rank_Dungeon_De_Knife_Ippon_Tewatasare_Tsuihou_Sareta_Shiro_Madoushi_Yggdrasil_No_Noroi_Ni_Yori_Jakuten_De_Aru_Maryoku_Fusoku_Wo_Kokufuku_Shi_Sekai_Saikyou_E_To_Itaru_23c", + "#class" : mangafreak.MangafreakChapterExtractor, + "#pattern" : r"https://images\.mangafreak\.me/mangas/sss_rank_dungeon_de_knife_ippon_tewatasare_tsuihou_sareta_shiro_madoushi_yggdrasil_no_noroi_ni_yori_jakuten_de_aru_maryoku_fusoku_wo_kokufuku_shi_sekai_saikyou_e_to_itaru/sss_rank_dungeon_de_knife_ippon_tewatasare_tsuihou_sareta_shiro_madoushi_yggdrasil_no_noroi_ni_yori_jakuten_de_aru_maryoku_fusoku_wo_kokufuku_shi_sekai_saikyou_e_to_itaru_23c/sss_rank_dungeon_de_knife_ippon_tewatasare_tsuihou_sareta_shiro_madoushi_yggdrasil_no_noroi_ni_yori_jakuten_de_aru_maryoku_fusoku_wo_kokufuku_shi_sekai_saikyou_e_to_itaru_23c_\d+\.jpg", + "#count" : 11, + + "chapter" : 23, + "chapter_minor" : "c", + "chapter_string": "23c", + "count" : 11, + "page" : range(1, 11), + "filename" : str, + "extension" : "jpg", + "lang" : "en", + "language" : "English", + "manga" : "Sss Rank Dungeon De Knife Ippon Tewatasare Tsuihou Sareta Shiro Madoushi Yggdrasil No Noroi Ni Yori Jakuten De Aru Maryoku Fusoku Wo Kokufuku Shi Sekai Saikyou E To Itaru", + "manga_slug" : "Sss_Rank_Dungeon_De_Knife_Ippon_Tewatasare_Tsuihou_Sareta_Shiro_Madoushi_Yggdrasil_No_Noroi_Ni_Yori_Jakuten_De_Aru_Maryoku_Fusoku_Wo_Kokufuku_Shi_Sekai_Saikyou_E_To_Itaru", + "title" : "", +}, + +{ + "#url" : "https://ww2.mangafreak.me/Read1_Tensei_Shitara_Slime_Datta_Ken_62", + "#class" : mangafreak.MangafreakChapterExtractor, + "#count" : 19, + + "chapter" : 62, + "count" : 19, + "manga" : "Tensei Shitara Slime Datta Ken", + "title" : "To be a Monster or Human", +}, + +{ + "#url" : "https://ww2.mangafreak.me/Manga/Onepunch_Man", + "#class" : mangafreak.MangafreakMangaExtractor, + "#pattern" : mangafreak.MangafreakChapterExtractor.pattern, + "#count" : range(150, 250), + + "lang" : "en", + "language" : "English", + "manga" : "Onepunch-Man", + "manga_slug" : "Onepunch_Man", + "chapter" : int, +}, + +{ + "#url" : "https://ww2.mangafreak.me/Manga/Sss_Rank_Dungeon_De_Knife_Ippon_Tewatasare_Tsuihou_Sareta_Shiro_Madoushi_Yggdrasil_No_Noroi_Ni_Yori_Jakuten_De_Aru_Maryoku_Fusoku_Wo_Kokufuku_Shi_Sekai_Saikyou_E_To_Itaru", + "#class" : mangafreak.MangafreakMangaExtractor, + "#pattern" : mangafreak.MangafreakChapterExtractor.pattern, + "#count" : range(40, 80), + + "chapter" : int, + "chapter_minor" : {"", "a", "b", "c"}, + "chapter_string": str, + "lang" : "en", + "language" : "English", + "manga" : "SSS Rank Dungeon de Knife Ippon Tewatasare Tsuihou Sareta Shiro Madoushi: Yggdrasil no Noroi ni yori Jakuten de aru Maryoku Fusoku wo Kokufuku-shi Sekai Saikyou e to Itaru", + "manga_slug" : "Sss_Rank_Dungeon_De_Knife_Ippon_Tewatasare_Tsuihou_Sareta_Shiro_Madoushi_Yggdrasil_No_Noroi_Ni_Yori_Jakuten_De_Aru_Maryoku_Fusoku_Wo_Kokufuku_Shi_Sekai_Saikyou_E_To_Itaru", + "title" : str, +}, + +)