This repository has been archived on 2026-05-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
GallerySubscriber/backend/app/api/platforms.py
T
2026-02-02 20:17:13 -05:00

238 lines
9.5 KiB
Python

"""Platform information API endpoints.
Provides information about supported platforms and their configuration options.
"""
from quart import Blueprint, jsonify
from app.services.gallery_dl import GalleryDLService
bp = Blueprint("platforms", __name__)
@bp.route("", methods=["GET"])
async def list_platforms():
"""List all supported platforms with their configuration options."""
gdl_service = GalleryDLService()
platforms = {
"patreon": {
"name": "Patreon",
"description": "Download posts from Patreon creators",
"requires_auth": True,
"auth_type": "cookies",
"url_pattern": "https://www.patreon.com/{creator}",
"url_examples": [
"https://www.patreon.com/example_artist",
"https://www.patreon.com/user?u=12345678",
],
"content_types": gdl_service.get_platform_content_types("patreon"),
"content_type_descriptions": {
"images": "Standard post images",
"image_large": "High-resolution image versions",
"attachments": "File attachments (ZIP, PSD, etc.)",
"postfile": "Post-specific files",
"content": "Embedded content in post body",
},
"default_config": gdl_service.get_default_config_for_platform("patreon"),
},
"subscribestar": {
"name": "SubscribeStar",
"description": "Download posts from SubscribeStar creators",
"requires_auth": True,
"auth_type": "cookies",
"url_pattern": "https://subscribestar.{domain}/{creator}",
"url_examples": [
"https://subscribestar.adult/example_artist",
"https://www.subscribestar.com/example_artist",
],
"content_types": gdl_service.get_platform_content_types("subscribestar"),
"content_type_descriptions": {
"all": "All available content",
},
"default_config": gdl_service.get_default_config_for_platform("subscribestar"),
},
"hentaifoundry": {
"name": "Hentai Foundry",
"description": "Download artwork from Hentai Foundry artists",
"requires_auth": False,
"auth_type": "cookies", # Optional but improves access
"url_pattern": "https://www.hentai-foundry.com/user/{artist}",
"url_examples": [
"https://www.hentai-foundry.com/user/example_artist",
"https://www.hentai-foundry.com/pictures/user/example_artist",
],
"content_types": gdl_service.get_platform_content_types("hentaifoundry"),
"content_type_descriptions": {
"pictures": "Artwork/pictures",
"stories": "Written stories",
},
"default_config": gdl_service.get_default_config_for_platform("hentaifoundry"),
},
"discord": {
"name": "Discord",
"description": "Download attachments from Discord channels",
"requires_auth": True,
"auth_type": "token",
"url_pattern": "https://discord.com/channels/{server}/{channel}",
"url_examples": [
"https://discord.com/channels/123456789/987654321",
],
"content_types": gdl_service.get_platform_content_types("discord"),
"content_type_descriptions": {
"all": "All attachments and embeds",
},
"default_config": gdl_service.get_default_config_for_platform("discord"),
"notes": "Requires Discord user token (not bot token)",
},
"pixiv": {
"name": "Pixiv",
"description": "Download artwork from Pixiv artists",
"requires_auth": True,
"auth_type": "cookies",
"url_pattern": "https://www.pixiv.net/users/{user_id}",
"url_examples": [
"https://www.pixiv.net/users/12345678",
"https://www.pixiv.net/en/users/12345678",
],
"content_types": gdl_service.get_platform_content_types("pixiv"),
"content_type_descriptions": {
"all": "All artwork (illustrations and manga)",
"illusts": "Illustrations only",
"manga": "Manga only",
"bookmarks": "Bookmarked works",
},
"default_config": gdl_service.get_default_config_for_platform("pixiv"),
},
"deviantart": {
"name": "DeviantArt",
"description": "Download artwork from DeviantArt artists",
"requires_auth": False,
"auth_type": "cookies",
"url_pattern": "https://www.deviantart.com/{username}",
"url_examples": [
"https://www.deviantart.com/example-artist",
"https://www.deviantart.com/example-artist/gallery",
],
"content_types": gdl_service.get_platform_content_types("deviantart"),
"content_type_descriptions": {
"all": "All deviations",
"gallery": "Gallery artwork",
"scraps": "Scraps folder",
"favorites": "Favorited works",
},
"default_config": gdl_service.get_default_config_for_platform("deviantart"),
},
}
return jsonify({"platforms": platforms})
@bp.route("/<platform>", methods=["GET"])
async def get_platform(platform: str):
"""Get detailed information about a specific platform."""
gdl_service = GalleryDLService()
if platform not in ["patreon", "subscribestar", "hentaifoundry", "discord", "pixiv", "deviantart"]:
return jsonify({"error": f"Unknown platform: {platform}"}), 404
# Get the full platform info from list_platforms
all_platforms = (await list_platforms()).get_json()
platform_info = all_platforms["platforms"].get(platform)
if not platform_info:
return jsonify({"error": f"Platform not found: {platform}"}), 404
return jsonify(platform_info)
@bp.route("/<platform>/config-schema", methods=["GET"])
async def get_config_schema(platform: str):
"""Get the configuration schema for a platform.
This defines what options can be set per-source for this platform.
Useful for building dynamic forms in the frontend.
"""
if platform not in ["patreon", "subscribestar", "hentaifoundry", "discord", "pixiv", "deviantart"]:
return jsonify({"error": f"Unknown platform: {platform}"}), 404
gdl_service = GalleryDLService()
content_types = gdl_service.get_platform_content_types(platform)
defaults = gdl_service.get_default_config_for_platform(platform)
schema = {
"platform": platform,
"fields": [
{
"name": "content_types",
"type": "multiselect",
"label": "Content Types to Download",
"description": "Select which types of content to download from this source",
"options": content_types,
"default": defaults.get("content_types", ["all"]),
},
{
"name": "sleep",
"type": "number",
"label": "Delay Between Downloads (seconds)",
"description": "Time to wait between downloading files. Higher values are safer but slower.",
"min": 0.5,
"max": 30.0,
"step": 0.5,
"default": defaults.get("sleep", 3.0),
},
{
"name": "sleep_request",
"type": "number",
"label": "Delay Between Requests (seconds)",
"description": "Time to wait between API requests. Helps avoid rate limiting.",
"min": 0.5,
"max": 15.0,
"step": 0.5,
"default": defaults.get("sleep_request", 1.5),
},
{
"name": "skip_existing",
"type": "boolean",
"label": "Skip Already Downloaded",
"description": "Skip files that have already been downloaded (uses archive database)",
"default": True,
},
{
"name": "save_metadata",
"type": "boolean",
"label": "Save Metadata",
"description": "Save JSON metadata file alongside each downloaded file",
"default": True,
},
{
"name": "timeout",
"type": "number",
"label": "Download Timeout (seconds)",
"description": "Maximum time to wait for a single download before giving up",
"min": 60,
"max": 7200,
"step": 60,
"default": 3600,
},
{
"name": "directory_pattern",
"type": "text",
"label": "Directory Pattern (Advanced)",
"description": "Custom directory structure pattern. Leave empty for platform default.",
"placeholder": defaults.get("directory_pattern", ""),
"default": None,
},
{
"name": "filename_pattern",
"type": "text",
"label": "Filename Pattern (Advanced)",
"description": "Custom filename pattern. Leave empty for platform default.",
"placeholder": defaults.get("filename_pattern", ""),
"default": None,
},
],
}
return jsonify(schema)