diff --git a/docs/supportedsites.md b/docs/supportedsites.md index 8abb4478..50e425e9 100644 --- a/docs/supportedsites.md +++ b/docs/supportedsites.md @@ -1141,5 +1141,21 @@ Consider all sites to be NSFW unless otherwise known. Collections, Products + + + lolisafe and chibisafe + + + Bunkr + https://bunkr.is/ + Albums + + + + ZzZz + https://zz.ht/ + Albums + + diff --git a/gallery_dl/extractor/__init__.py b/gallery_dl/extractor/__init__.py index a8ab39b5..4f84d6ab 100644 --- a/gallery_dl/extractor/__init__.py +++ b/gallery_dl/extractor/__init__.py @@ -145,6 +145,7 @@ modules = [ "foolslide", "mastodon", "shopify", + "lolisafe", "imagehosts", "directlink", "recursive", diff --git a/gallery_dl/extractor/cyberdrop.py b/gallery_dl/extractor/cyberdrop.py index dbaa97e3..6d6e1923 100644 --- a/gallery_dl/extractor/cyberdrop.py +++ b/gallery_dl/extractor/cyberdrop.py @@ -6,16 +6,13 @@ """Extractors for https://cyberdrop.me/""" -from .common import Extractor, Message +from . import lolisafe from .. import text -class CyberdropAlbumExtractor(Extractor): +class CyberdropAlbumExtractor(lolisafe.LolisafelbumExtractor): category = "cyberdrop" - subcategory = "album" root = "https://cyberdrop.me" - directory_fmt = ("{category}", "{album_name} ({album_id})") - archive_fmt = "{album_id}_{id}" pattern = r"(?:https?://)?(?:www\.)?cyberdrop\.me/a/([^/?#]+)" test = ( # images @@ -44,11 +41,7 @@ class CyberdropAlbumExtractor(Extractor): }), ) - def __init__(self, match): - Extractor.__init__(self, match) - self.album_id = match.group(1) - - def items(self): + def fetch_album(self, album_id): url = self.root + "/a/" + self.album_id extr = text.extract_from(self.request(url).text) @@ -58,9 +51,9 @@ class CyberdropAlbumExtractor(Extractor): url = extr('id="file" href="', '"') if not url: break - append(text.unescape(url)) + append({"file": text.unescape(url)}) - data = { + return files, { "album_id" : self.album_id, "album_name" : extr("name: '", "'"), "date" : text.parse_timestamp(extr("timestamp: ", ",")), @@ -68,9 +61,3 @@ class CyberdropAlbumExtractor(Extractor): "description": extr("description: `", "`"), "count" : len(files), } - - yield Message.Directory, data - for url in files: - text.nameext_from_url(url, data) - data["filename"], _, data["id"] = data["filename"].rpartition("-") - yield Message.Url, url, data diff --git a/gallery_dl/extractor/lolisafe.py b/gallery_dl/extractor/lolisafe.py new file mode 100644 index 00000000..f8fbe4de --- /dev/null +++ b/gallery_dl/extractor/lolisafe.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +# Copyright 2021 Mike Fährmann +# +# 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 lolisafe/chibisafe instances""" + +from .common import BaseExtractor, Message +from .. import text + + +class LolisafeExtractor(BaseExtractor): + """Base class for lolisafe extractors""" + basecategory = "lolisafe" + directory_fmt = ("{category}", "{album_name} ({album_id})") + archive_fmt = "{album_id}_{id}" + + +BASE_PATTERN = LolisafeExtractor.update({ + "bunkr": {"root": "https://bunkr.is", "pattern": r"bunkr\.(?:is|to)"}, + "zzzz" : {"root": "https://zz.ht" , "pattern": r"zz\.(?:ht|fo)"}, +}) + + +class LolisafelbumExtractor(LolisafeExtractor): + subcategory = "album" + pattern = BASE_PATTERN + "/a/([^/?#]+)" + test = ( + ("https://bunkr.is/a/Lktg9Keq", { + "pattern": r"https://cdn\.bunkr\.is/test-テスト-\"&>-QjgneIQv\.png", + "content": "0c8768055e4e20e7c7259608b67799171b691140", + "keyword": { + "album_id": "Lktg9Keq", + "album_name": 'test テスト "&>', + "count": 1, + "filename": 'test-テスト-"&>', + "id": "QjgneIQv", + "num": int, + }, + }), + ("https://bunkr.to/a/Lktg9Keq"), + ("https://zz.ht/a/lop7W6EZ", { + "pattern": r"https://z\.zz\.fo/(4anuY|ih560)\.png", + "count": 2, + "keyword": { + "album_id": "lop7W6EZ", + "album_name": "ferris", + }, + }), + ("https://zz.fo/a/lop7W6EZ"), + ) + + def __init__(self, match): + LolisafeExtractor.__init__(self, match) + self.album_id = match.group(match.lastindex) + + def items(self): + files, data = self.fetch_album(self.album_id) + + yield Message.Directory, data + for data["num"], file in enumerate(files, 1): + url = file["file"] + text.nameext_from_url(url, data) + data["filename"], sep, data["id"] = \ + data["filename"].rpartition("-") + if not sep: + data["filename"] = data["id"] + yield Message.Url, url, data + + def fetch_album(self, album_id): + url = "{}/api/album/get/{}".format(self.root, album_id) + data = self.request(url).json() + + return data["files"], { + "album_id" : self.album_id, + "album_name": text.unescape(data["title"]), + "count" : data["count"], + } diff --git a/scripts/supportedsites.py b/scripts/supportedsites.py index cd6d3b3f..142c5b73 100755 --- a/scripts/supportedsites.py +++ b/scripts/supportedsites.py @@ -115,6 +115,7 @@ CATEGORY_MAP = { "xhamster" : "xHamster", "xvideos" : "XVideos", "yandere" : "yande.re", + "zzzz" : "ZzZz", } SUBCATEGORY_MAP = { @@ -203,6 +204,7 @@ BASE_MAP = { "foolslide" : "FoOlSlide Instances", "gelbooru_v01": "Gelbooru Beta 0.1.11", "gelbooru_v02": "Gelbooru Beta 0.2", + "lolisafe" : "lolisafe and chibisafe", "moebooru" : "Moebooru and MyImouto", }