From 4f33751c3085e50e05b39365c283707f7559628f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20F=C3=A4hrmann?= Date: Sun, 14 Dec 2025 18:01:18 +0100 Subject: [PATCH] [koofer] add 'shared' extractor (#8700) --- docs/supportedsites.md | 6 ++++ gallery_dl/extractor/__init__.py | 1 + gallery_dl/extractor/koofr.py | 55 ++++++++++++++++++++++++++++++++ scripts/supportedsites.py | 3 ++ test/results/koofr.py | 50 +++++++++++++++++++++++++++++ 5 files changed, 115 insertions(+) create mode 100644 gallery_dl/extractor/koofr.py create mode 100644 test/results/koofr.py diff --git a/docs/supportedsites.md b/docs/supportedsites.md index 4a50637a..804d37da 100644 --- a/docs/supportedsites.md +++ b/docs/supportedsites.md @@ -583,6 +583,12 @@ Consider all listed sites to potentially be NSFW. Chapters, Manga + + Koofr + https://koofr.net/ + Shared Links + + Leak Gallery https://leakgallery.com diff --git a/gallery_dl/extractor/__init__.py b/gallery_dl/extractor/__init__.py index 77efc9be..3cb29fad 100644 --- a/gallery_dl/extractor/__init__.py +++ b/gallery_dl/extractor/__init__.py @@ -113,6 +113,7 @@ modules = [ "kemono", "khinsider", "komikcast", + "koofr", "leakgallery", "lensdump", "lexica", diff --git a/gallery_dl/extractor/koofr.py b/gallery_dl/extractor/koofr.py new file mode 100644 index 00000000..9ebc1331 --- /dev/null +++ b/gallery_dl/extractor/koofr.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +# Copyright 2025 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 https://koofr.net/""" + +from .common import Extractor, Message +from .. import text + + +class KoofrSharedExtractor(Extractor): + """Base class for koofr extractors""" + category = "koofr" + subcategory = "shared" + root = "https://app.koofr.net" + pattern = (r"(?:https?://)?(?:" + r"(?:app\.)?koofr\.(?:net|eu)/links/([\w-]+)|" + r"k00\.fr/(\w+))") + example = "https://app.koofr.net/links/UUID" + + def items(self): + uuid, code = self.groups + if code is not None: + uuid = self.request_location( + "https://k00.fr/" + code, method="GET").rpartition("/")[2] + + url = f"{self.root}/api/v2/public/links/{uuid}" + referer = f"{self.root}/links/{uuid}" + password = self.config("password") + params = {"password": password or ""} + headers = { + "Referer" : referer, + "X-Client" : "newfrontend", + "X-Koofr-Version": "2.1", + "Sec-Fetch-Dest" : "empty", + "Sec-Fetch-Mode" : "cors", + "Sec-Fetch-Site" : "same-origin", + } + data = self.request_json(url, params=params, headers=headers) + + name = data["name"] + file = text.nameext_from_name(name, data["file"]) + file["_http_headers"] = {"Referer": referer} + + root = data.get("publicUrlBase") or self.root + url = f"{root}/content/links/{uuid}/files/get/{name}?path=/&force=" + if password: + url = f"{url}&password={password}" + + yield Message.Directory, "", file + yield Message.Url, url, file diff --git a/scripts/supportedsites.py b/scripts/supportedsites.py index e1db6fc6..d34190bd 100755 --- a/scripts/supportedsites.py +++ b/scripts/supportedsites.py @@ -341,6 +341,9 @@ SUBCATEGORY_MAP = { "discord-server": "", "posts" : "", }, + "koofr": { + "shared": "Shared Links", + }, "leakgallery": { "trending" : "Trending Medias", "mostliked": "Most Liked Posts", diff --git a/test/results/koofr.py b/test/results/koofr.py new file mode 100644 index 00000000..749219cd --- /dev/null +++ b/test/results/koofr.py @@ -0,0 +1,50 @@ +# -*- 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 koofr + + +__tests__ = ( +{ + "#url" : "https://k00.fr/cltf71jr", + "#class" : koofr.KoofrSharedExtractor, + "#results" : "https://app.koofr.net/content/links/923b4f56-3aaf-49ee-95e3-d85c52b687b0/files/get/wsf-form-job-application-form.json?path=/&force=", + "#sha1_content": "f65ccc63a99165ecb9ff2ab92302c25b245a904f", + + "contentType": "application/json", + "extension" : "json", + "filename" : "wsf-form-job-application-form", + "hash" : "99271125b819ee7907dc47ab723f6dc7", + "modified" : 1728623530078, + "name" : "wsf-form-job-application-form.json", + "size" : 18023, + "tags" : {}, + "type" : "file", +}, + +{ + "#url" : "https://app.koofr.net/links/923b4f56-3aaf-49ee-95e3-d85c52b687b0", + "#class" : koofr.KoofrSharedExtractor, + "#results" : "https://app.koofr.net/content/links/923b4f56-3aaf-49ee-95e3-d85c52b687b0/files/get/wsf-form-job-application-form.json?path=/&force=", + "#sha1_content": "f65ccc63a99165ecb9ff2ab92302c25b245a904f", + + "contentType": "application/json", + "extension" : "json", + "filename" : "wsf-form-job-application-form", + "hash" : "99271125b819ee7907dc47ab723f6dc7", + "modified" : 1728623530078, + "name" : "wsf-form-job-application-form.json", + "size" : 18023, + "tags" : {}, + "type" : "file", +}, + +{ + "#url" : "https://app.koofr.eu/links/923b4f56-3aaf-49ee-95e3-d85c52b687b0", + "#class" : koofr.KoofrSharedExtractor, +}, + +)