Files
siftlode/README.md
T
peter 688efb9ed6 feat(selfhost): license the repo, and make Plex actually usable on the public compose files
DX-10: the repo invited people to clone, build and self-host while carrying
no LICENSE at all — which legally means all rights reserved, so none of that
was permitted. Adds the verbatim GNU AGPL-3.0 text, the SPDX id in
package.json and a README section. AGPL rather than MIT deliberately: this is
a server application, so the case worth covering is someone running a
modified copy as a network service.

DX-12: .env.example documented PLEX_MEDIA_HOST_PATH -> /plex-media and the
README advertised the Plex library, but only the localdev and home compose
files carried the mount — on both PUBLIC files the module could read Plex's
catalogue and then fail to open a single file, because it streams the media
itself rather than proxying Plex. Both api and worker now mount it read-only
with an empty named volume as the fallback, and self-hosting.md gains the
section that explains the server URL/token, the path map and the mount
together (it had never mentioned Plex).

DX-15: the worker had no init: true on either public file, though localdev
and home both carry tini with the reason written out — without PID 1 reaping,
a watchdog hard-kill of a download's process group orphans its ffmpeg/yt-dlp
grandchildren.

Verified: 'compose config' resolves on both files, the Plex mount comes out
read_only: true on api and worker, and init lands on worker (not just the
bgutil-pot sidecar). Gate green: vitest 671, pytest 896.
2026-09-05 00:53:26 +02:00

130 lines
6.4 KiB
Markdown

# Siftlode
**Your YouTube subscriptions, the way a feed should work.** Siftlode pulls every upload from the
channels you follow into one clean, filterable feed — no algorithm deciding what you see, and no
Shorts or livestream noise unless you want it. Self-hosted, multi-user, and private: your data
stays on your own server.
![Siftlode feed](frontend/public/welcome/feed.webp)
Everything expensive (channels, videos, metadata) is fetched from YouTube once and stored locally,
so filtering, searching and sorting are instant and don't burn API quota. Click a video to watch it
in an in-app player that resumes where you left off — or open it on youtube.com so your own ad
blocker and SponsorBlock keep working.
## Features
- **A readable subscription feed** — sort and filter by channel, tag, language, topic, length,
upload date or watch state; hide channels without unsubscribing; save filter setups as named views.
- **Search all of YouTube** from the feed — live results you can play, save or add to playlists like
any other video; they stay temporary and out of your catalog unless you keep one.
- **Channel pages & a channel manager** — per-channel stats and uploads, priorities, and your own
tags to slice the feed by.
- **Playlists with two-way YouTube sync** — build them locally, keep them in sync in both directions.
- **In-app player** with resume, plus keyboard/scroll controls.
- **Download Center** — save videos to the server with yt-dlp in a Plex-friendly layout (format
presets, per-user storage quota), trim / crop / split & join them in a built-in editor, then save
to your device, share with another user, or hand out a public watch link.
- **Plex library** *(optional)* — point Siftlode at your own Plex server to browse and play its
movies and shows alongside your feed, with watch state kept in sync.
- **Multi-user** with per-user private state, a shared catalog, and a fair daily API-quota guard.
- **Self-hosted & private**, with a first-run web setup wizard and the interface in **English
and Hungarian**.
## Quick start (self-hosting)
You don't need to build anything — Siftlode runs from a prebuilt public image, and all
configuration (your admin account, Google sign-in, email) happens in a **first-run web wizard**.
You need [Docker](https://docs.docker.com/get-docker/) with the Compose plugin.
**1. Get the files and run the installer:**
```sh
git clone https://git.b1fr0st.eu/peter/siftlode.git
cd siftlode
./install.sh # Windows (PowerShell): ./install.ps1
```
The installer generates a private `.env` (secrets), pulls the image, starts the app + database, and
prints a one-time setup URL like `http://localhost:8080/setup?token=…`.
**2. Finish in your browser.** Open that URL and follow the wizard:
1. **Admin account** — the email + password you'll sign in with.
2. **Google sign-in** *(optional)* — paste a Google OAuth client to enable "Sign in with Google" and
pulling your YouTube subscriptions. Skip it to use email + password only.
3. **Email / SMTP** *(optional)* — for verification/notification emails. Skip it and you (the admin)
simply approve new accounts yourself.
Then sign in with your admin account. That's it. See **[docs/self-hosting.md](docs/self-hosting.md)**
for the full walkthrough.
> Just trying it out? Press Enter at the installer's URL prompt to run on `http://localhost:8080`.
## Build from source (alternative)
Prefer to build the image yourself instead of pulling it:
```sh
git clone https://git.b1fr0st.eu/peter/siftlode.git
cd siftlode
cp .env.example .env
# generate the two secrets and paste them into .env:
python -c "import secrets;print('SECRET_KEY='+secrets.token_urlsafe(48))"
python -c "import base64,os;print('TOKEN_ENCRYPTION_KEY='+base64.urlsafe_b64encode(os.urandom(32)).decode())"
docker compose up --build -d # builds from the included Dockerfile
```
Open `http://localhost:8080` and finish in the setup wizard as above. (Set a `POSTGRES_PASSWORD` in
`.env` too.)
## HTTPS / public access
Port `8080` over plain HTTP is fine for a LAN or a quick trial. For public access put a reverse
proxy (Caddy, Nginx, Traefik…) in front to terminate TLS, and set the **public URL** (the installer
prompt, or `OAUTH_REDIRECT_URL` in `.env`) to your `https://…` address — this also marks the session
cookie secure. Add that same `…/auth/callback` URL to your Google OAuth client's authorized redirect
URIs. Behind a proxy, also set `TRUSTED_PROXY_IPS` so the rate limiters see the real client IP and
can't be bypassed via a forged `X-Forwarded-For` — see [docs/self-hosting.md](docs/self-hosting.md#https--public-access).
## Updating & backups
```sh
docker compose -f docker-compose.selfhost.yml pull # or: docker compose pull
docker compose -f docker-compose.selfhost.yml up -d
```
That follows `latest`, which moves with every release. Set `IMAGE_TAG=0.80.0` in `.env` to pin a
version and upgrade on your own schedule; released versions are listed in [`CHANGELOG.md`](CHANGELOG.md)
and in the app's Release Notes.
**Back up before upgrading.** Migrations run automatically on startup and are not undone by pulling
the old image back. A backup is the database dump **plus your `.env`** — `TOKEN_ENCRYPTION_KEY` is
what decrypts the Google, SMTP and Plex secrets stored in that database, so a dump restored without it
is only half an instance. Use `scripts/backup.sh` (or `backup.ps1` on Windows) and `scripts/restore.sh`;
the equivalent one-liners, the pinning recipe and the rollback steps are in
[docs/self-hosting.md](docs/self-hosting.md#backups).
## How it works
- **Shared catalog, private state.** Channels and videos are stored once and shared; each user's
subscriptions, tags, playlists and watch/save/hide state are private.
- **Cheap by design.** Public reads are cached locally; a shared daily quota budget and a background
scheduler keep unattended syncing within YouTube's free API limits. An optional API key lets
backfill run without depending on a user's OAuth token.
## Tech
FastAPI + PostgreSQL (SQLAlchemy, Alembic) backend; React + Vite + Tailwind + TanStack Query
frontend; packaged as a single Docker image with Docker Compose.
## License
[GNU AGPL-3.0](LICENSE). You can run, study, modify and share Siftlode; if you modify it and let other
people use it over a network, they are entitled to your modified source. Copyright © 2026 Siftlode
contributors.
## Note
This project is developed with AI assistance.