Frontend Architecture¶
High-level architecture of the ytdl-go web frontend.
Overview¶
The frontend is a Single Page Application (SPA) built with SolidJS. It compiles to static assets (index.html, app.js, styles.css) that are embedded directly into the Go binary at build time via //go:embed. This means the final distributed artifact is a single, self-contained executable.
Tech Stack¶
| Layer | Technology |
|---|---|
| UI Framework | SolidJS |
| Build Tool | Vite |
| Styling | Tailwind CSS |
| Icons | lucide-solid |
| Language | JavaScript (JSX) |
Component Structure¶
src/
├── App.jsx # Root component and top-level layout
├── index.jsx # Entry point, mounts App + store provider
├── utils/
│ └── libraryModel.js # Normalized library grouping/filtering model
├── store/
│ └── appStore.jsx # Central app state + localStorage persistence
└── components/
├── DownloadView.jsx # URL input, download options, result display
├── LibraryView.jsx # Explorer-style library (gallery/list/detail)
├── SettingsView.jsx # Configuration (cookies, extensions)
└── Player.jsx # Media playback
State Management¶
State is centralized in store/appStore.jsx using Solid's context + store primitives. The app persists key UI fields in localStorage so layout and form choices survive reloads:
ui.activeTab— Current view (download, library, settings)ui.isAdvanced— Power-user toggle statesettings— Download options (output template, quality, jobs, audio-only, duplicate policy)library.section— Active library section (artists,channels,playlists,all_media)library.viewMode— Explorer presentation (gallery,list,detail)library.typeFilter— Type filter (all,audio,video)library.navPath— Drill-down path (creator/album/playlist context + breadcrumbs)library.filters— Query + advanced filters (creator/collection/source playlist/saved playlist)library.ui— Library-specific UI flags (advanced filters panel + metadata anomaly banner dismiss state)download.urlInput— Current URL draft in the download textarea
Runtime download progress state is also centralized so tab navigation does not reset active download progress UI.
Saved playlists and media-to-playlist assignments are persisted on the backend (media/data/saved_playlists.json) and synced through /api/library/playlists.
A one-time frontend migration path (/api/library/playlists/migrate) seeds backend data from legacy localStorage state.
Library grouping and metadata anomaly detection are derived client-side by utils/libraryModel.js from /api/media/ responses plus saved-playlist assignments.
Only durable state is persisted to localStorage. Transient runtime state (active job status/progress/logs/prompts) is intentionally not persisted.
Build & Integration Pipeline¶
- Development:
npm run devstarts Vite dev server with hot reload. API calls proxy to the Go backend viavite.config.jsproxy (/api→VITE_API_PROXY_TARGET, defaulthttp://127.0.0.1:8080). Ifytdl-go -webauto-switches to a fallback port, updateVITE_API_PROXY_TARGETto match the logged backend URL. - Production build:
npm run buildcompiles assets into../internal/web/assets/. - Go embed: The Go server uses
//go:embed assets/*to bundle the compiled frontend into the binary. - Runtime: The Go server serves the SPA at
/and API endpoints at/api/*.
API Communication¶
The frontend communicates with the Go backend via JSON over HTTP:
POST /api/download— Submit URLs for download (synchronous, returns results).-
WS /ws— Real-time progress updates, logs, and status events via WebSockets. -
POST /api/download/duplicate-response— Resolve duplicate-file prompts. GET /api/media/— Fetch downloaded media list.GET /api/media/{filename}— Serve a specific media file.GET /api/library/playlists— Load saved playlists + assignments.PUT /api/library/playlists— Persist saved playlists + assignments.POST /api/library/playlists/migrate— One-time migration from legacy local state.GET /api/status— Server health and active job count.
See the API Reference for the full contract.