Note: This is a personal project built for a very specific use case by the author. It is part of a series of internal systems for managing media workflows and is tailored to the author's particular setup and preferences. While parts of it may be useful or adaptable for others, it is not designed as a general-purpose application and comes with no guarantees of suitability for other environments.
A personal TV show tracker built with Blazor Server, EF Core, and the TVMaze API. Track shows, monitor downloads, get notifications for new episodes, and manage your watchlist.
# Clone and build
git clone <repo-url>
cd Showlist2026
dotnet restore
dotnet build
# Configure your connection string (see Configuration below)
cd src/Showlist2026.Web
dotnet user-secrets set "ConnectionStrings:Default" "Server=YOUR_SERVER;Database=showlist2026;User ID=YOUR_USER;Password=YOUR_PASS;TrustServerCertificate=True;"
# Run
dotnet run --project src/Showlist2026.Web
The database is created and migrations are applied automatically on startup.
All settings live in src/Showlist2026.Web/appsettings.json. For secrets (passwords, API keys), use User Secrets or environment variables instead of editing appsettings.json directly.
cd src/Showlist2026.Web
dotnet user-secrets init # only needed once
Then set any config value:
dotnet user-secrets set "Key:SubKey" "value"
Or create/edit the secrets file directly at:
%APPDATA%\Microsoft\UserSecrets\<user-secrets-id>\secrets.json~/.microsoft/usersecrets/<user-secrets-id>/secrets.jsonThe database connection. Required.
| Key | Description | Default |
|---|---|---|
ConnectionStrings:Default |
SQL Server connection string | Server=localhost;Database=showlist2026;TrustServerCertificate=True;Integrated Security=True; |
User Secrets example:
dotnet user-secrets set "ConnectionStrings:Default" "Server=10.0.3.253;Database=showlist2026;User ID=myuser;Password=mypassword;TrustServerCertificate=True;"
Environment variable example:
export ConnectionStrings__Default="Server=10.0.3.253;Database=showlist2026;User ID=myuser;Password=mypassword;TrustServerCertificate=True;"
Paths and URLs used by the application.
| Key | Description | Default |
|---|---|---|
Showlist:TvNameListPath |
Root folder where show name folders are scanned to match shows to folders | C:\tvnamelist\ |
Showlist:ShowFolderBasePath |
Base path where new show folders are created when you select a show as wanted | F:\tv_name_list\ |
Showlist:TvMazeBaseUrl |
TVMaze API base URL. Only change if using a proxy/mirror | http://api.tvmaze.com |
Showlist:NzbPlanetApiKey |
API key for NZBPlanet NZB search | (empty) |
appsettings.json:
"Showlist": {
"TvNameListPath": "C:\\tvnamelist\\",
"ShowFolderBasePath": "F:\\tv_name_list\\",
"TvMazeBaseUrl": "http://api.tvmaze.com",
"NzbPlanetApiKey": ""
}
User Secrets example:
dotnet user-secrets set "Showlist:TvNameListPath" "/mnt/media/tvnamelist/"
dotnet user-secrets set "Showlist:ShowFolderBasePath" "/mnt/media/tv_name_list/"
dotnet user-secrets set "Showlist:NzbPlanetApiKey" "your-api-key"
Three notification channels are supported. Enable any combination. All are disabled by default.
Push notifications to your phone via Pushover.
| Key | Description |
|---|---|
Notifications:Pushover:Enabled |
true to enable |
Notifications:Pushover:ApiKey |
Your Pushover application API token |
Notifications:Pushover:UserKey |
Your Pushover user key |
dotnet user-secrets set "Notifications:Pushover:Enabled" "true"
dotnet user-secrets set "Notifications:Pushover:ApiKey" "your-app-token"
dotnet user-secrets set "Notifications:Pushover:UserKey" "your-user-key"
Post messages to a Discord channel via webhook.
| Key | Description |
|---|---|
Notifications:Discord:Enabled |
true to enable |
Notifications:Discord:WebhookUrl |
Discord webhook URL (Server Settings > Integrations > Webhooks) |
dotnet user-secrets set "Notifications:Discord:Enabled" "true"
dotnet user-secrets set "Notifications:Discord:WebhookUrl" "https://discord.com/api/webhooks/123456/abcdef"
Send notifications via SMTP.
| Key | Description |
|---|---|
Notifications:Email:Enabled |
true to enable |
Notifications:Email:SmtpHost |
SMTP server hostname (e.g. smtp.gmail.com) |
Notifications:Email:SmtpPort |
SMTP port (default: 587) |
Notifications:Email:From |
Sender email address |
Notifications:Email:To |
Recipient email address |
Notifications:Email:Username |
SMTP username |
Notifications:Email:Password |
SMTP password or app-specific password |
dotnet user-secrets set "Notifications:Email:Enabled" "true"
dotnet user-secrets set "Notifications:Email:SmtpHost" "smtp.gmail.com"
dotnet user-secrets set "Notifications:Email:SmtpPort" "587"
dotnet user-secrets set "Notifications:Email:From" "myemail@gmail.com"
dotnet user-secrets set "Notifications:Email:To" "myemail@gmail.com"
dotnet user-secrets set "Notifications:Email:Username" "myemail@gmail.com"
dotnet user-secrets set "Notifications:Email:Password" "your-app-password"
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=showlist2026;TrustServerCertificate=True;Integrated Security=True;"
},
"Showlist": {
"TvNameListPath": "C:\\tvnamelist\\",
"ShowFolderBasePath": "F:\\tv_name_list\\",
"TvMazeBaseUrl": "http://api.tvmaze.com",
"NzbPlanetApiKey": ""
},
"Notifications": {
"Pushover": {
"Enabled": false,
"ApiKey": "",
"UserKey": ""
},
"Discord": {
"Enabled": false,
"WebhookUrl": ""
},
"Email": {
"Enabled": false,
"SmtpHost": "",
"SmtpPort": 587,
"From": "",
"To": "",
"Username": "",
"Password": ""
}
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Foo/Season 3/... where the new show's S01 = Foo's S03) are matched to the correct show's episodes in place. Managed per-show on the show detail page.| Route | Description |
|---|---|
/ |
Home — stats overview, tonight's episodes, background job status |
/airing |
Episodes airing around now for your selected shows |
/calendar |
Week/month calendar view of upcoming episodes |
/missed |
Episodes you may have missed |
/missed-shows |
Undecided shows — bulk accept or reject |
/unwatched |
Next unwatched episode per show |
/coming-soon |
New shows premiering soon |
/downloaded |
Downloaded episode history |
/download-progress |
Per-show download completion with missing episode lists |
/no-folder |
Selected shows without a matched folder |
/watched-history |
Chronological watch history |
/stats |
Watch statistics — genres, trends, watch time |
/storage |
Storage dashboard — disk usage per show folder |
/search |
Advanced search (local + TVMaze API) |
/trending |
Trending shows from TVMaze |
/compare |
Side-by-side show comparison |
/showlist/show/{id} |
Show detail with episodes, NZB search, catch-up |
/filters/* |
Filter management (shows, genres, networks, countries, languages, types) |
/admin |
Admin operations, data export/import |
/admin/nzbsites |
NZB site configuration |
/admin/tvdirectories |
TV directory scan configuration |
/hangfire |
Hangfire background job dashboard |
/health |
Health check endpoint (DB + TVMaze API) |
Managed by Hangfire. Status is visible on the home page and at /hangfire.
| Job | Schedule | Description |
|---|---|---|
| RefreshShowDates | Every hour at :06 | Fetches show update timestamps from TVMaze |
| RefreshShows | Every hour at :02, :22, :42 | Updates show metadata and episodes for changed shows |
| PopulateShowFolderNames | Every 3 hours at :25 | Matches selected shows to folders on disk |
| ShowDownloadedJob | Every 10 minutes | Scans TV directories for new downloads, sends notifications |
| NewSeasonNotifications | Daily at 8:00 AM | Notifies when a new season starts for selected shows |
From the Admin page (/admin):
If you have an existing database from a previous version, you need to mark the initial migration as applied:
INSERT INTO [__EFMigrationsHistory] (MigrationId, ProductVersion)
VALUES ('<migration-id>', '10.0.5');
Find the migration ID in src/Showlist2026.Data/Migrations/ (the timestamp-prefixed filename).
src/
Showlist2026.Core/ Entities, models, service interfaces, config
Showlist2026.Data/ EF Core DbContext and migrations
Showlist2026.Web/ Blazor Server app
Components/
Layout/ App shell and nav menu
Pages/ All page components
Shared/ Reusable components
Health/ Health check implementations
Services/ Service implementations