feat: implement migration to split MediaStreamInfos into AudioStreamDetails and VideoStreamDetails

This commit is contained in:
2026-04-30 17:48:49 -04:00
parent 57d6342524
commit 9fc10226c9
3 changed files with 253 additions and 16 deletions
@@ -62,6 +62,9 @@ namespace Emby.Server.Implementations.Library
var keys = item.GetUserDataKeys();
using var dbContext = _repository.CreateDbContext();
var executionStrategy = dbContext.Database.CreateExecutionStrategy();
executionStrategy.Execute(() =>
{
using var transaction = dbContext.Database.BeginTransaction();
foreach (var key in keys)
@@ -80,6 +83,7 @@ namespace Emby.Server.Implementations.Library
dbContext.SaveChanges();
transaction.Commit();
});
var userId = user.InternalId;
var cacheKey = GetCacheKey(userId, item.Id);
+233
View File
@@ -0,0 +1,233 @@
# PostgreSQL Database Views
All views live in the `library` schema unless otherwise noted. They are read-only and safe to query from pgAdmin, BI tools, or any reporting/debugging context without risk of affecting the application.
---
## `library."MediaStreamInfos_v"`
Reassembles the original flat `MediaStreamInfos` table shape that existed before the `SplitMediaStreamInfos` migration split audio- and video-specific columns into dedicated tables.
**Use when:** you want a single flat result of all stream data without writing the three-way JOIN yourself.
**Columns of note:**
| Column | Source |
|---|---|
| `ItemId`, `StreamIndex`, `StreamType`, `Codec`, … | `MediaStreamInfos` (always present) |
| `ChannelLayout`, `Channels`, `SampleRate`, `IsHearingImpaired` | `AudioStreamDetails``NULL` for non-audio streams |
| `Height`, `Width`, `AverageFrameRate`, `BitDepth`, `ColorTransfer`, `DvProfile`, … | `VideoStreamDetails``NULL` for non-video streams |
**Example:**
```sql
-- All audio streams for a specific item
SELECT "StreamIndex", "Codec", "Language", "Channels", "SampleRate", "ChannelLayout"
FROM library."MediaStreamInfos_v"
WHERE "ItemId" = '<item-uuid>'
AND "StreamType" = 0 -- 0 = Audio
ORDER BY "StreamIndex";
```
---
## `library."VideoItems_v"`
Every non-folder, non-virtual item that has at least one video stream (movies, episodes, home videos, etc.), joined with the primary video stream's technical details.
**Use when:** auditing codec/resolution/HDR distribution across the library, or finding items that need re-encoding.
**Columns of note:**
| Column | Description |
|---|---|
| `Type` | Fully-qualified Jellyfin type name (e.g. `MediaBrowser.Controller.Entities.Movies.Movie`) |
| `VideoCodec` | Codec of the primary video stream (e.g. `hevc`, `h264`) |
| `Width` / `Height` | Resolution of the primary video stream |
| `BitDepth` | Colour bit depth (8, 10, 12) |
| `HDRFormat` | Derived string: `Dolby Vision`, `HDR10+`, `HDR10`, `HLG`, or `SDR` |
| `IsDolbyVision` | Boolean shortcut for `DvProfile IS NOT NULL` |
| `AudioTrackCount` | Number of audio streams on the item |
| `SubtitleTrackCount` | Number of subtitle streams on the item |
**Example queries:**
```sql
-- All 4K HDR movies
SELECT "Name", "ProductionYear", "VideoCodec", "Width", "Height", "HDRFormat", "TotalBitrate"
FROM library."VideoItems_v"
WHERE "Type" LIKE '%Movie%'
AND "Height" >= 2160
AND "HDRFormat" <> 'SDR'
ORDER BY "Name";
-- Episodes still encoded in H.264 (candidates for HEVC re-encode)
SELECT "SeriesName", "SeasonName", "EpisodeNumber", "Name", "Width", "Height"
FROM library."VideoItems_v"
WHERE "Type" LIKE '%Episode%'
AND "VideoCodec" = 'h264'
ORDER BY "SeriesName", "SeasonNumber", "EpisodeNumber";
```
---
## `library."UserPlaybackHistory_v"`
Per-user watch history joined with item metadata and a calculated playback progress percentage.
**Use when:** reporting on viewing activity, finding in-progress items, or checking which users have watched what.
**Columns of note:**
| Column | Description |
|---|---|
| `Username` | Jellyfin username |
| `ItemName` | Name of the item |
| `ItemType` | Jellyfin type name |
| `Played` | `true` if the item has been marked as played |
| `PlayCount` | Number of times fully played |
| `LastPlayedDate` | Timestamp of the most recent playback |
| `PlaybackPositionTicks` | Raw position (divide by `10,000,000` for seconds) |
| `ProgressPct` | Calculated percentage through the item (0100), `NULL` if no runtime |
| `AudioStreamIndex` | Last-used audio track index |
| `SubtitleStreamIndex` | Last-used subtitle track index |
**Example queries:**
```sql
-- All in-progress items for a user (started but not finished)
SELECT "ItemName", "ItemType", "SeriesName", "ProgressPct", "LastPlayedDate"
FROM library."UserPlaybackHistory_v"
WHERE "Username" = 'alice'
AND "Played" = false
AND "ProgressPct" > 0
ORDER BY "LastPlayedDate" DESC;
-- Top 10 most-played items across all users
SELECT "ItemName", "ItemType", SUM("PlayCount") AS "TotalPlays"
FROM library."UserPlaybackHistory_v"
GROUP BY "ItemName", "ItemType"
ORDER BY "TotalPlays" DESC
LIMIT 10;
```
---
## `library."ItemProviders_v"`
Items with their external provider IDs (IMDb, TMDB, TVDB, etc.) pivoted into named columns. Providers not explicitly named appear in a JSONB `OtherProviders` column.
**Use when:** cross-referencing Jellyfin items against external databases, finding items with missing metadata IDs, or bulk-exporting IDs for external tools.
**Columns of note:**
| Column | Description |
|---|---|
| `ImdbId` | IMDb identifier (e.g. `tt0111161`) |
| `TmdbId` | The Movie Database ID |
| `TvdbId` | TheTVDB series/episode ID |
| `TvRageId` | TVRage ID (legacy) |
| `MusicBrainzAlbumId` | MusicBrainz album MBID |
| `MusicBrainzArtistId` | MusicBrainz artist MBID |
| `OtherProviders` | JSONB object of any remaining provider key/value pairs |
**Example queries:**
```sql
-- Movies missing a TMDB ID
SELECT "Name", "ProductionYear", "ImdbId"
FROM library."ItemProviders_v"
WHERE "Type" LIKE '%Movie%'
AND "TmdbId" IS NULL
ORDER BY "Name";
-- Look up an item by IMDb ID
SELECT "ItemId", "Type", "Name", "ProductionYear"
FROM library."ItemProviders_v"
WHERE "ImdbId" = 'tt0111161';
```
---
## `library."ItemPeople_v"`
All cast and crew entries linked to the items they appear in.
**Use when:** browsing which items feature a specific actor or director, building cast-focused reports, or auditing people metadata.
**Columns of note:**
| Column | Description |
|---|---|
| `PersonName` | Name of the person |
| `PersonType` | Role type: `Actor`, `Director`, `Writer`, `Producer`, etc. |
| `Role` | Specific character name or role description (may be empty) |
| `SortOrder` / `ListOrder` | Display ordering within the item's people list |
**Example queries:**
```sql
-- All items featuring a specific actor
SELECT "ItemType", "ItemName", "SeriesName", "ProductionYear", "Role"
FROM library."ItemPeople_v"
WHERE "PersonName" = 'Bryan Cranston'
AND "PersonType" = 'Actor'
ORDER BY "ProductionYear";
-- Directors with the most items in the library
SELECT "PersonName", COUNT(*) AS "DirectedItems"
FROM library."ItemPeople_v"
WHERE "PersonType" = 'Director'
GROUP BY "PersonName"
ORDER BY "DirectedItems" DESC
LIMIT 20;
```
---
## `library."LibrarySummary_v"`
Aggregate statistics broken down by item type — one row per type. Provides a quick dashboard overview of the entire library.
**Use when:** getting a high-level snapshot of library size, total runtime, storage usage, and video quality distribution.
**Columns of note:**
| Column | Description |
|---|---|
| `Type` | Jellyfin item type |
| `ItemCount` | Total number of items of this type |
| `TotalRuntimeHours` | Sum of all runtimes in hours |
| `TotalSizeGB` | Sum of all file sizes in gigabytes |
| `AvgCommunityRating` | Average community rating across items with a rating |
| `Count4K` | Items with primary video height ≥ 2160 |
| `Count1080p` | Items with height 10802159 |
| `Count720p` | Items with height 7201079 |
| `CountSD` | Items with height < 720 |
| `CountDolbyVision` | Items with a Dolby Vision video stream |
| `CountHDR10Plus` | Items with HDR10+ flag set |
| `CountHDR10` | Items with HDR10 (`smpte2084` transfer, no DV or HDR10+) |
**Example:**
```sql
-- Full summary
SELECT "Type", "ItemCount", "TotalRuntimeHours", "TotalSizeGB",
"Count4K", "Count1080p", "Count720p", "CountSD",
"CountDolbyVision", "CountHDR10Plus", "CountHDR10"
FROM library."LibrarySummary_v";
```
---
## StreamType Reference
The `StreamType` integer used in `MediaStreamInfos` and `MediaStreamInfos_v` maps to:
| Value | Type |
|---|---|
| 0 | Audio |
| 1 | Video |
| 2 | Subtitle |
| 3 | EmbeddedImage |
| 4 | Data / Attachment |