From 0466fcab4cd8841dfd14ce84a8bff9cc822123f6 Mon Sep 17 00:00:00 2001 From: hdk5 Date: Thu, 5 Dec 2024 17:38:57 +0200 Subject: [PATCH] [lofter]: add initial support --- gallery_dl/extractor/__init__.py | 1 + gallery_dl/extractor/lofter.py | 150 +++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 gallery_dl/extractor/lofter.py diff --git a/gallery_dl/extractor/__init__.py b/gallery_dl/extractor/__init__.py index 594ce41a96..0201b781e6 100644 --- a/gallery_dl/extractor/__init__.py +++ b/gallery_dl/extractor/__init__.py @@ -98,6 +98,7 @@ "lexica", "lightroom", "livedoor", + "lofter", "luscious", "lynxchan", "mangadex", diff --git a/gallery_dl/extractor/lofter.py b/gallery_dl/extractor/lofter.py new file mode 100644 index 0000000000..bb167761d3 --- /dev/null +++ b/gallery_dl/extractor/lofter.py @@ -0,0 +1,150 @@ +# -*- 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://www.lofter.com/""" + +from .common import Extractor, Message +from .. import text, util, exception + + +class LofterExtractor(Extractor): + """Base class for lofter extractors""" + category = "lofter" + root = "https://www.lofter.com" + directory_fmt = ("{category}", "{blog_name}") + filename_fmt = "{id}_{num}.{extension}" + archive_fmt = "{id}_{num}" + + def _init(self): + self.api = LofterAPI(self) + + def items(self): + for post in self.posts(): + if "post" in post: + post = post["post"] + + post["blog_name"] = post["blogInfo"]["blogName"] + + post_type = post["type"] + image_urls = [] + + # Article + if post_type == 1: + content = post["content"] + image_urls = text.extract_iter(content, ' + r"www\.lofter\.com/front/blog/home-page/([\w-]+)|" + # https://.lofter.com/ + r"([\w-]+)\.lofter\.com" + r")") + example = "https://blog_name.lofter.com/" + + def posts(self): + blog_name = self.groups[0] or self.groups[1] + posts = self.api.blog_posts(blog_name) + return posts + + +class LofterAPI(): + def __init__(self, extractor): + self.extractor = extractor + + def _call(self, endpoint, data): + url = "https://api.lofter.com{}".format(endpoint) + params = { + 'product': 'lofter-android-7.9.10' + } + response = self.extractor.request( + url, method="POST", params=params, data=data) + info = response.json() + + if info["meta"]["status"] != 200: + self.extractor.log.debug("Server response: %s", info) + raise exception.StopExtraction("API request failed") + + return info + + def blog_posts(self, blog_name): + endpoint = "/v2.0/blogHomePage.api" + params = { + "method": "getPostLists", + "offset": 0, + "limit": 200, + "blogdomain": "{}.lofter.com".format(blog_name), + } + + while True: + data = self._call(endpoint, params) + posts = data["response"]["posts"] + + for post in posts: + yield post + + if params["offset"] + len(posts) < data["response"]["offset"]: + break + + params["offset"] = data["response"]["offset"] + + def post(self, blog_id, post_id): + endpoint = "/oldapi/post/detail.api" + params = { + "targetblogid": blog_id, + "postid": post_id, + } + data = self._call(endpoint, params) + posts = data["response"]["posts"] + post = posts[0] + return post