# jpaulovaz/ersatztv-youtube-playlist-generator architecture

> Architecture diagram of the GitHub repository jpaulovaz/ersatztv-youtube-playlist-generator, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-28). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/jpaulovaz/ersatztv-youtube-playlist-generator
- Repository: https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator

## Overview

ErsatzTV YouTube Downloader discovers videos and channel sources, deduplicates them by destination, persists a shared download queue, and produces library-ready media. The web UI and schedulers initiate library and channel workflows; channel catalog and synchronization are distinct from library discovery. Download processing also supports subtitles, metadata, profiles, retries, and orphan management. ErsatzTV catalog, scan, and Smart Collection features are documented, but their full wiring was not sampled; their nodes use supported enclosing paths and uncertain links are omitted.

Main entry points: [`src/downloadManager.js`](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/downloadManager.js) (Download manager), [`src/server.js`](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/server.js) (HTTP server), [`src/discovery/channelSyncService.js`](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/discovery/channelSyncService.js) (Channel sync), [`src/syncService.js`](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/syncService.js) (Library discovery)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_ui["Web interface"]
  node_web["Dashboard UI<br/>[app.js]"]
  node_channelui["Channel UI<br/>[channelsView.js]"]
end

subgraph group_discovery["Discovery and sync"]
  node_librarysync["Library discovery<br/>[syncService.js]"]
  node_channelsync["Channel sync"]
  node_catalog["Channel catalog"]
  node_provider["YouTube provider"]
end

subgraph group_downloads["Queue and media"]
  node_manager["Download manager<br/>[downloadManager.js]"]
  node_selector["Worker selection<br/>[workerSelector.js]"]
  node_queue[("Persistent queue<br/>[queueState.js]")]
  node_profiles["Media profiles"]
  node_metadata["Media metadata"]
  node_subtitles["Subtitle processing<br/>[subtitleService.js]"]
end

subgraph group_integrations["External services"]
  node_youtubeapi["YouTube API<br/>[youtubeApi.js]"]
  node_ytdlp["yt-dlp"]
  node_ffmpeg["FFmpeg tools"]
  node_ersatztv["ErsatzTV<br/>[ersatztvService.js]"]
end

node_operator(("Administrator"))
node_server["HTTP server<br/>[server.js]"]
node_channelroutes["Channel routes<br/>[channelRoutes.js]"]
node_libraryroutes["Library routes<br/>[libraryRoutes.js]"]
node_ersatztvroutes["ErsatzTV routes<br/>[ersatztvRoutes.js]"]
node_auth["Local authentication<br/>[auth.js]"]
node_config["Configuration<br/>[config.js]"]
node_scheduler["Library scheduler<br/>[scheduler.js]"]
node_channelscheduler["Channel scheduler"]
node_mediafiles[("Library media")]
node_librarytimer["Library timer<br/>[main.js]"]
node_channeltimer["Channel timer<br/>[main.js]"]

node_operator -->|"uses"| node_web
node_web -->|"requests"| node_server
node_channelui -->|"requests"| node_server
node_server -->|"authenticates"| node_auth
node_server -->|"dispatches"| node_channelroutes
node_server -->|"dispatches"| node_libraryroutes
node_server -->|"dispatches"| node_ersatztvroutes
node_server -->|"loads config"| node_config
node_libraryroutes -->|"starts discovery"| node_librarysync
node_channelroutes -->|"analyzes channel"| node_catalog
node_channelroutes -->|"starts sync"| node_channelsync
node_librarysync -->|"fetches sources"| node_provider
node_catalog -->|"queries API"| node_youtubeapi
node_catalog -.->|"falls back"| node_provider
node_channelsync -->|"refreshes catalog"| node_catalog
node_channelsync -->|"fetches destination"| node_provider
node_librarysync -->|"queues videos"| node_manager
node_channelsync -->|"queues videos"| node_manager
node_manager -->|"persists state"| node_queue
node_manager -->|"selects work"| node_selector
node_manager -->|"downloads"| node_ytdlp
node_manager -->|"processes media"| node_ffmpeg
node_manager -->|"applies profile"| node_profiles
node_manager -->|"writes metadata"| node_metadata
node_manager -->|"handles subtitles"| node_subtitles
node_manager -->|"writes files"| node_mediafiles
node_scheduler -->|"triggers discovery"| node_librarysync
node_channelscheduler -->|"triggers sync"| node_channelsync
node_librarytimer -->|"starts"| node_scheduler
node_librarytimer -->|"starts"| node_channelscheduler
node_ersatztvroutes -->|"checks and links"| node_ersatztv
node_ersatztv -.->|"scans library"| node_mediafiles
node_ersatztv -.->|"returns catalog"| node_web

click node_web "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/public/app.js"
click node_channelui "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/public/js/channelsView.js"
click node_server "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/server.js"
click node_channelroutes "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/routes/channelRoutes.js"
click node_libraryroutes "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/routes/libraryRoutes.js"
click node_ersatztvroutes "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/routes/ersatztvRoutes.js"
click node_auth "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/auth.js"
click node_config "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/config.js"
click node_librarysync "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/syncService.js"
click node_channelsync "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/discovery/channelSyncService.js"
click node_catalog "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/discovery/channelCatalogService.js"
click node_provider "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/discovery/youtubeSourceProvider.js"
click node_youtubeapi "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/youtubeApi.js"
click node_scheduler "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/scheduler.js"
click node_channelscheduler "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/channelScheduler.js"
click node_manager "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/downloadManager.js"
click node_selector "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/download/workerSelector.js"
click node_queue "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/download/queueState.js"
click node_profiles "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/mediaProfileService.js"
click node_metadata "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/movieMetadataService.js"
click node_subtitles "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/subtitleService.js"
click node_ersatztv "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/ersatztvService.js"
click node_librarytimer "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/main.js"
click node_channeltimer "https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/main.js"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_web,node_channelui toneBlue
class node_librarysync,node_channelsync,node_catalog,node_provider,node_mediafiles toneAmber
class node_manager,node_selector,node_queue,node_profiles,node_metadata,node_subtitles,node_server,node_channelroutes,node_libraryroutes,node_ersatztvroutes toneMint
class node_youtubeapi,node_ytdlp,node_ffmpeg,node_ersatztv,node_scheduler,node_channelscheduler toneRose
class node_operator toneIndigo
class node_auth,node_config,node_librarytimer,node_channeltimer toneTeal
```

## Components

### Web interface

- [Dashboard UI](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/public/app.js): `public/app.js`
- [Channel UI](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/public/js/channelsView.js): `public/js/channelsView.js`

### Discovery and sync

- [Library discovery](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/syncService.js): `src/syncService.js`
- [Channel sync](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/discovery/channelSyncService.js): `src/discovery/channelSyncService.js`
- [Channel catalog](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/discovery/channelCatalogService.js): `src/discovery/channelCatalogService.js`
- [YouTube provider](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/discovery/youtubeSourceProvider.js): `src/discovery/youtubeSourceProvider.js`

### Queue and media

- [Download manager](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/downloadManager.js): `src/downloadManager.js`
- [Worker selection](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/download/workerSelector.js): `src/download/workerSelector.js`
- [Persistent queue](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/download/queueState.js): `src/download/queueState.js`
- [Media profiles](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/mediaProfileService.js): `src/mediaProfileService.js`
- [Media metadata](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/movieMetadataService.js): `src/movieMetadataService.js`
- [Subtitle processing](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/subtitleService.js): `src/subtitleService.js`

### External services

- [YouTube API](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/youtubeApi.js): `src/youtubeApi.js`
- **yt-dlp**
- **FFmpeg tools**
- [ErsatzTV](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/ersatztvService.js): `src/ersatztvService.js`

### Other components

- **Administrator**
- [HTTP server](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/server.js): `src/server.js`
- [Channel routes](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/routes/channelRoutes.js): `src/routes/channelRoutes.js`
- [Library routes](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/routes/libraryRoutes.js): `src/routes/libraryRoutes.js`
- [ErsatzTV routes](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/routes/ersatztvRoutes.js): `src/routes/ersatztvRoutes.js`
- [Local authentication](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/auth.js): `src/auth.js`
- [Configuration](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/config.js): `src/config.js`
- [Library scheduler](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/scheduler.js): `src/scheduler.js`
- [Channel scheduler](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/channelScheduler.js): `src/channelScheduler.js`
- **Library media**
- [Library timer](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/main.js): `src/main.js`
- [Channel timer](https://github.com/jpaulovaz/ersatztv-youtube-playlist-generator/blob/main/src/main.js): `src/main.js`

## Connections

- Administrator → Dashboard UI: uses
- Dashboard UI → HTTP server: requests
- Channel UI → HTTP server: requests
- HTTP server → Local authentication: authenticates
- HTTP server → Channel routes: dispatches
- HTTP server → Library routes: dispatches
- HTTP server → ErsatzTV routes: dispatches
- HTTP server → Configuration: loads config
- Library routes → Library discovery: starts discovery
- Channel routes → Channel catalog: analyzes channel
- Channel routes → Channel sync: starts sync
- Library discovery → YouTube provider: fetches sources
- Channel catalog → YouTube API: queries API
- Channel catalog → YouTube provider: falls back
- Channel sync → Channel catalog: refreshes catalog
- Channel sync → YouTube provider: fetches destination
- Library discovery → Download manager: queues videos
- Channel sync → Download manager: queues videos
- Download manager → Persistent queue: persists state
- Download manager → Worker selection: selects work
- Download manager → yt-dlp: downloads
- Download manager → FFmpeg tools: processes media
- Download manager → Media profiles: applies profile
- Download manager → Media metadata: writes metadata
- Download manager → Subtitle processing: handles subtitles
- Download manager → Library media: writes files
- Library scheduler → Library discovery: triggers discovery
- Channel scheduler → Channel sync: triggers sync
- Library timer → Library scheduler: starts
- Library timer → Channel scheduler: starts
- ErsatzTV routes → ErsatzTV: checks and links
- ErsatzTV → Library media: scans library
- ErsatzTV → Dashboard UI: returns catalog
