From 204e8efcdccf5a5e5482a548b145cfd6942870e1 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 26 Jan 2026 22:37:15 -0500 Subject: [PATCH] signing for extension deployment, tuning for download crawl depth, and dependency version visibility in settings view --- .claude/settings.local.json | 8 +- .gitignore | 4 + PROJECT_PLAN.md | 548 ----------------------------- backend/app/api/settings.py | 55 +++ backend/app/services/gallery_dl.py | 8 +- extension/.amo-upload-uuid | 1 + extension/README.md | 170 +++++++++ extension/RELEASE_NOTES.md | 74 ++++ extension/manifest.json | 6 + frontend/src/views/Settings.vue | 105 +++++- 10 files changed, 426 insertions(+), 553 deletions(-) delete mode 100644 PROJECT_PLAN.md create mode 100644 extension/.amo-upload-uuid create mode 100644 extension/README.md create mode 100644 extension/RELEASE_NOTES.md diff --git a/.claude/settings.local.json b/.claude/settings.local.json index d28a2d3..edca24f 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -7,7 +7,13 @@ "Bash(docker compose logs:*)", "Bash(docker compose exec celery sh -c \"grep -i session /data/cookies/patreon_cookies.txt || echo ''No session cookie found''\")", "Bash(docker compose exec celery sh -c \"gallery-dl --cookies /data/cookies/patreon_cookies.txt -v ''https://www.patreon.com/knuxy'' 2>&1 | head -20\")", - "Bash(docker compose exec:*)" + "Bash(docker compose exec:*)", + "Bash(powershell -File - <<'EOF'\nAdd-Type -AssemblyName System.IO.Compression.FileSystem\n$zip = [System.IO.Compression.ZipFile]::OpenRead\\('c:\\\\Users\\\\bvandeusen\\\\Nextcloud\\\\Projects\\\\GallerySubscriber\\\\gallerysubscriber.xpi'\\)\n$zip.Entries | Select-Object FullName\n$zip.Dispose\\(\\)\nEOF)", + "Bash(npx web-ext sign:*)", + "Bash(where:*)", + "Bash(where npm:*)", + "Bash(powershell -Command \"Copy-Item ''c:\\\\Users\\\\bvandeusen\\\\Nextcloud\\\\Projects\\\\GallerySubscriber\\\\extension\\\\web-ext-artifacts\\\\be3706e9e89640a5b70b-1.0.0.xpi'' ''c:\\\\Users\\\\bvandeusen\\\\Nextcloud\\\\Projects\\\\GallerySubscriber\\\\gallerysubscriber-signed.xpi'' -Force; Get-Item ''c:\\\\Users\\\\bvandeusen\\\\Nextcloud\\\\Projects\\\\GallerySubscriber\\\\gallerysubscriber-signed.xpi'' | Select-Object Name, Length\")", + "WebFetch(domain:github.com)" ] } } diff --git a/.gitignore b/.gitignore index 8251568..840d53f 100644 --- a/.gitignore +++ b/.gitignore @@ -83,3 +83,7 @@ config/ # Build artifacts backend/static/ + +# Extension packages +*.xpi +extension-dist/ diff --git a/PROJECT_PLAN.md b/PROJECT_PLAN.md deleted file mode 100644 index eb14c02..0000000 --- a/PROJECT_PLAN.md +++ /dev/null @@ -1,548 +0,0 @@ -# Gallery Subscriber - -A Docker-based web application for managing gallery-dl downloads with a modern web interface. - ---- - -## Table of Contents - -1. [Project Overview](#project-overview) -2. [Architecture](#architecture) -3. [Technology Stack](#technology-stack) -4. [Project Structure](#project-structure) -5. [Database Schema](#database-schema) -6. [API Specification](#api-specification) -7. [Firefox Extension](#firefox-extension) -8. [Configuration](#configuration) -9. [Development Phases](#development-phases) -10. [Migration from Legacy Project](#migration-from-legacy-project) - ---- - -## Project Overview - -### Goals - -- **Containerized Deployment**: Run the entire download manager in Docker for portability -- **Web Interface**: Modern UI for managing subscriptions, viewing downloads, and monitoring new content -- **Flexible Authentication**: Firefox extension for cookie export OR manual cookie upload via web UI -- **Notifications**: Real-time updates when new content is downloaded -- **Reliability**: Maintain the robust scheduling and error handling from the original project - -### Non-Goals (Initial Release) - -- Multi-user support (single-user initially) -- Mobile app -- SSL termination (handled by external reverse proxy) - ---- - -## Architecture - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ External Reverse Proxy │ -│ (Traefik/Caddy/nginx - handles SSL) │ -└──────────────────────────┬──────────────────────────────────────┘ - │ HTTP (port 8080) - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ Docker Compose Stack │ -│ │ -│ ┌─────────────────────────────────────────────────────────┐ │ -│ │ Quart Backend │ │ -│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │ │ -│ │ │ REST API │ │WebSocket │ │ Static │ │ gallery-dl│ │ │ -│ │ │ /api/* │ │ /ws/* │ │ Files │ │ Wrapper │ │ │ -│ │ └──────────┘ └──────────┘ └──────────┘ └───────────┘ │ │ -│ └─────────────────────────────────────────────────────────┘ │ -│ │ │ -│ ┌───────────────────────────┴───────────────────────────────┐ │ -│ │ Celery Worker │ │ -│ │ • Download tasks • Scheduled checks │ │ -│ │ • Manifest generation • Error retry logic │ │ -│ └───────────────────────────────────────────────────────────┘ │ -│ │ │ -│ ┌──────────────┐ ┌─────────┴───────┐ ┌──────────────────┐ │ -│ │ PostgreSQL │ │ Redis │ │ Vue Frontend │ │ -│ │ (data) │ │ (task queue) │ │ (static build) │ │ -│ └──────────────┘ └─────────────────┘ └──────────────────┘ │ -│ │ -│ Volumes: │ -│ ├── /data/downloads (downloaded content) │ -│ ├── /data/config (gallery-dl.conf) │ -│ ├── /data/cookies (cookie files) │ -│ └── /data/db (PostgreSQL data) │ -└─────────────────────────────────────────────────────────────────┘ -``` - ---- - -## Technology Stack - -### Backend -| Component | Technology | Rationale | -|-----------|------------|-----------| -| Web Framework | **Quart** | Flask-like API with native async, WebSocket support | -| Task Queue | **Celery + Redis** | Reliable background tasks, scheduling with Celery Beat | -| Database | **PostgreSQL** | JSON fields for metadata, robust concurrency | -| ORM | **SQLAlchemy 2.0** | Async support, mature ecosystem | -| Migrations | **Alembic** | Standard for SQLAlchemy | - -### Frontend -| Component | Technology | Rationale | -|-----------|------------|-----------| -| Framework | **Vue 3** | Reactive, component-based | -| UI Library | **Vuetify 3** | Material Design, comprehensive components | -| State | **Pinia** | Official Vue state management | -| HTTP Client | **Axios** | Request interceptors for auth | -| WebSocket | **Native** | Real-time updates | - -### Infrastructure -| Component | Technology | Rationale | -|-----------|------------|-----------| -| Container | **Docker Compose** | Easy deployment | -| Process Manager | **Supervisor** | Manage Quart + Celery in container | - ---- - -## Project Structure - -``` -gallery-subscriber/ -├── docker-compose.yml -├── docker-compose.dev.yml -├── .env.example -├── README.md -│ -├── backend/ -│ ├── Dockerfile -│ ├── requirements.txt -│ ├── supervisord.conf -│ │ -│ ├── app/ -│ │ ├── __init__.py -│ │ ├── main.py # Quart app factory -│ │ ├── config.py # Settings (from env) -│ │ │ -│ │ ├── api/ -│ │ │ ├── __init__.py -│ │ │ ├── sources.py # Source CRUD -│ │ │ ├── downloads.py # Download history -│ │ │ ├── credentials.py # Cookie management -│ │ │ ├── settings.py # App settings -│ │ │ └── websocket.py # Real-time events -│ │ │ -│ │ ├── models/ -│ │ │ ├── __init__.py -│ │ │ ├── source.py -│ │ │ ├── download.py -│ │ │ ├── credential.py -│ │ │ └── content.py -│ │ │ -│ │ ├── services/ -│ │ │ ├── __init__.py -│ │ │ ├── gallery_dl.py # gallery-dl subprocess wrapper -│ │ │ ├── download_manager.py -│ │ │ ├── credential_manager.py -│ │ │ └── manifest.py # Manifest generation -│ │ │ -│ │ ├── tasks/ -│ │ │ ├── __init__.py -│ │ │ ├── celery_app.py # Celery configuration -│ │ │ ├── downloads.py # Download tasks -│ │ │ └── scheduler.py # Scheduled jobs -│ │ │ -│ │ └── utils/ -│ │ ├── __init__.py -│ │ ├── cookies.py # Cookie parsing -│ │ └── encryption.py # Credential encryption -│ │ -│ ├── alembic/ -│ │ ├── env.py -│ │ └── versions/ -│ │ -│ └── tests/ -│ -├── frontend/ -│ ├── Dockerfile -│ ├── package.json -│ ├── vite.config.js -│ │ -│ └── src/ -│ ├── main.js -│ ├── App.vue -│ ├── router/ -│ ├── stores/ -│ ├── views/ -│ │ ├── Dashboard.vue -│ │ ├── Sources.vue -│ │ ├── Downloads.vue -│ │ ├── NewContent.vue -│ │ └── Settings.vue -│ ├── components/ -│ └── services/ -│ └── api.js -│ -├── extension/ -│ ├── manifest.json -│ ├── popup/ -│ │ ├── popup.html -│ │ ├── popup.css -│ │ └── popup.js -│ ├── background/ -│ │ └── background.js -│ └── icons/ -│ -└── scripts/ - ├── migrate_legacy.py # Import from old project - └── init_db.py -``` - ---- - -## Database Schema - -```sql --- Sources (artists/creators to download from) -CREATE TABLE sources ( - id SERIAL PRIMARY KEY, - name VARCHAR(255) NOT NULL, - platform VARCHAR(50) NOT NULL, -- patreon, subscribestar, hentaifoundry, discord - url TEXT NOT NULL, - enabled BOOLEAN DEFAULT true, - priority INTEGER DEFAULT 0, - check_interval INTEGER DEFAULT 3600, -- seconds between checks - last_check TIMESTAMP, - last_success TIMESTAMP, - error_count INTEGER DEFAULT 0, - metadata JSONB DEFAULT '{}', - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - UNIQUE(platform, url) -); - --- Downloads (individual download jobs) -CREATE TABLE downloads ( - id SERIAL PRIMARY KEY, - source_id INTEGER REFERENCES sources(id) ON DELETE SET NULL, - url TEXT NOT NULL, - status VARCHAR(20) DEFAULT 'pending', -- pending, running, completed, failed, skipped - error_type VARCHAR(50), -- auth_error, rate_limited, not_found, etc. - error_message TEXT, - file_count INTEGER DEFAULT 0, - started_at TIMESTAMP, - completed_at TIMESTAMP, - metadata JSONB DEFAULT '{}', - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); - -CREATE INDEX idx_downloads_status ON downloads(status); -CREATE INDEX idx_downloads_source ON downloads(source_id); - --- Content Items (discovered files) -CREATE TABLE content_items ( - id SERIAL PRIMARY KEY, - source_id INTEGER REFERENCES sources(id) ON DELETE CASCADE, - download_id INTEGER REFERENCES downloads(id) ON DELETE SET NULL, - external_id VARCHAR(255), -- Platform-specific ID - title VARCHAR(500), - content_type VARCHAR(50), -- image, video, attachment - file_path VARCHAR(500), - file_size BIGINT, - thumbnail_path VARCHAR(500), - published_at TIMESTAMP, - discovered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - metadata JSONB DEFAULT '{}', - UNIQUE(source_id, external_id) -); - -CREATE INDEX idx_content_discovered ON content_items(discovered_at DESC); - --- Credentials (encrypted cookie/token storage) -CREATE TABLE credentials ( - id SERIAL PRIMARY KEY, - platform VARCHAR(50) NOT NULL UNIQUE, - credential_type VARCHAR(20) NOT NULL, -- cookies, token - data BYTEA NOT NULL, -- Encrypted - expires_at TIMESTAMP, - last_verified TIMESTAMP, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); - --- Settings (key-value store) -CREATE TABLE settings ( - key VARCHAR(100) PRIMARY KEY, - value JSONB NOT NULL, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); -``` - ---- - -## API Specification - -### Sources - -``` -GET /api/sources List all sources (with pagination) -POST /api/sources Add new source -GET /api/sources/:id Get source details -PATCH /api/sources/:id Update source -DELETE /api/sources/:id Delete source -POST /api/sources/:id/check Trigger immediate download check -``` - -### Downloads - -``` -GET /api/downloads List download history -GET /api/downloads/:id Get download details with logs -POST /api/downloads/:id/retry Retry failed download -GET /api/downloads/stats Get statistics (by platform, by day) -``` - -### Content - -``` -GET /api/content List content items (filterable) -GET /api/content/new Get new content since timestamp -``` - -### Credentials - -``` -GET /api/credentials List credential status (no secrets) -POST /api/credentials Upload cookies (manual or from extension) -DELETE /api/credentials/:platform Remove credentials for platform -POST /api/credentials/verify Verify credentials are working -``` - -### Settings - -``` -GET /api/settings Get all settings -PATCH /api/settings Update settings -GET /api/settings/gallery-dl Get gallery-dl config -PUT /api/settings/gallery-dl Update gallery-dl config -``` - -### WebSocket - -``` -WS /ws/events - -Events (server -> client): - download.started { download_id, source_id, url } - download.progress { download_id, file_count } - download.completed { download_id, file_count } - download.failed { download_id, error_type, error_message } - content.new { content_id, source_name, title, thumbnail } - credential.expiring { platform, expires_in_hours } -``` - ---- - -## Firefox Extension - -### Features - -- Export cookies for supported platforms (Patreon, SubscribeStar, HentaiFoundry) -- Export Discord token -- Auto-refresh option (re-export when cookies change) -- Connection status indicator -- Manual export button per platform - -### Supported Platforms - -| Platform | Auth Type | Domains | -|----------|-----------|---------| -| Patreon | Cookies | `.patreon.com` | -| SubscribeStar | Cookies | `.subscribestar.com`, `.subscribestar.adult` | -| HentaiFoundry | Cookies | `.hentai-foundry.com` | -| Discord | Token | `.discord.com` | - -### Manual Alternative - -For users who don't want the extension: -1. Export cookies using browser dev tools or "cookies.txt" extension -2. Upload via Settings page in web UI -3. Paste cookie content or upload file - ---- - -## Configuration - -### Environment Variables (.env) - -```bash -# Database -DATABASE_URL=postgresql://gdl:password@db:5432/gallery_subscriber - -# Redis -REDIS_URL=redis://redis:6379/0 - -# Security -SECRET_KEY=your-secret-key-at-least-32-characters -EXTENSION_API_KEY=key-for-firefox-extension - -# Paths (inside container) -DOWNLOAD_PATH=/data/downloads -CONFIG_PATH=/data/config -COOKIES_PATH=/data/cookies - -# Download settings -DOWNLOAD_PARALLEL_LIMIT=3 -DOWNLOAD_RATE_LIMIT=3.0 -DEFAULT_CHECK_INTERVAL=3600 - -# Server -HOST=0.0.0.0 -PORT=8080 -``` - -### docker-compose.yml - -```yaml -services: - app: - build: ./backend - ports: - - "8080:8080" - environment: - - DATABASE_URL=postgresql://gdl:${DB_PASSWORD}@db:5432/gallery_subscriber - - REDIS_URL=redis://redis:6379/0 - - SECRET_KEY=${SECRET_KEY} - - EXTENSION_API_KEY=${EXTENSION_API_KEY} - volumes: - - downloads:/data/downloads - - config:/data/config - - cookies:/data/cookies - depends_on: - - db - - redis - restart: unless-stopped - - celery: - build: ./backend - command: celery -A app.tasks.celery_app worker -B --loglevel=info - environment: - - DATABASE_URL=postgresql://gdl:${DB_PASSWORD}@db:5432/gallery_subscriber - - REDIS_URL=redis://redis:6379/0 - - SECRET_KEY=${SECRET_KEY} - volumes: - - downloads:/data/downloads - - config:/data/config - - cookies:/data/cookies - depends_on: - - db - - redis - restart: unless-stopped - - db: - image: postgres:15-alpine - environment: - - POSTGRES_USER=gdl - - POSTGRES_PASSWORD=${DB_PASSWORD} - - POSTGRES_DB=gallery_subscriber - volumes: - - postgres_data:/var/lib/postgresql/data - restart: unless-stopped - - redis: - image: redis:7-alpine - restart: unless-stopped - -volumes: - postgres_data: - downloads: - config: - cookies: -``` - ---- - -## Development Phases - -### Phase 1: Foundation -- [ ] Set up project structure -- [ ] Create Docker Compose development environment -- [ ] Initialize Quart app with basic routing -- [ ] Set up PostgreSQL + Alembic migrations -- [ ] Create database models -- [ ] Basic API endpoints (sources CRUD) - -### Phase 2: Download Engine -- [ ] Port gallery-dl wrapper from legacy project -- [ ] Implement Celery tasks for downloads -- [ ] Add platform-specific locking (from legacy) -- [ ] Error categorization and handling -- [ ] Download history tracking - -### Phase 3: Scheduling & State -- [ ] Celery Beat for scheduled downloads -- [ ] Round-robin scheduling logic (from legacy) -- [ ] Priority queue for failed tasks -- [ ] State persistence in PostgreSQL - -### Phase 4: Frontend -- [ ] Vue 3 + Vuetify scaffold -- [ ] Dashboard view -- [ ] Sources management UI -- [ ] Download history view -- [ ] Settings page - -### Phase 5: Authentication -- [ ] Credential storage (encrypted) -- [ ] Manual cookie upload via web UI -- [ ] Firefox extension -- [ ] Credential verification - -### Phase 6: Real-time & Content -- [ ] WebSocket event streaming -- [ ] New content feed -- [ ] Content browsing with thumbnails -- [ ] Notifications - -### Phase 7: Polish & Migration -- [ ] Migration script for legacy sources.yaml -- [ ] Import legacy gallery-dl.conf -- [ ] Testing -- [ ] Documentation - ---- - -## Migration from Legacy Project - -### What Gets Migrated - -| Legacy File | Destination | -|-------------|-------------| -| `sources.yaml` | `sources` table | -| `gallery-dl.conf` | `/data/config/gallery-dl.conf` (paths updated) | -| `state.json` | `sources` table (last_check, error_count) | -| Download history | Optional - start fresh or import logs | - -### Migration Script Usage - -```bash -python scripts/migrate_legacy.py \ - --sources /path/to/sources.yaml \ - --config /path/to/gallery-dl.conf \ - --state /path/to/state.json -``` - -### Key Patterns Preserved from Legacy - -1. **Platform locking** - One download per platform at a time -2. **Round-robin scheduling** - Fair distribution across sources -3. **Priority queue** - Failed tasks get priority on next run -4. **Error categorization** - AUTH_ERROR, RATE_LIMITED, NOT_FOUND, etc. -5. **Rate limiting** - Configurable delay between requests - ---- - -*Document Version: 2.0* -*Created: 2025-01-24* -*Project: Gallery Subscriber* diff --git a/backend/app/api/settings.py b/backend/app/api/settings.py index ce0014b..367f039 100644 --- a/backend/app/api/settings.py +++ b/backend/app/api/settings.py @@ -266,3 +266,58 @@ async def get_logs(): }) return jsonify({"logs": logs, "count": len(logs)}) + + +@bp.route("/system-info", methods=["GET"]) +async def get_system_info(): + """Get system information including dependency versions.""" + import sys + import importlib.metadata + + config = get_settings() + + # Get all installed packages (preserve original names for display) + all_packages = {} + # Also build a normalized lookup (lowercase, underscores normalized to hyphens) + normalized_lookup = {} + for dist in importlib.metadata.distributions(): + name = dist.metadata["Name"] + if name: + all_packages[name] = dist.version + # Normalize: lowercase and replace underscores with hyphens + normalized = name.lower().replace("_", "-") + normalized_lookup[normalized] = dist.version + + def get_version(name): + """Get version with case-insensitive and underscore/hyphen-insensitive lookup.""" + normalized = name.lower().replace("_", "-") + return normalized_lookup.get(normalized, "not installed") + + # Key packages to highlight (sorted alphabetically) + key_package_names = [ + "alembic", + "asyncpg", + "celery", + "gallery-dl", + "hypercorn", + "pydantic", + "quart", + "redis", + "sqlalchemy", + ] + + key_packages = { + name: get_version(name) + for name in key_package_names + } + + return jsonify({ + "version": "1.0.0", + "python_version": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}", + "python_full": sys.version, + "gallery_dl_version": get_version("gallery-dl"), + "key_packages": key_packages, + "all_packages": all_packages, + "download_path": config.download_path, + "config_path": config.config_path, + }) diff --git a/backend/app/services/gallery_dl.py b/backend/app/services/gallery_dl.py index 861b833..0f24b46 100644 --- a/backend/app/services/gallery_dl.py +++ b/backend/app/services/gallery_dl.py @@ -144,17 +144,21 @@ class GalleryDLService: # Additional options "videos": True, # Download video content "embeds": True, # Download embedded URLs (YouTube, etc.) + # Deep crawling options + "cursor": True, # Enable cursor-based pagination for complete history }, "subscribestar": { "content_types": ["all"], "directory": ["{date:%Y-%m-%d}_{id}_{title[:40]}"], "filename": "{num:>02}_{filename}.{extension}", + # Automatic infinite scroll pagination is built-in }, "hentaifoundry": { "content_types": ["pictures"], "directory": [], # Flat structure within platform folder "filename": "{category}_{index:>03}_{title[:50]}.{extension}", - "include": "all", # Include all content types + "include": "all", # Include all content types (pictures, scraps, stories) + # Automatic pagination through all pages (25 items/page) }, "discord": { "content_types": ["all"], @@ -164,6 +168,8 @@ class GalleryDLService: "embeds": True, # Download embedded URLs "stickers": True, # Download stickers "reactions": False, # Skip reaction images + # Deep crawling options + "threads": True, # Include thread content for complete history }, } diff --git a/extension/.amo-upload-uuid b/extension/.amo-upload-uuid new file mode 100644 index 0000000..2beade4 --- /dev/null +++ b/extension/.amo-upload-uuid @@ -0,0 +1 @@ +{"uploadUuid":"fe2853742907461a9436c0b20d45bcd9","channel":"unlisted","xpiCrcHash":"59496211d207900b7b0f4ee7cbece6aba1be1d2f6523229fee17f6652dc38d95"} \ No newline at end of file diff --git a/extension/README.md b/extension/README.md new file mode 100644 index 0000000..e64d3c0 --- /dev/null +++ b/extension/README.md @@ -0,0 +1,170 @@ +# GallerySubscriber Browser Extension + +A Firefox extension that exports authentication cookies and tokens from supported platforms to the GallerySubscriber backend for automated content downloading. + +## Features + +### Cookie Export +Automatically extracts authentication cookies from supported platforms and sends them to your GallerySubscriber backend. This enables gallery-dl to download content that requires login authentication. + +### Supported Platforms + +| Platform | Auth Type | How It Works | +|----------|-----------|--------------| +| **Patreon** | Cookies | Exports session cookies after you log in | +| **SubscribeStar** | Cookies | Exports session cookies (supports both .com and .adult domains) | +| **Hentai-Foundry** | Cookies | Exports session cookies after you log in | +| **Discord** | Token | Captures authorization token from API requests | + +### Discord Token Capture +Unlike other platforms that use cookies, Discord requires an authorization token. The extension automatically captures this token by monitoring Discord API requests when you use Discord in your browser. Simply: +1. Open Discord in Firefox +2. Interact with it (switch channels, send a message, etc.) +3. The extension captures and stores your token automatically + +### Dark/Light Theme Support +The extension automatically matches your system's color scheme preference: +- Detects `prefers-color-scheme` media query +- Supports manual theme override via `data-theme` attribute +- Consistent theming across popup and options pages + +## Installation + +### Temporary Installation (Development) +1. Open Firefox and navigate to `about:debugging#/runtime/this-firefox` +2. Click "Load Temporary Add-on" +3. Select any file in the `extension` folder (e.g., `manifest.json`) + +### Permanent Installation (Unsigned) +Requires Firefox Developer Edition or Nightly: +1. Navigate to `about:config` +2. Set `xpinstall.signatures.required` to `false` +3. Go to `about:addons` → gear icon → "Install Add-on From File" +4. Select `gallerysubscriber.xpi` + +### Permanent Installation (Signed) +1. Create an account at [addons.mozilla.org](https://addons.mozilla.org) +2. Use `web-ext sign` to sign the extension +3. Install the signed `.xpi` file + +## Configuration + +### Initial Setup +1. Click the extension icon in the toolbar +2. Click "Open Settings" or the gear icon +3. Enter your GallerySubscriber backend URL (e.g., `http://localhost:8000`) +4. Enter your API key (found in GallerySubscriber web UI → Settings) +5. Click "Test Connection" to verify +6. Click "Save" + +### Options Page Settings +- **API URL**: The base URL of your GallerySubscriber backend +- **API Key**: Authentication key for the extension API + +## Usage + +### Exporting Cookies for a Single Platform +1. Log into the platform in Firefox (e.g., patreon.com) +2. Click the GallerySubscriber extension icon +3. Click on the platform card +4. Cookies are exported to the backend + +### Exporting All Platforms +1. Ensure you're logged into all desired platforms +2. Click the extension icon +3. Click "Export All Platforms" +4. All available cookies/tokens are exported + +### Checking Platform Status +The popup shows the status of each platform: +- **"X cookies ready"** - Cookies found, ready to export +- **"No cookies found"** - Not logged in or cookies expired +- **"Token captured"** - Discord token available +- **"Open Discord in browser"** - Need to use Discord to capture token + +## Architecture + +``` +extension/ +├── manifest.json # Extension manifest (Manifest V2) +├── background/ +│ └── background.js # Background script - handles API calls & cookie extraction +├── popup/ +│ ├── popup.html # Popup UI +│ ├── popup.js # Popup logic +│ └── popup.css # Popup styles with theme support +├── options/ +│ └── options.html # Settings page (inline CSS/JS) +├── lib/ +│ ├── platforms.js # Platform definitions and configuration +│ ├── cookies.js # Cookie extraction utilities +│ └── api.js # Backend API client +└── icons/ + └── icon.svg # Extension icon +``` + +## Permissions + +The extension requires the following permissions: + +| Permission | Purpose | +|------------|---------| +| `cookies` | Read cookies from supported platform domains | +| `storage` | Store API configuration and Discord token | +| `tabs` | Access active tab information | +| `activeTab` | Interact with the current tab | +| `webRequest` | Monitor Discord API requests to capture token | +| `*://*.patreon.com/*` | Access Patreon cookies | +| `*://*.subscribestar.com/*` | Access SubscribeStar cookies | +| `*://*.subscribestar.adult/*` | Access SubscribeStar Adult cookies | +| `*://*.hentai-foundry.com/*` | Access Hentai-Foundry cookies | +| `*://*.discord.com/*` | Monitor Discord API for token capture | + +## API Endpoints Used + +The extension communicates with these GallerySubscriber backend endpoints: + +| Endpoint | Method | Purpose | +|----------|--------|---------| +| `/api/health` | GET | Connection test | +| `/api/credentials` | POST | Upload cookies/tokens | + +## Troubleshooting + +### Extension shows "Setup Required" +- Open settings and configure the API URL and key +- Ensure the backend is running and accessible + +### Connection test fails +- Verify the API URL is correct (include protocol, e.g., `http://`) +- Check that the backend is running +- Verify the API key matches the one in GallerySubscriber settings + +### "No cookies found" for a platform +- Ensure you're logged into the platform in Firefox +- Try logging out and back in +- Clear cookies and re-authenticate + +### Discord token not captured +- Open discord.com in Firefox (not the desktop app) +- Interact with Discord (switch channels, scroll, etc.) +- The token is captured from API requests automatically + +### Popup is blank or slow +- Check the browser console for errors (`about:debugging` → Inspect) +- The extension caches connection status for 2 minutes to improve performance + +## Privacy & Security + +- Cookies and tokens are sent only to your configured backend URL +- No data is sent to third parties +- API key is stored locally in browser storage +- Discord tokens are stored locally and only sent to your backend when you export + +## Version History + +### 1.0.0 +- Initial release +- Support for Patreon, SubscribeStar, Hentai-Foundry, Discord +- Dark/light theme support +- Connection caching for improved performance diff --git a/extension/RELEASE_NOTES.md b/extension/RELEASE_NOTES.md new file mode 100644 index 0000000..e0043b0 --- /dev/null +++ b/extension/RELEASE_NOTES.md @@ -0,0 +1,74 @@ +# GallerySubscriber Extension - Release Notes + +## Version 1.0.0 + +**Release Date:** January 2026 + +### Overview + +Initial release of the GallerySubscriber browser extension for Firefox. This extension streamlines the process of exporting authentication credentials from supported platforms to your self-hosted GallerySubscriber backend, enabling automated content downloading via gallery-dl. + +### Features + +#### Multi-Platform Cookie Export +- **Patreon** - Export session cookies for accessing patron-only content +- **SubscribeStar** - Support for both .com and .adult domains +- **Hentai-Foundry** - Export authentication cookies for mature content access + +#### Discord Token Capture +- Automatic authorization token capture from Discord API requests +- No manual token entry required - just use Discord in your browser +- Secure local storage with timestamp tracking + +#### User Interface +- Clean, modern popup interface for quick access +- Real-time platform status indicators showing cookie/token availability +- One-click export for individual platforms or bulk export all at once +- Connection status indicator showing backend connectivity + +#### Theme Support +- Automatic light/dark theme matching system preferences +- Uses CSS custom properties for consistent theming +- Seamless appearance across popup and options pages + +#### Performance Optimizations +- Connection test caching (2-minute interval) to reduce API calls +- Non-blocking UI - interface loads immediately while data fetches in background +- Efficient background script initialization + +#### Configuration +- Simple setup via options page +- Secure API key authentication with your GallerySubscriber backend +- Connection test to verify setup before use + +### Technical Details + +- **Manifest Version:** 2 +- **Minimum Firefox Version:** 57+ +- **Permissions Required:** + - `cookies` - Read authentication cookies from supported sites + - `storage` - Store configuration and captured tokens + - `webRequest` - Monitor Discord API for token capture + - Host permissions for supported platforms + +### Installation + +1. Download `gallerysubscriber-signed.xpi` +2. Open Firefox and navigate to `about:addons` +3. Click the gear icon and select "Install Add-on From File" +4. Select the downloaded .xpi file +5. Click the extension icon and configure your backend URL and API key + +### Known Limitations + +- Discord token capture requires using Discord in the browser (not the desktop app) +- Cookies must be refreshed if you log out and back into platforms +- Token-based platforms other than Discord require manual configuration in the web UI + +### Support + +For issues, feature requests, or contributions, please visit the project repository. + +--- + +*GallerySubscriber Extension is designed for personal use with self-hosted GallerySubscriber instances.* diff --git a/extension/manifest.json b/extension/manifest.json index e215e4d..63b2961 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -4,6 +4,12 @@ "version": "1.0.0", "description": "Export cookies from supported platforms to GallerySubscriber for automated downloads", + "browser_specific_settings": { + "gecko": { + "id": "gallerysubscriber@fabledsword.com" + } + }, + "permissions": [ "cookies", "storage", diff --git a/frontend/src/views/Settings.vue b/frontend/src/views/Settings.vue index 32f4e51..a45606a 100644 --- a/frontend/src/views/Settings.vue +++ b/frontend/src/views/Settings.vue @@ -288,7 +288,7 @@ Version - 1.0.0 + {{ systemInfo.version }} API Status @@ -298,19 +298,90 @@ + + Python Version + {{ systemInfo.python_version }} + + + Gallery-dl Version + + + {{ systemInfo.gallery_dl_version }} + + + Download Path - /data/downloads + {{ systemInfo.download_path }} + + + Config Path + {{ systemInfo.config_path }} + + + + +

+ mdi-package-variant + Dependencies +

+ + + + + Package + Version + + + + + {{ name }} + + + {{ version }} + + + + + + + + {{ showAllPackages ? 'mdi-chevron-up' : 'mdi-chevron-down' }} + {{ showAllPackages ? 'Hide' : 'Show' }} all packages ({{ Object.keys(systemInfo.all_packages || {}).length }}) + + + +
+ + + + Package + Version + + + + + {{ name }} + {{ version }} + + + +
+