From 8617c08c6cb59bb9de5bb3defdd1e6f7219b4360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20F=C3=A4hrmann?= Date: Tue, 9 Sep 2025 21:47:43 +0200 Subject: [PATCH] [cyberfile] add support (#5015) --- docs/configuration.rst | 14 ++++ docs/gallery-dl.conf | 4 ++ docs/supportedsites.md | 6 ++ gallery_dl/extractor/__init__.py | 1 + gallery_dl/extractor/cyberfile.py | 114 ++++++++++++++++++++++++++++++ scripts/supportedsites.py | 1 + test/results/cyberfile.py | 107 ++++++++++++++++++++++++++++ 7 files changed, 247 insertions(+) create mode 100644 gallery_dl/extractor/cyberfile.py create mode 100644 test/results/cyberfile.py diff --git a/docs/configuration.rst b/docs/configuration.rst index e14701c4..50039bee 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -2036,6 +2036,20 @@ Description uses the same domain as a given input URL. +extractor.cyberfile.password +---------------------------- +Type + ``string`` +Default + ``""`` +Description + Password value used to access protected files and folders. + + Note: Leave this value empty or undefined + to be interactively prompted for a password when needed + (see `getpass() `__). + + extractor.[Danbooru].external ----------------------------- Type diff --git a/docs/gallery-dl.conf b/docs/gallery-dl.conf index f44d4429..6b14d3a2 100644 --- a/docs/gallery-dl.conf +++ b/docs/gallery-dl.conf @@ -237,6 +237,10 @@ { "domain": null }, + "cyberfile": + { + "password": "" + }, "dankefuerslesen": { "zip": false diff --git a/docs/supportedsites.md b/docs/supportedsites.md index 4d34c2cb..5efb4276 100644 --- a/docs/supportedsites.md +++ b/docs/supportedsites.md @@ -211,6 +211,12 @@ Consider all listed sites to potentially be NSFW. Albums, Media Files + + CyberFile + https://cyberfile.me/ + Files, Folders + + Danke fürs Lesen https://danke.moe/ diff --git a/gallery_dl/extractor/__init__.py b/gallery_dl/extractor/__init__.py index 574d1e29..fe89cd60 100644 --- a/gallery_dl/extractor/__init__.py +++ b/gallery_dl/extractor/__init__.py @@ -44,6 +44,7 @@ modules = [ "comick", "comicvine", "cyberdrop", + "cyberfile", "danbooru", "dankefuerslesen", "desktopography", diff --git a/gallery_dl/extractor/cyberfile.py b/gallery_dl/extractor/cyberfile.py new file mode 100644 index 00000000..381e86c7 --- /dev/null +++ b/gallery_dl/extractor/cyberfile.py @@ -0,0 +1,114 @@ +# -*- 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://cyberfile.me/""" + +from .common import Extractor, Message +from .. import text, exception + +BASE_PATTERN = r"(?:https?://)?(?:www\.)?cyberfile\.me" + + +class CyberfileExtractor(Extractor): + """Base class for cyberfile extractors""" + category = "cyberfile" + root = "https://cyberfile.me" + + def request_api(self, endpoint, data): + url = f"{self.root}{endpoint}" + headers = { + "X-Requested-With": "XMLHttpRequest", + "Origin": self.root, + } + resp = self.request_json( + url, method="POST", headers=headers, data=data) + + if "albumPasswordModel" in resp.get("javascript", ""): + url_pw = f"{self.root}/ajax/folder_password_process" + data_pw = { + "folderPassword": self._get_auth_info(password=True)[1], + "folderId": text.extr( + resp["html"], '', "")) + folder = info[0] if len(info) > 1 else "" + + file = { + "file_id" : file_id, + "file_num": text.parse_int(file_num), + "name" : resp["page_title"], + "folder" : folder, + "uploader": info[-1][2:].strip(), + "size" : text.parse_bytes(text.remove_html(extr( + "Filesize:", ""))[:-1]), + "tags" : text.split_html(extr( + "Keywords:", "")), + "date" : text.parse_datetime(text.remove_html(extr( + "Uploaded:", "")), "%d/%m/%Y %H:%M:%S"), + "permissions": text.remove_html(extr( + "Permissions:", "")).split(" & "), + } + + file["file_url"] = url = extr("openUrl('", "'") + text.nameext_from_url(file["name"] or url, file) + yield Message.Directory, file + yield Message.Url, url, file diff --git a/scripts/supportedsites.py b/scripts/supportedsites.py index 018a7341..f8fb4a62 100755 --- a/scripts/supportedsites.py +++ b/scripts/supportedsites.py @@ -42,6 +42,7 @@ CATEGORY_MAP = { "cien" : "Ci-en", "cohost" : "cohost!", "comicvine" : "Comic Vine", + "cyberfile" : "CyberFile", "dankefuerslesen": "Danke fürs Lesen", "deviantart" : "DeviantArt", "drawfriends" : "Draw Friends", diff --git a/test/results/cyberfile.py b/test/results/cyberfile.py new file mode 100644 index 00000000..68d7aa56 --- /dev/null +++ b/test/results/cyberfile.py @@ -0,0 +1,107 @@ +# -*- 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 cyberfile +from gallery_dl import exception + + +__tests__ = ( +{ + "#url" : "https://cyberfile.me/bpfD", + "#class" : cyberfile.CyberfileFileExtractor, + "#pattern" : r"https://p1.cyberfile.me/bpfD/Raindrops.mp4\?download_token=[0-9a-f]{64}", + "#count" : 1, + + "date" : "dt:2024-01-04 16:01:26", + "extension" : "mp4", + "file_id" : "bpfD", + "file_num" : 718677, + "file_url" : str, + "filename" : "Raindrops", + "folder" : "Videos", + "name" : "Raindrops.mp4", + "size" : 3659530, + "uploader" : "barbarella", + "permissions": [ + "View", + "Download", + ], + "tags" : [ + "raindrops", + "mp4", + ], +}, + +{ + "#url" : "https://cyberfile.me/7d79", + "#comment" : "password-protected", + "#class" : cyberfile.CyberfileFileExtractor, + "#options" : {"password": "sample_pwd"}, + "#pattern" : r"https://p1.cyberfile.me/7d79/Raindrops.mp4\?download_token=[0-9a-f]{64}", + "#count" : 1, + + "date" : "dt:2024-01-04 17:50:59", + "extension" : "mp4", + "file_id" : "7d79", + "file_num" : 718711, + "file_url" : str, + "filename" : "Raindrops", + "folder" : "Playlist Protected", + "name" : "Raindrops.mp4", + "size" : 3659530, + "tags" : [], + "uploader" : "barbarella", + "permissions": [ + "View", + "Download", + ], +}, + +{ + "#url" : "https://cyberfile.me/7d79", + "#comment" : "password-protected", + "#class" : cyberfile.CyberfileFileExtractor, + "#options" : {"password": "abc"}, + "#exception": exception.AuthorizationError, +}, + +{ + "#url" : "https://cyberfile.me/folder/82d0aab0853fdd13294171577081f4d8/Playlist", + "#class" : cyberfile.CyberfileFolderExtractor, + "#results" : ( + "https://cyberfile.me/7d76", + "https://cyberfile.me/7d77", + ), + + "folder" : "Playlist", + "folder_hash": "82d0aab0853fdd13294171577081f4d8", + "folder_num" : 56050, +}, + +{ + "#url" : "https://cyberfile.me/folder/1524a09fa9d773dcc88c841ed2e098c9/Playlist_Protected", + "#comment" : "password-protected", + "#class" : cyberfile.CyberfileFolderExtractor, + "#options" : {"password": "sample_pwd"}, + "#results" : ( + "https://cyberfile.me/7d7a", + "https://cyberfile.me/7d79", + ), + + "folder" : "Playlist Protected", + "folder_hash": "1524a09fa9d773dcc88c841ed2e098c9", + "folder_num" : 56051, +}, + +{ + "#url" : "https://cyberfile.me/folder/1524a09fa9d773dcc88c841ed2e098c9/Playlist_Protected", + "#comment" : "password-protected", + "#class" : cyberfile.CyberfileFolderExtractor, + "#options" : {"password": "abc"}, + "#exception": exception.AuthorizationError, +}, + +)