Skip to content

About

Youtube curated timeline

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

Β 

History

311 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

YT Clear View (YTCV)


Release Docker License

Python Flask SQLAlchemy SQLite Gunicorn Caddy

YouTube Data API v3 Google OAuth 2.0 JavaScript HTML5 CSS3


Leer en EspaΓ±ol

Your YouTube channels, zero noise 🎯

Hey! I’m GOTXE πŸ‘‹, and YTCV came from something very simple: I would open YouTube with a clear mission... and end up somewhere else πŸ˜…

That is not necessarily bad. Discovering new things is great. But many times I wanted the opposite: open, check my subscriptions, catch up, and move on with my day πŸš€

So I built this app for myself, and now I’m sharing it in case it helps you too.

YTCV is a self-hosted viewer to see only what matters to you: your subscriptions, in chronological order, with a clean, direct, no-nonsense experience ✨

And remember: the real enemy is not the algorithm, it is procrastination. You are in control πŸ’ͺ

[!IMPORTANT] IMPORTANT Do not forget the YouTubers you like. They still need your direct support (subscriptions, likes, comments, merch, etc.) to keep creating quality content. Also use the official YouTube app for that and support your favorite creators.

Index

What does YTCV do?

  • Imports your subscriptions with Google OAuth + YouTube Data API v3.
  • Shows videos in real chronological order (as it should be 🫑).
  • Lets you filter watched/unwatched and organize by categories.
  • After first Google login, you create your local DB user so you can log in from any device with that user, without using Google again.
  • Runs in containers (backend + proxy), ideal for self-hosting.

Screenshots

Main app

YTCV login Main web view Playback in YTCV

Admin panel

Admin panel - view 1 Admin panel - view 2 Admin panel - view 3

Usage

The recommended way is Docker Compose.

Storage modes (choose one):

  1. Docker named volumes (no host folder management)
  • No need to create host folders.
  • Compose uses Docker-managed volumes (ytcv_data, ytcv_logs).
  1. Host persistent folders (recommended on Synology)
  • Create host folders, for example:
/volume1/docker/ytclearview/
  β”œβ”€ data/
  └─ logs/
  • Then map them as bind mounts in compose:
services:
  backend:
    volumes:
      - /volume1/docker/ytclearview/data:/data
      - /volume1/docker/ytclearview/logs:/logs

Release and images:

docker pull ghcr.io/gotxe/ytcv-backend:v0.13.0
docker pull ghcr.io/gotxe/ytcv-proxy:v0.13.0

1) Prepare Google Cloud (quick searches)

Before launching YTCV, prepare this in Google Cloud. Here are direct searches:

2) Standard install (normal use)

No local build, using GHCR images.

Step A: prepare your .env

Templates:

You have two options:

  1. If you cloned the full repo:
cp backend/.env.prod.example backend/.env
  1. If you did NOT clone the repo (for example, you use your own docker-compose.yml):
  • Create a .env file in the same folder as your compose file.
  • Fill it with the required variables.
FLASK_SECRET_KEY=put_a_long_unique_secret_here
AUTH_MODE=google
YT_API_KEY=your_youtube_api_key
GOOGLE_CLIENT_ID=your_client_id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your_client_secret
GOOGLE_REDIRECT_URI=http://localhost:5550/api/auth/google/callback
FRONTEND_URL=http://localhost:8080
CORS_ORIGINS=http://localhost:8080,http://localhost:5550

Options for GOOGLE_REDIRECT_URI FRONTEND_URL CORS_ORIGINS (choose one):

  1. Localhost (no HTTPS)
  • GOOGLE_REDIRECT_URI=http://localhost:5550/api/auth/google/callback
  • Use this when everything runs on the same machine (browser + containers).
  • It is the simplest local option. Google OAuth logins work fine with localhost without HTTPS. You will need to do Google login on that device first. After that first login, you can log in from any device with your local user without going through Google OAuth again.
  1. External domain (with HTTPS)
  • GOOGLE_REDIRECT_URI=https://your-domain/api/auth/google/callback
  • Use this when you access from other devices or outside your local network.
  • Google OAuth for web apps works reliably with a public hostname and HTTPS.
  • In this scenario, also adjust these:
    • FRONTEND_URL=https://your-domain
    • CORS_ORIGINS=https://your-domain
  • If frontend and API live on different domains, add both origins in CORS_ORIGINS:
    • CORS_ORIGINS=https://your-frontend,https://your-api

Minimum required values before starting Docker Compose:

  • FLASK_SECRET_KEY
  • AUTH_TOKEN_ENCRYPTION_KEY
  • YT_API_KEY
  • GOOGLE_CLIENT_ID
  • GOOGLE_CLIENT_SECRET
  • GOOGLE_REDIRECT_URI
  • FRONTEND_URL
  • CORS_ORIGINS

Generate secrets with Python:

python3 -c "import secrets; print(secrets.token_urlsafe(64))"
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

Step B: start with your compose

The stack runs:

  • backend: Flask API
  • proxy: frontend + reverse proxy on http://localhost:8080

Example if you use the repo (infra/compose/compose.yaml):

YTCV_TAG=v0.13.0 docker compose -f infra/compose/compose.yaml up -d

You can customize startup with variables:

  • YTCV_TAG: image version (v0.13.0, latest, etc.).
  • YTCV_HTTP_PORT: public port (default 8080).

Examples:

# Port 8090
YTCV_TAG=v0.13.0 YTCV_HTTP_PORT=8090 docker compose -f infra/compose/compose.yaml up -d

Basic equivalent compose example (if you want your own):

services:
  backend:
    image: ghcr.io/gotxe/ytcv-backend:${YTCV_TAG:-latest}
    env_file:
      - ./.env
    environment:
      AUTH_MODE: google
      DATABASE_URI: sqlite:////data/youtube_clear_view.db
    volumes:
      - ytcv_data:/data
      - ytcv_logs:/logs

  proxy:
    image: ghcr.io/gotxe/ytcv-proxy:${YTCV_TAG:-latest}
    depends_on:
      - backend
    ports:
      - "${YTCV_HTTP_PORT:-8080}:8080"

volumes:
  ytcv_data:
  ytcv_logs:

Open:

  • http://localhost:8080
  • https://your-domain (if using external domain)

First access (recommended flow)

  1. Open the main web app:
  • http://localhost:8080 (local)
  • https://your-domain (external domain)
  1. Complete the first login with Google (OAuth).

  2. Complete the initial wizard:

  • create/configure your local app user,
  • finish initial setup so you can sign in from other devices without repeating Google OAuth every time.

IMPORTANT: On first boot (fresh database), admin/user bootstrap can take noticeably longer than a normal login. Wait until the wizard fully completes before retrying or refreshing.

  1. Access admin panel when needed:
  • http://localhost:8080/gestor/
  • https://your-domain/gestor/

Login from other devices (passkey or code)

After first access and initial setup, you can sign in from other devices using:

  1. Passkey (WebAuthn)
  • Best for phones, laptops, and compatible browsers.
  • Flow: on the new device choose passkey login and complete biometric/PIN verification.
  1. Pairing code
  • Best for TV or devices with uncomfortable text input.
  • Flow: new device shows a code, you approve it from an already authenticated device, and the new device signs in.

Note:

  • First account bootstrap still starts with Google OAuth.
  • After that, these methods avoid repeating OAuth on every device.

3) DEV mode (for touching code with coffee β˜• and faith πŸ™)

Local build from repo for development and PRs.

cp backend/.env.dev.example backend/.env
# Edit backend/.env
./scripts/dev_docker.sh up --mode dev --build

Equivalent command:

docker compose -f infra/compose/compose.yaml -f infra/compose/compose.dev.yaml up -d --build

Useful commands

# Change public port
YTCV_HTTP_PORT=8081 YTCV_TAG=v0.13.0 docker compose -f infra/compose/compose.yaml up -d

# Update standard install
YTCV_TAG=v0.13.0 docker compose -f infra/compose/compose.yaml pull
YTCV_TAG=v0.13.0 docker compose -f infra/compose/compose.yaml up -d

# Rebuild proxy only (frontend)
./scripts/dev_docker.sh up --mode dev --build proxy

# Stop dev stack
./scripts/dev_docker.sh down --mode dev

[!TIP] SUPER IMPORTANT For frontend devs: watch browser cache. If you change frontend and do not bump CACHE_VERSION in frontend/sw.js, your browser may keep serving the old frontend from cache and make you think your changes did not work. Always rebuild proxy and bump CACHE_VERSION after frontend changes. The web app has a service worker and JS update notice. Click to load the new version. Otherwise, the browser may serve an old version and drive you crazy πŸ™ƒ

OAuth without headaches

You have two paths:

  1. localhost callback (everything on same machine)
  • http://localhost:5550/api/auth/google/callback
  1. External domain callback (multi-device Google login)
  • https://your-domain/api/auth/google/callback

Important:

  • Avoid LAN IP callback over HTTP for Google OAuth.
  • If it is not localhost, use HTTPS.

Troubleshooting

  • OAuth callback error:
    • GOOGLE_REDIRECT_URI must match exactly in Google Cloud Console and backend/.env.
  • Port already in use:
    • change YTCV_HTTP_PORT.
  • Backend is β€œhealthy” but you cannot log in:
    • check AUTH_MODE=google, OAuth credentials, and consistency between FRONTEND_URL and CORS_ORIGINS. Also make sure you completed admin user setup and local DB user login (created after first Google login).
  • Locked out after failed logins (423 error):
    • after 5 failed password attempts an account is locked for 15 minutes. Wait it out, or restart the backend to lift the lock sooner.
  • Forgot the admin/gestor password:
    • set ADMIN_RESET_PASSWORD=true in backend/.env, restart the backend, and check the backend logs β€” a new temporary password is generated for every admin account and printed there (you must change it on next login). Remove the variable and restart again once you are back in.
    • if you need to demote/disable all existing admins instead and go through the bootstrap wizard again, use ADMIN_FORCE_RESET=true (destructive: it disables all current admin accounts).
  • Forgot a normal user's password:
    • an admin can set a temporary password for that user from the admin panel (Gestor β†’ users β†’ reset password). If no admin account is reachable, use the admin password reset above first.

Documentation

🚧 W.I.P.: still under construction, but you can already take a look πŸ‘€ If you find anything weird or have questions, open an issue πŸ“Ž

Support

Bug? πŸ› Improvement idea? πŸ’‘

  • Open a GitHub issue.
  • Include version (v0.13.0 or tag), environment, and reproduction steps.

Legal notice

YTCV is an independent project and is not affiliated with YouTube/Google. It uses the official YouTube Data API v3 and follows its terms of use.

Your use of YTCV is your responsibility. Make sure you comply with Google and YouTube policies when using this tool.

And of course, YTCV and its author/developer are not responsible for any damage, data loss, or productivity addiction that may result from using this application. Use it in moderation and enjoy your distraction-free experience.

License

MIT. See LICENSE.

About

Youtube curated timeline

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages