- JavaScript 85.8%
- Python 7.5%
- CSS 4.5%
- Nix 1.7%
- HTML 0.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
Build and Push Attic Cache / build (push) Successful in 25s
|
||
| .forgejo | ||
| .github | ||
| bdfr-patches | ||
| downloaders | ||
| lib | ||
| nix | ||
| public | ||
| routes | ||
| scripts | ||
| tests | ||
| .dockerignore | ||
| .gitignore | ||
| AGENTS.md | ||
| db.js | ||
| docker-compose.amd.yml | ||
| docker-compose.local.yml | ||
| docker-compose.nvidia.yml | ||
| docker-compose.override.yml | ||
| Dockerfile.amd | ||
| Dockerfile.cpu | ||
| Dockerfile.nvidia | ||
| flake.lock | ||
| flake.nix | ||
| LICENSE | ||
| openapi.base.json | ||
| package-lock.json | ||
| package.json | ||
| paseo.json | ||
| pyrightconfig.json | ||
| README.md | ||
| report.md | ||
| requirements-amd-torch.txt | ||
| requirements-amd.txt | ||
| requirements-cpu.txt | ||
| requirements.txt | ||
| scanner.js | ||
| server.js | ||
| tagger-amd.py | ||
| tagger.py | ||
| THIRD-PARTY-NOTICES | ||
redview
An offline Reddit media viewer. Browse, slideshow, and tag images and videos downloaded via BDFR or similar tools.
Features
- Gallery — infinite-scroll grid with search, sorting (newest/oldest/A–Z/random), and active tag filters
- Slideshow — auto-advances through images (configurable duration) and plays videos to completion
- Browse by subreddit / poster — sortable by image count or alphabetically; cross-reference modals show which subreddits a user posts in (or which users post in a subreddit), with inline favourite toggles
- Tag browser — autocomplete search, multi-select tag filters, top-tags grid sortable by count or A–Z
- Favourites — mark images, users, and subreddits as favourites; bulk-import favourite subreddits or users from a
.txtfile - Block — hide all content from a poster or subreddit; block/unblock from the list view or slideshow; purge blocked content from disk
- Delete — remove an image from disk directly from the slideshow
- GPU tagging — WD-ViT Tagger v3 (Danbooru-trained) via ONNX Runtime; tags untagged images or reprocesses everything; videos are tagged via 5 evenly-spaced frames (extracted with ffmpeg) with the tag list merged and deduplicated; batch size auto-detected from available VRAM
- BDFR Rip — trigger BDFR downloads from within the app; automatically rips all favourited subreddits and users, respecting block lists
- Auto-scan — configurable folder watch interval
Requirements
- NixOS with the native flake module (recommended), or Docker + Docker Compose
- For native NVIDIA deployments, a NixOS NVIDIA driver configuration
- AMD GPU with ROCm support (
/dev/kfd,/dev/dri) for the legacy AMD Compose configuration (see Setup)
Setup
The native NixOS deployment is the supported production path. Docker Compose files remain available for local or legacy deployments; build their images locally because this project no longer publishes Docker images. For NixOS, see Native NixOS deployment.
1. Clone the repo
git clone <repo-url>
cd redview
2. Configure environment
Create a .env file:
NAS_IP=192.168.1.100
NAS_MEDIA_PATH=/volume1/your/share
HF_TOKEN= # optional — only needed for gated HuggingFace models
The compose file mounts an NFS share using NAS_IP and NAS_MEDIA_PATH. To use a local path instead, remove the NFS volume block and bind-mount directly:
volumes:
- /path/to/your/media:/media
3. Start
Use the compose file matching your GPU:
# AMD
docker compose -f docker-compose.amd.yml up -d
# NVIDIA
docker compose -f docker-compose.nvidia.yml up -d
The app is available at http://localhost:3210.
Native NixOS deployment
The flake exports a native NixOS module. It runs Node.js and the Python workers directly under systemd; no container runtime is involved. Add the repository as a flake input and enable the service in a host configuration:
{
inputs.redview.url = "git+ssh://git@git.nimmog.uk/nimmo/redview";
# In nixosConfigurations.<host>.modules:
({ pkgs, ... }: let
redviewNvidia =
inputs.redview.packages.${pkgs.stdenv.hostPlatform.system}.redview-nvidia;
in {
imports = [ inputs.redview.nixosModules.default ];
services.redview = {
enable = true;
accelerator = "nvidia";
mediaDir = "/mnt/media";
package = redviewNvidia;
pythonEnvironment = redviewNvidia.passthru.pythonEnvironment;
};
})
}
The module creates a dedicated service account and persistent directories for
the database, model cache, media, and BDFR configuration. cpu uses the
default nixpkgs ONNX Runtime environment. For amd, provide a Python
environment containing the native AMD TheRock torch/torchvision wheels plus
onnx, onnx2torch, Pillow, NumPy, and Hugging Face Hub. For nvidia,
provide an environment containing onnxruntime-gpu and its CUDA runtime.
environmentFiles or environment.HF_TOKEN can provide optional Hugging
Face authentication.
The native package is built on commits to main and pushed to the shared
nixos Attic cache. The default redview package is the CPU application;
redview-nvidia is the CUDA runtime bundle for an RTX 4070 (SM 8.9), including
the Python tagging and BDFR environment used by Lyra. Consumers need the cache
configured, for example:
{
nix.settings = {
substituters = [ "https://attic.nimmog.uk/nixos" ];
trusted-public-keys = [ "nixos:tNn8ouVBQkqLS2qTq86V50TCL1AGn2NgwEhpxReo6jU=" ];
};
}
Docker (legacy): the supplied Compose files build their local image. Start them with
docker compose -f docker-compose.nvidia.yml up --build -d(or substitutedocker-compose.amd.yml).
First run
- Go to Settings → add
/media(or a subfolder) as a gallery folder - Click Scan All Folders Now — indexes all media into the database
- Optionally go to Settings → Image Tagging → click Tag Untagged Images to run the GPU tagger
The tagger downloads the WD-ViT Tagger v3 model (~350 MB) on first use and caches it in the redview-data directory.
File naming convention
Filenames are expected to follow the BDFR format:
REDDITOR__post-title__postID.ext
The poster name is parsed from everything before the first __ (double underscore). Subreddits are inferred from the subfolder name within the library root.
Environment variables
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
Internal server port |
DATA_DIR |
/data |
Database and model cache location |
TAG_THRESHOLD |
0.35 |
Minimum confidence for a tag to be kept (0–1) |
TAG_BATCH_SIZE |
auto | Override auto-detected GPU batch size |
TAG_VIDEO_FRAMES |
5 |
Frames extracted per video (evenly spaced) for tagging |
HF_TOKEN |
— | HuggingFace token for gated model access |
REDDIT_ACCESS_TOKEN |
— | Optional Reddit OAuth bearer-token override for fetching subreddit descriptions. By default Redview reuses BDFR's authenticated OAuth configuration from ~/.config/bdfr. |
BDFR_CONFIG_PATH |
BDFR's config.cfg or default_config.cfg |
Optional path to BDFR's OAuth configuration file when it is not in the standard location |
Large library tag index
For a large, existing database, build the covering tag filter index once during a maintenance window. Stop Redview's writers first and allow room for SQLite to build the index. Supply the actual database path explicitly:
npm run db:index-tags -- --db /var/lib/redview/redview.db
The command verifies the index and is safe to run again. SQLite stores it in
redview.db, so it survives service restarts and does not rebuild at startup.
Normal startup does not create this optional index on an existing library.
API
All endpoints are available at http://localhost:3210. Useful for external tools (e.g. BDFR post-processing scripts).
Authentication
All API and media endpoints require an X-Api-Key header (or ?api_key= query parameter). The key is generated on first start and shown in the server logs. It can also be found in Settings → API Key.
curl -s http://localhost:3210/api/favourites \
-H 'X-Api-Key: your-key-here'
Favourites
| Method | Endpoint | Body / Query | Description |
|---|---|---|---|
GET |
/api/favourites |
?type=subreddit|poster |
List all favourites (optionally filtered by type) |
POST |
/api/favourites |
{ type, value } |
Add a single favourite |
DELETE |
/api/favourites |
{ type, value } |
Remove a single favourite |
POST |
/api/favourites/bulk |
{ type, values: [] } |
Add multiple favourites (duplicates ignored) |
Blocked
| Method | Endpoint | Body / Query | Description |
|---|---|---|---|
GET |
/api/blocked |
— | List all blocked entries |
POST |
/api/blocked |
{ type, value } |
Block a single user or subreddit |
DELETE |
/api/blocked |
{ type, value } |
Unblock by type and value |
DELETE |
/api/blocked/:id |
— | Unblock by entry ID |
POST |
/api/blocked/bulk |
{ type, values: [] } |
Block multiple entries (duplicates ignored) |
GET |
/api/blocked/purge |
— | Preview purge: returns counts of files that would be deleted |
POST |
/api/blocked/purge |
— | Delete all files belonging to blocked users/subreddits from disk and database |
type is "subreddit" or "poster" in all cases.
Cross-reference
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/posters/:poster/subreddits |
Subreddits a user has media in, with counts and favourite status |
GET |
/api/subreddits/:subreddit/posters |
Users who have media in a subreddit, with counts and favourite status |
Examples
Mark a list of subreddits as favourites:
curl -s -X POST http://localhost:3210/api/favourites/bulk \
-H 'X-Api-Key: your-key-here' \
-H 'Content-Type: application/json' \
-d '{"type":"subreddit","values":["pics","videos","aww"]}'
List all favourite subreddits:
curl -s http://localhost:3210/api/favourites?type=subreddit \
-H 'X-Api-Key: your-key-here'
Stack
- Backend — Node.js, Express, better-sqlite3 (SQLite WAL mode); routes split across
routes/by domain - Frontend — Vanilla JS SPA, no build step
- Tagger (NVIDIA) — Python, native ONNX Runtime CUDA bundle, built for SM 8.9
- Tagger (AMD) — Python, PyTorch ROCm via TheRock, ONNX Runtime, Pillow, HuggingFace Hub; base image
ubuntu:24.04
Licence
Copyright (c) 2026 Redview contributors. Licensed under the EUPL-1.2.
Redview's original code is licensed under the European Union Public Licence 1.2 (EUPL-1.2).
This repository also contains or builds with third-party software that remains under its own licence. See THIRD-PARTY-NOTICES for the important exceptions, including the GPLv3 BDFR integration and the Apache-2.0 WD-ViT model downloaded at runtime.