diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index d6ea8ea0..393d6989 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "jetbrains.resharper.globaltools": { - "version": "2023.2.0", + "version": "2023.3.3", "commands": [ "jb" ] diff --git a/ErsatzTV.Application/Channels/Commands/CreateChannel.cs b/ErsatzTV.Application/Channels/Commands/CreateChannel.cs index a9de70fc..e3427b58 100644 --- a/ErsatzTV.Application/Channels/Commands/CreateChannel.cs +++ b/ErsatzTV.Application/Channels/Commands/CreateChannel.cs @@ -3,8 +3,7 @@ using ErsatzTV.Core.Domain; namespace ErsatzTV.Application.Channels; -public record CreateChannel -( +public record CreateChannel( string Name, string Number, string Group, diff --git a/ErsatzTV.Application/Channels/Commands/DeleteChannelHandler.cs b/ErsatzTV.Application/Channels/Commands/DeleteChannelHandler.cs index 21a8590f..2ea9db31 100644 --- a/ErsatzTV.Application/Channels/Commands/DeleteChannelHandler.cs +++ b/ErsatzTV.Application/Channels/Commands/DeleteChannelHandler.cs @@ -39,7 +39,7 @@ public class DeleteChannelHandler : IRequestHandler { + private readonly IConfigElementRepository _configElementRepository; private readonly IDbContextFactory _dbContextFactory; private readonly ILocalFileSystem _localFileSystem; - private readonly IConfigElementRepository _configElementRepository; private readonly ILogger _logger; private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager; @@ -45,7 +45,7 @@ public class RefreshChannelDataHandler : IRequestHandler public async Task Handle(RefreshChannelData request, CancellationToken cancellationToken) { _logger.LogDebug("Refreshing channel data (XMLTV) for channel {Channel}", request.ChannelNumber); - + _localFileSystem.EnsureFolderExists(FileSystemLayout.ChannelGuideCacheFolder); string movieTemplateFileName = GetMovieTemplateFileName(); @@ -68,7 +68,7 @@ public class RefreshChannelDataHandler : IRequestHandler }); var templateContext = new XmlTemplateContext(); - + string movieText = await File.ReadAllTextAsync(movieTemplateFileName, cancellationToken); var movieTemplate = Template.Parse(movieText, movieTemplateFileName); @@ -302,7 +302,7 @@ public class RefreshChannelDataHandler : IRequestHandler (_, true) => displayItem.GuideFinishOffset!.Value, (_, false) => finishItem.FinishOffset }; - + string start = startTime .ToString("yyyyMMddHHmmss zzz", CultureInfo.InvariantCulture) .Replace(":", string.Empty); @@ -329,7 +329,7 @@ public class RefreshChannelDataHandler : IRequestHandler i++; } } - + private static async Task WriteBlockPlayoutXml( RefreshChannelData request, List sorted, @@ -367,7 +367,7 @@ public class RefreshChannelDataHandler : IRequestHandler item, start, stop, - hasCustomTitle: false, + false, templateContext, movieTemplate, episodeTemplate, @@ -481,7 +481,7 @@ public class RefreshChannelDataHandler : IRequestHandler { metadata.Genres ??= []; metadata.Guids ??= []; - + string poster = Optional(metadata.Artwork).Flatten() .Filter(a => a.ArtworkKind == ArtworkKind.Poster) .HeadOrNone() @@ -491,9 +491,9 @@ public class RefreshChannelDataHandler : IRequestHandler { ProgrammeStart = start, ProgrammeStop = stop, - ChannelNumber = request.ChannelNumber, + request.ChannelNumber, HasCustomTitle = hasCustomTitle, - CustomTitle = displayItem.CustomTitle, + displayItem.CustomTitle, MovieTitle = title, MovieHasPlot = !string.IsNullOrWhiteSpace(metadata.Plot), MoviePlot = metadata.Plot, @@ -516,7 +516,7 @@ public class RefreshChannelDataHandler : IRequestHandler return Option.None; } - + private static async Task> ProcessEpisodeTemplate( RefreshChannelData request, Episode templateEpisode, @@ -546,9 +546,9 @@ public class RefreshChannelDataHandler : IRequestHandler { ProgrammeStart = start, ProgrammeStop = stop, - ChannelNumber = request.ChannelNumber, + request.ChannelNumber, HasCustomTitle = hasCustomTitle, - CustomTitle = displayItem.CustomTitle, + displayItem.CustomTitle, ShowTitle = title, EpisodeHasTitle = !string.IsNullOrWhiteSpace(subtitle), EpisodeTitle = subtitle, @@ -560,13 +560,13 @@ public class RefreshChannelDataHandler : IRequestHandler EpisodeHasArtwork = !string.IsNullOrWhiteSpace(artworkPath), EpisodeArtworkUrl = artworkPath, SeasonNumber = templateEpisode.Season?.SeasonNumber ?? 0, - EpisodeNumber = metadata.EpisodeNumber, + metadata.EpisodeNumber, ShowHasContentRating = !string.IsNullOrWhiteSpace(showMetadata.ContentRating), ShowContentRating = showMetadata.ContentRating, ShowGuids = showMetadata.Guids.Map(g => g.Guid), EpisodeGuids = metadata.Guids.Map(g => g.Guid) }; - + var scriptObject = new ScriptObject(); scriptObject.Import(data); templateContext.PushGlobal(scriptObject); @@ -606,9 +606,9 @@ public class RefreshChannelDataHandler : IRequestHandler { ProgrammeStart = start, ProgrammeStop = stop, - ChannelNumber = request.ChannelNumber, + request.ChannelNumber, HasCustomTitle = hasCustomTitle, - CustomTitle = displayItem.CustomTitle, + displayItem.CustomTitle, ArtistTitle = title, MusicVideoTitle = subtitle, MusicVideoHasPlot = !string.IsNullOrWhiteSpace(metadata.Plot), @@ -639,7 +639,7 @@ public class RefreshChannelDataHandler : IRequestHandler return Option.None; } - + private static async Task> ProcessSongTemplate( RefreshChannelData request, Song templateSong, @@ -663,9 +663,9 @@ public class RefreshChannelDataHandler : IRequestHandler { ProgrammeStart = start, ProgrammeStop = stop, - ChannelNumber = request.ChannelNumber, + request.ChannelNumber, HasCustomTitle = hasCustomTitle, - CustomTitle = displayItem.CustomTitle, + displayItem.CustomTitle, SongTitle = subtitle, SongArtists = metadata.Artists, SongAlbumArtists = metadata.AlbumArtists, @@ -682,7 +682,7 @@ public class RefreshChannelDataHandler : IRequestHandler SongAlbum = metadata.Album, SongHasReleaseDate = metadata.ReleaseDate.HasValue, SongReleaseDate = metadata.ReleaseDate, - SongStudios = metadata.Studios.Map(s => s.Name), + SongStudios = metadata.Studios.Map(s => s.Name) }; var scriptObject = new ScriptObject(); @@ -694,7 +694,7 @@ public class RefreshChannelDataHandler : IRequestHandler return Option.None; } - + private static async Task> ProcessOtherVideoTemplate( RefreshChannelData request, OtherVideo templateOtherVideo, @@ -710,14 +710,14 @@ public class RefreshChannelDataHandler : IRequestHandler { metadata.Genres ??= []; metadata.Guids ??= []; - + var data = new { ProgrammeStart = start, ProgrammeStop = stop, - ChannelNumber = request.ChannelNumber, + request.ChannelNumber, HasCustomTitle = hasCustomTitle, - CustomTitle = displayItem.CustomTitle, + displayItem.CustomTitle, OtherVideoTitle = title, OtherVideoHasPlot = !string.IsNullOrWhiteSpace(metadata.Plot), OtherVideoPlot = metadata.Plot, @@ -741,13 +741,13 @@ public class RefreshChannelDataHandler : IRequestHandler private string GetMovieTemplateFileName() { string templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "movie.sbntxt"); - + // fall back to default template if (!_localFileSystem.FileExists(templateFileName)) { templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "_movie.sbntxt"); } - + // fail if file doesn't exist if (!_localFileSystem.FileExists(templateFileName)) { @@ -760,17 +760,17 @@ public class RefreshChannelDataHandler : IRequestHandler return templateFileName; } - + private string GetEpisodeTemplateFileName() { string templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "episode.sbntxt"); - + // fall back to default template if (!_localFileSystem.FileExists(templateFileName)) { templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "_episode.sbntxt"); } - + // fail if file doesn't exist if (!_localFileSystem.FileExists(templateFileName)) { @@ -783,17 +783,17 @@ public class RefreshChannelDataHandler : IRequestHandler return templateFileName; } - + private string GetMusicVideoTemplateFileName() { string templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "musicVideo.sbntxt"); - + // fall back to default template if (!_localFileSystem.FileExists(templateFileName)) { templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "_musicVideo.sbntxt"); } - + // fail if file doesn't exist if (!_localFileSystem.FileExists(templateFileName)) { @@ -806,17 +806,17 @@ public class RefreshChannelDataHandler : IRequestHandler return templateFileName; } - + private string GetSongTemplateFileName() { string templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "song.sbntxt"); - + // fall back to default template if (!_localFileSystem.FileExists(templateFileName)) { templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "_song.sbntxt"); } - + // fail if file doesn't exist if (!_localFileSystem.FileExists(templateFileName)) { @@ -829,17 +829,17 @@ public class RefreshChannelDataHandler : IRequestHandler return templateFileName; } - + private string GetOtherVideoTemplateFileName() { string templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "otherVideo.sbntxt"); - + // fall back to default template if (!_localFileSystem.FileExists(templateFileName)) { templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "_otherVideo.sbntxt"); } - + // fail if file doesn't exist if (!_localFileSystem.FileExists(templateFileName)) { @@ -863,10 +863,12 @@ public class RefreshChannelDataHandler : IRequestHandler _ => 440 }; - if (artworkPath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || artworkPath.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) + if (artworkPath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || + artworkPath.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) { return artworkPath; } + if (artworkPath.StartsWith("jellyfin://", StringComparison.OrdinalIgnoreCase)) { artworkPath = JellyfinUrl.PlaceholderProxyForArtwork(artworkPath, artworkKind, height); @@ -1025,7 +1027,7 @@ public class RefreshChannelDataHandler : IRequestHandler foreach (ExternalJsonChannel channel in maybeChannel) { // TODO: null start time should log and throw - + DateTimeOffset startTime = DateTimeOffset.Parse( channel.StartTime ?? string.Empty, CultureInfo.InvariantCulture, @@ -1077,14 +1079,15 @@ public class RefreshChannelDataHandler : IRequestHandler var artwork = new List(); if (!string.IsNullOrWhiteSpace(program.Icon)) { - artwork.Add(new Artwork - { - ArtworkKind = ArtworkKind.Thumbnail, - Path = program.Icon, - SourcePath = program.Icon - }); + artwork.Add( + new Artwork + { + ArtworkKind = ArtworkKind.Thumbnail, + Path = program.Icon, + SourcePath = program.Icon + }); } - + return new Episode { MediaVersions = @@ -1100,7 +1103,7 @@ public class RefreshChannelDataHandler : IRequestHandler { EpisodeNumber = program.Episode, Title = program.Title - }, + } ], Season = new Season { @@ -1125,12 +1128,13 @@ public class RefreshChannelDataHandler : IRequestHandler var artwork = new List(); if (!string.IsNullOrWhiteSpace(program.Icon)) { - artwork.Add(new Artwork - { - ArtworkKind = ArtworkKind.Poster, - Path = program.Icon, - SourcePath = program.Icon - }); + artwork.Add( + new Artwork + { + ArtworkKind = ArtworkKind.Poster, + Path = program.Icon, + SourcePath = program.Icon + }); } return new Movie diff --git a/ErsatzTV.Application/Channels/Commands/RefreshChannelListHandler.cs b/ErsatzTV.Application/Channels/Commands/RefreshChannelListHandler.cs index a46cf386..ed13c308 100644 --- a/ErsatzTV.Application/Channels/Commands/RefreshChannelListHandler.cs +++ b/ErsatzTV.Application/Channels/Commands/RefreshChannelListHandler.cs @@ -39,13 +39,13 @@ public class RefreshChannelListHandler : IRequestHandler await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); string templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "channel.sbntxt"); - + // fall back to default template if (!_localFileSystem.FileExists(templateFileName)) { templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "_channel.sbntxt"); } - + // fail if file doesn't exist if (!_localFileSystem.FileExists(templateFileName)) { @@ -63,11 +63,11 @@ public class RefreshChannelListHandler : IRequestHandler RemoveXmlComments = true, CollapseTagsWithoutContent = true }); - + string text = await File.ReadAllTextAsync(templateFileName, cancellationToken); var template = Template.Parse(text, templateFileName); var templateContext = new XmlTemplateContext(); - + await using RecyclableMemoryStream ms = _recyclableMemoryStreamManager.GetStream(); await using var xml = XmlWriter.Create( ms, @@ -83,7 +83,7 @@ public class RefreshChannelListHandler : IRequestHandler ChannelHasArtwork = !string.IsNullOrWhiteSpace(channel.ArtworkPath), ChannelArtworkPath = channel.ArtworkPath }; - + var scriptObject = new ScriptObject(); scriptObject.Import(data); templateContext.PushGlobal(scriptObject); diff --git a/ErsatzTV.Application/Channels/Commands/UpdateChannel.cs b/ErsatzTV.Application/Channels/Commands/UpdateChannel.cs index 69149904..96667106 100644 --- a/ErsatzTV.Application/Channels/Commands/UpdateChannel.cs +++ b/ErsatzTV.Application/Channels/Commands/UpdateChannel.cs @@ -3,8 +3,7 @@ using ErsatzTV.Core.Domain; namespace ErsatzTV.Application.Channels; -public record UpdateChannel -( +public record UpdateChannel( int ChannelId, string Name, string Number, diff --git a/ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs b/ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs index 6a15ddd1..b0ca4ec0 100644 --- a/ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs +++ b/ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs @@ -71,7 +71,7 @@ public class UpdateChannelHandler( c.WatermarkId = update.WatermarkId; c.FallbackFillerId = update.FallbackFillerId; await dbContext.SaveChangesAsync(); - + searchTargets.SearchTargetsChanged(); if (c.SubtitleMode != ChannelSubtitleMode.None) @@ -84,7 +84,7 @@ public class UpdateChannelHandler( await workerChannel.WriteAsync(new ExtractEmbeddedSubtitles(playout.Id)); } } - + await workerChannel.WriteAsync(new RefreshChannelList()); return ProjectToViewModel(c); diff --git a/ErsatzTV.Application/Channels/Queries/GetChannelGuide.cs b/ErsatzTV.Application/Channels/Queries/GetChannelGuide.cs index cdb8af72..a0e40aed 100644 --- a/ErsatzTV.Application/Channels/Queries/GetChannelGuide.cs +++ b/ErsatzTV.Application/Channels/Queries/GetChannelGuide.cs @@ -3,5 +3,5 @@ using ErsatzTV.Core.Iptv; namespace ErsatzTV.Application.Channels; -public record GetChannelGuide - (string Scheme, string Host, string BaseUrl, string AccessToken) : IRequest>; +public record GetChannelGuide(string Scheme, string Host, string BaseUrl, string AccessToken) + : IRequest>; diff --git a/ErsatzTV.Application/Configuration/Commands/UpdateGeneralSettingsHandler.cs b/ErsatzTV.Application/Configuration/Commands/UpdateGeneralSettingsHandler.cs index 96b42fcf..4cdda64d 100644 --- a/ErsatzTV.Application/Configuration/Commands/UpdateGeneralSettingsHandler.cs +++ b/ErsatzTV.Application/Configuration/Commands/UpdateGeneralSettingsHandler.cs @@ -26,16 +26,24 @@ public class UpdateGeneralSettingsHandler : IRequestHandler maybeDefaultLevel = await _configElementRepository.GetValue(ConfigElementKey.MinimumLogLevel); - + Option maybeScanningLevel = await _configElementRepository.GetValue(ConfigElementKey.MinimumLogLevelScanning); Option maybeSchedulingLevel = await _configElementRepository.GetValue(ConfigElementKey.MinimumLogLevelScheduling); - + Option maybeStreamingLevel = await _configElementRepository.GetValue(ConfigElementKey.MinimumLogLevelStreaming); - + Option maybeHttpLevel = await _configElementRepository.GetValue(ConfigElementKey.MinimumLogLevelHttp); diff --git a/ErsatzTV.Application/Emby/Commands/UpdateEmbyLibraryPreferences.cs b/ErsatzTV.Application/Emby/Commands/UpdateEmbyLibraryPreferences.cs index b46a8a14..a986d606 100644 --- a/ErsatzTV.Application/Emby/Commands/UpdateEmbyLibraryPreferences.cs +++ b/ErsatzTV.Application/Emby/Commands/UpdateEmbyLibraryPreferences.cs @@ -2,7 +2,6 @@ namespace ErsatzTV.Application.Emby; -public record UpdateEmbyLibraryPreferences - (List Preferences) : IRequest>; +public record UpdateEmbyLibraryPreferences(List Preferences) : IRequest>; public record EmbyLibraryPreference(int Id, bool ShouldSyncItems); diff --git a/ErsatzTV.Application/Emby/Commands/UpdateEmbyLibraryPreferencesHandler.cs b/ErsatzTV.Application/Emby/Commands/UpdateEmbyLibraryPreferencesHandler.cs index ade791d8..986a30ae 100644 --- a/ErsatzTV.Application/Emby/Commands/UpdateEmbyLibraryPreferencesHandler.cs +++ b/ErsatzTV.Application/Emby/Commands/UpdateEmbyLibraryPreferencesHandler.cs @@ -6,7 +6,7 @@ namespace ErsatzTV.Application.Emby; public class UpdateEmbyLibraryPreferencesHandler : IRequestHandler> + Either> { private readonly IMediaSourceRepository _mediaSourceRepository; private readonly ISearchIndex _searchIndex; diff --git a/ErsatzTV.Application/Emby/EmbyLibraryViewModel.cs b/ErsatzTV.Application/Emby/EmbyLibraryViewModel.cs index 9189feba..b57fc44e 100644 --- a/ErsatzTV.Application/Emby/EmbyLibraryViewModel.cs +++ b/ErsatzTV.Application/Emby/EmbyLibraryViewModel.cs @@ -4,9 +4,9 @@ using ErsatzTV.Core.Domain; namespace ErsatzTV.Application.Emby; public record EmbyLibraryViewModel( - int Id, - string Name, - LibraryMediaKind MediaKind, - bool ShouldSyncItems, - int MediaSourceId) + int Id, + string Name, + LibraryMediaKind MediaKind, + bool ShouldSyncItems, + int MediaSourceId) : LibraryViewModel("Emby", Id, Name, MediaKind, MediaSourceId, string.Empty); diff --git a/ErsatzTV.Application/Emby/Queries/GetEmbyPathReplacementsBySourceId.cs b/ErsatzTV.Application/Emby/Queries/GetEmbyPathReplacementsBySourceId.cs index 81e41b35..74920df1 100644 --- a/ErsatzTV.Application/Emby/Queries/GetEmbyPathReplacementsBySourceId.cs +++ b/ErsatzTV.Application/Emby/Queries/GetEmbyPathReplacementsBySourceId.cs @@ -1,4 +1,3 @@ namespace ErsatzTV.Application.Emby; -public record GetEmbyPathReplacementsBySourceId - (int EmbyMediaSourceId) : IRequest>; +public record GetEmbyPathReplacementsBySourceId(int EmbyMediaSourceId) : IRequest>; diff --git a/ErsatzTV.Application/ErsatzTV.Application.csproj b/ErsatzTV.Application/ErsatzTV.Application.csproj index e4b6cf96..71da7f96 100644 --- a/ErsatzTV.Application/ErsatzTV.Application.csproj +++ b/ErsatzTV.Application/ErsatzTV.Application.csproj @@ -15,13 +15,13 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/ErsatzTV.Application/FFmpegProfiles/Commands/CopyFFmpegProfile.cs b/ErsatzTV.Application/FFmpegProfiles/Commands/CopyFFmpegProfile.cs index bb4515b6..9eadc888 100644 --- a/ErsatzTV.Application/FFmpegProfiles/Commands/CopyFFmpegProfile.cs +++ b/ErsatzTV.Application/FFmpegProfiles/Commands/CopyFFmpegProfile.cs @@ -2,5 +2,4 @@ namespace ErsatzTV.Application.FFmpegProfiles; -public record CopyFFmpegProfile - (int FFmpegProfileId, string Name) : IRequest>; +public record CopyFFmpegProfile(int FFmpegProfileId, string Name) : IRequest>; diff --git a/ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfileHandler.cs b/ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfileHandler.cs index b1446483..8db493f9 100644 --- a/ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfileHandler.cs +++ b/ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfileHandler.cs @@ -59,9 +59,9 @@ public class p.NormalizeFramerate = update.NormalizeFramerate; p.DeinterlaceVideo = update.DeinterlaceVideo; await dbContext.SaveChangesAsync(); - + _searchTargets.SearchTargetsChanged(); - + return new UpdateFFmpegProfileResult(p.Id); } diff --git a/ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegSettingsHandler.cs b/ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegSettingsHandler.cs index b57cd41f..69f60475 100644 --- a/ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegSettingsHandler.cs +++ b/ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegSettingsHandler.cs @@ -101,11 +101,11 @@ public class UpdateFFmpegSettingsHandler : IRequestHandler> + Option> { private readonly IDbContextFactory _dbContextFactory; diff --git a/ErsatzTV.Application/FFmpegProfiles/Queries/GetSupportedHardwareAccelerationKindsHandler.cs b/ErsatzTV.Application/FFmpegProfiles/Queries/GetSupportedHardwareAccelerationKindsHandler.cs index 35923fcb..3b109e44 100644 --- a/ErsatzTV.Application/FFmpegProfiles/Queries/GetSupportedHardwareAccelerationKindsHandler.cs +++ b/ErsatzTV.Application/FFmpegProfiles/Queries/GetSupportedHardwareAccelerationKindsHandler.cs @@ -10,7 +10,7 @@ namespace ErsatzTV.Application.FFmpegProfiles; public class GetSupportedHardwareAccelerationKindsHandler : IRequestHandler> + List> { private readonly IDbContextFactory _dbContextFactory; private readonly IHardwareCapabilitiesFactory _hardwareCapabilitiesFactory; diff --git a/ErsatzTV.Application/Images/Commands/UpdateImageFolderDurationHandler.cs b/ErsatzTV.Application/Images/Commands/UpdateImageFolderDurationHandler.cs index a7277e8b..326f9df4 100644 --- a/ErsatzTV.Application/Images/Commands/UpdateImageFolderDurationHandler.cs +++ b/ErsatzTV.Application/Images/Commands/UpdateImageFolderDurationHandler.cs @@ -16,7 +16,7 @@ public class UpdateImageFolderDurationHandler(IDbContextFactory dbCon { request = request with { ImageFolderDuration = 0.01 }; } - + // delete entry if null if (request.ImageFolderDuration is null) { @@ -48,7 +48,7 @@ public class UpdateImageFolderDurationHandler(IDbContextFactory dbCon await dbContext.SaveChangesAsync(cancellationToken); } } - + // update all images (bfs) starting at this folder Option maybeFolder = await dbContext.LibraryFolders .AsNoTracking() @@ -59,7 +59,7 @@ public class UpdateImageFolderDurationHandler(IDbContextFactory dbCon foreach (LibraryFolder libraryFolder in maybeFolder) { LibraryFolder currentFolder = libraryFolder; - + // walk up to get duration, if needed double? durationSeconds = currentFolder.ImageFolderDuration?.DurationSeconds; while (durationSeconds is null && currentFolder?.ParentId is not null) @@ -73,7 +73,7 @@ public class UpdateImageFolderDurationHandler(IDbContextFactory dbCon { currentFolder = null; } - + foreach (LibraryFolder parent in maybeParent) { currentFolder = parent; @@ -83,7 +83,7 @@ public class UpdateImageFolderDurationHandler(IDbContextFactory dbCon queue.Enqueue(new FolderWithParentDuration(libraryFolder, durationSeconds)); } - + while (queue.Count > 0) { (LibraryFolder currentFolder, double? parentDuration) = queue.Dequeue(); @@ -109,7 +109,7 @@ public class UpdateImageFolderDurationHandler(IDbContextFactory dbCon .Filter(lf => lf.ParentId == currentFolder.Id) .Include(lf => lf.ImageFolderDuration) .ToListAsync(cancellationToken); - + // queue all children foreach (LibraryFolder child in children) { diff --git a/ErsatzTV.Application/Images/Queries/GetCachedImagePath.cs b/ErsatzTV.Application/Images/Queries/GetCachedImagePath.cs index 8688ce21..849f52f1 100644 --- a/ErsatzTV.Application/Images/Queries/GetCachedImagePath.cs +++ b/ErsatzTV.Application/Images/Queries/GetCachedImagePath.cs @@ -3,6 +3,5 @@ using ErsatzTV.Core.Domain; namespace ErsatzTV.Application.Images; -public record GetCachedImagePath - (string FileName, ArtworkKind ArtworkKind, int? MaxHeight = null) : IRequest< - Either>; +public record GetCachedImagePath(string FileName, ArtworkKind ArtworkKind, int? MaxHeight = null) : IRequest< + Either>; diff --git a/ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserIdHandler.cs b/ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserIdHandler.cs index 1ddadb55..f385b244 100644 --- a/ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserIdHandler.cs +++ b/ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserIdHandler.cs @@ -10,7 +10,7 @@ namespace ErsatzTV.Application.Jellyfin; public class SynchronizeJellyfinAdminUserIdHandler : IRequestHandler> + Either> { private readonly IJellyfinApiClient _jellyfinApiClient; private readonly IJellyfinSecretStore _jellyfinSecretStore; diff --git a/ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinLibraryById.cs b/ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinLibraryById.cs index a7f80886..b6c49333 100644 --- a/ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinLibraryById.cs +++ b/ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinLibraryById.cs @@ -16,8 +16,8 @@ public record SynchronizeJellyfinLibraryByIdIfNeeded(int JellyfinLibraryId) : IS public bool DeepScan => false; } -public record ForceSynchronizeJellyfinLibraryById - (int JellyfinLibraryId, bool DeepScan) : ISynchronizeJellyfinLibraryById +public record ForceSynchronizeJellyfinLibraryById(int JellyfinLibraryId, bool DeepScan) + : ISynchronizeJellyfinLibraryById { public bool ForceScan => true; } diff --git a/ErsatzTV.Application/Jellyfin/Commands/UpdateJellyfinLibraryPreferences.cs b/ErsatzTV.Application/Jellyfin/Commands/UpdateJellyfinLibraryPreferences.cs index 89324728..b288b718 100644 --- a/ErsatzTV.Application/Jellyfin/Commands/UpdateJellyfinLibraryPreferences.cs +++ b/ErsatzTV.Application/Jellyfin/Commands/UpdateJellyfinLibraryPreferences.cs @@ -2,7 +2,7 @@ namespace ErsatzTV.Application.Jellyfin; -public record UpdateJellyfinLibraryPreferences - (List Preferences) : IRequest>; +public record UpdateJellyfinLibraryPreferences(List Preferences) + : IRequest>; public record JellyfinLibraryPreference(int Id, bool ShouldSyncItems); diff --git a/ErsatzTV.Application/Jellyfin/Commands/UpdateJellyfinLibraryPreferencesHandler.cs b/ErsatzTV.Application/Jellyfin/Commands/UpdateJellyfinLibraryPreferencesHandler.cs index 856a2615..d6c2fa7c 100644 --- a/ErsatzTV.Application/Jellyfin/Commands/UpdateJellyfinLibraryPreferencesHandler.cs +++ b/ErsatzTV.Application/Jellyfin/Commands/UpdateJellyfinLibraryPreferencesHandler.cs @@ -6,7 +6,7 @@ namespace ErsatzTV.Application.Jellyfin; public class UpdateJellyfinLibraryPreferencesHandler : IRequestHandler> + Either> { private readonly IMediaSourceRepository _mediaSourceRepository; private readonly ISearchIndex _searchIndex; diff --git a/ErsatzTV.Application/Jellyfin/JellyfinLibraryViewModel.cs b/ErsatzTV.Application/Jellyfin/JellyfinLibraryViewModel.cs index 923def50..40865c92 100644 --- a/ErsatzTV.Application/Jellyfin/JellyfinLibraryViewModel.cs +++ b/ErsatzTV.Application/Jellyfin/JellyfinLibraryViewModel.cs @@ -4,9 +4,9 @@ using ErsatzTV.Core.Domain; namespace ErsatzTV.Application.Jellyfin; public record JellyfinLibraryViewModel( - int Id, - string Name, - LibraryMediaKind MediaKind, - bool ShouldSyncItems, - int MediaSourceId) + int Id, + string Name, + LibraryMediaKind MediaKind, + bool ShouldSyncItems, + int MediaSourceId) : LibraryViewModel("Jellyfin", Id, Name, MediaKind, MediaSourceId, string.Empty); diff --git a/ErsatzTV.Application/Jellyfin/Queries/GetAllJellyfinMediaSourcesHandler.cs b/ErsatzTV.Application/Jellyfin/Queries/GetAllJellyfinMediaSourcesHandler.cs index aa65fac1..b969b994 100644 --- a/ErsatzTV.Application/Jellyfin/Queries/GetAllJellyfinMediaSourcesHandler.cs +++ b/ErsatzTV.Application/Jellyfin/Queries/GetAllJellyfinMediaSourcesHandler.cs @@ -5,7 +5,7 @@ namespace ErsatzTV.Application.Jellyfin; public class GetAllJellyfinMediaSourcesHandler : IRequestHandler> + List> { private readonly IMediaSourceRepository _mediaSourceRepository; diff --git a/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinLibrariesBySourceIdHandler.cs b/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinLibrariesBySourceIdHandler.cs index 9491118d..0f7a1386 100644 --- a/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinLibrariesBySourceIdHandler.cs +++ b/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinLibrariesBySourceIdHandler.cs @@ -5,7 +5,7 @@ namespace ErsatzTV.Application.Jellyfin; public class GetJellyfinLibrariesBySourceIdHandler : IRequestHandler> + List> { private readonly IMediaSourceRepository _mediaSourceRepository; diff --git a/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinMediaSourceById.cs b/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinMediaSourceById.cs index f730e26f..7fc48802 100644 --- a/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinMediaSourceById.cs +++ b/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinMediaSourceById.cs @@ -1,4 +1,3 @@ namespace ErsatzTV.Application.Jellyfin; -public record GetJellyfinMediaSourceById - (int JellyfinMediaSourceId) : IRequest>; +public record GetJellyfinMediaSourceById(int JellyfinMediaSourceId) : IRequest>; diff --git a/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinMediaSourceByIdHandler.cs b/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinMediaSourceByIdHandler.cs index 70b8b8f1..74d718fe 100644 --- a/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinMediaSourceByIdHandler.cs +++ b/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinMediaSourceByIdHandler.cs @@ -5,7 +5,7 @@ namespace ErsatzTV.Application.Jellyfin; public class GetJellyfinMediaSourceByIdHandler : IRequestHandler> + Option> { private readonly IMediaSourceRepository _mediaSourceRepository; diff --git a/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinPathReplacementsBySourceId.cs b/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinPathReplacementsBySourceId.cs index 2f920b3d..3fb3c2c8 100644 --- a/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinPathReplacementsBySourceId.cs +++ b/ErsatzTV.Application/Jellyfin/Queries/GetJellyfinPathReplacementsBySourceId.cs @@ -1,4 +1,4 @@ namespace ErsatzTV.Application.Jellyfin; -public record GetJellyfinPathReplacementsBySourceId - (int JellyfinMediaSourceId) : IRequest>; +public record GetJellyfinPathReplacementsBySourceId(int JellyfinMediaSourceId) + : IRequest>; diff --git a/ErsatzTV.Application/Libraries/Commands/CallLibraryScannerHandler.cs b/ErsatzTV.Application/Libraries/Commands/CallLibraryScannerHandler.cs index ad72da6b..4bf22fd3 100644 --- a/ErsatzTV.Application/Libraries/Commands/CallLibraryScannerHandler.cs +++ b/ErsatzTV.Application/Libraries/Commands/CallLibraryScannerHandler.cs @@ -13,6 +13,7 @@ using ErsatzTV.Infrastructure.Data; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using Serilog; +using Serilog.Core; using Serilog.Events; using Serilog.Formatting.Compact.Reader; @@ -20,6 +21,7 @@ namespace ErsatzTV.Application.Libraries; public abstract class CallLibraryScannerHandler { + private readonly int _batchSize = 100; private readonly ChannelWriter _channel; private readonly IConfigElementRepository _configElementRepository; private readonly IDbContextFactory _dbContextFactory; @@ -27,7 +29,6 @@ public abstract class CallLibraryScannerHandler private readonly IRuntimeInfo _runtimeInfo; private readonly List _toReindex = []; private readonly List _toRemove = []; - private readonly int _batchSize = 100; private string _libraryName; protected CallLibraryScannerHandler( @@ -74,7 +75,7 @@ public abstract class CallLibraryScannerHandler await _channel.WriteAsync(new ReindexMediaItems(_toReindex.ToArray()), cancellationToken); _toReindex.Clear(); } - + if (_toRemove.Count > 0) { await _channel.WriteAsync(new RemoveMediaItems(_toReindex.ToArray()), cancellationToken); @@ -104,10 +105,10 @@ public abstract class CallLibraryScannerHandler if (logEvent.Properties.TryGetValue("SourceContext", out LogEventPropertyValue property)) { log = log.ForContext( - Serilog.Core.Constants.SourceContextPropertyName, + Constants.SourceContextPropertyName, property.ToString().Trim('"')); } - + log.Write( new LogEvent( logEvent.Timestamp.ToLocalTime(), @@ -143,7 +144,7 @@ public abstract class CallLibraryScannerHandler await _channel.WriteAsync(new ReindexMediaItems(_toReindex.ToArray())); _toReindex.Clear(); } - + _toRemove.AddRange(progressUpdate.ItemsToRemove); if (_toRemove.Count >= _batchSize) { diff --git a/ErsatzTV.Application/Libraries/Commands/CreateLocalLibraryHandler.cs b/ErsatzTV.Application/Libraries/Commands/CreateLocalLibraryHandler.cs index c6ac9280..fbaca344 100644 --- a/ErsatzTV.Application/Libraries/Commands/CreateLocalLibraryHandler.cs +++ b/ErsatzTV.Application/Libraries/Commands/CreateLocalLibraryHandler.cs @@ -32,7 +32,7 @@ public class CreateLocalLibraryHandler : LocalLibraryHandlerBase, { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply(validation, localLibrary => PersistLocalLibrary(dbContext, localLibrary)); + return await validation.Apply(localLibrary => PersistLocalLibrary(dbContext, localLibrary)); } private async Task PersistLocalLibrary( diff --git a/ErsatzTV.Application/Libraries/Commands/CreateLocalLibraryPath.cs b/ErsatzTV.Application/Libraries/Commands/CreateLocalLibraryPath.cs index 29c6289e..1a210549 100644 --- a/ErsatzTV.Application/Libraries/Commands/CreateLocalLibraryPath.cs +++ b/ErsatzTV.Application/Libraries/Commands/CreateLocalLibraryPath.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Application.Libraries; -public record CreateLocalLibraryPath - (int LibraryId, string Path) : IRequest>; +public record CreateLocalLibraryPath(int LibraryId, string Path) + : IRequest>; diff --git a/ErsatzTV.Application/Libraries/Commands/DeleteLocalLibraryHandler.cs b/ErsatzTV.Application/Libraries/Commands/DeleteLocalLibraryHandler.cs index 6e75f673..1cd04e18 100644 --- a/ErsatzTV.Application/Libraries/Commands/DeleteLocalLibraryHandler.cs +++ b/ErsatzTV.Application/Libraries/Commands/DeleteLocalLibraryHandler.cs @@ -28,7 +28,7 @@ public class DeleteLocalLibraryHandler : LocalLibraryHandlerBase, { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await LocalLibraryMustExist(dbContext, request); - return await LanguageExtensions.Apply(validation, localLibrary => DoDeletion(dbContext, localLibrary)); + return await validation.Apply(localLibrary => DoDeletion(dbContext, localLibrary)); } private async Task DoDeletion(TvContext dbContext, LocalLibrary localLibrary) diff --git a/ErsatzTV.Application/Libraries/Commands/MoveLocalLibraryPathHandler.cs b/ErsatzTV.Application/Libraries/Commands/MoveLocalLibraryPathHandler.cs index 6f4e0ac8..ca58c908 100644 --- a/ErsatzTV.Application/Libraries/Commands/MoveLocalLibraryPathHandler.cs +++ b/ErsatzTV.Application/Libraries/Commands/MoveLocalLibraryPathHandler.cs @@ -39,7 +39,7 @@ public class MoveLocalLibraryPathHandler : IRequestHandler validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply(validation, parameters => MovePath(dbContext, parameters)); + return await validation.Apply(parameters => MovePath(dbContext, parameters)); } private async Task MovePath(TvContext dbContext, Parameters parameters) diff --git a/ErsatzTV.Application/Libraries/Commands/UpdateLocalLibraryHandler.cs b/ErsatzTV.Application/Libraries/Commands/UpdateLocalLibraryHandler.cs index c90f32dc..85005014 100644 --- a/ErsatzTV.Application/Libraries/Commands/UpdateLocalLibraryHandler.cs +++ b/ErsatzTV.Application/Libraries/Commands/UpdateLocalLibraryHandler.cs @@ -37,7 +37,7 @@ public class UpdateLocalLibraryHandler : LocalLibraryHandlerBase, { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply(validation, parameters => UpdateLocalLibrary(dbContext, parameters)); + return await validation.Apply(parameters => UpdateLocalLibrary(dbContext, parameters)); } private async Task UpdateLocalLibrary(TvContext dbContext, Parameters parameters) diff --git a/ErsatzTV.Application/Libraries/PlexLibraryViewModel.cs b/ErsatzTV.Application/Libraries/PlexLibraryViewModel.cs index c8fd2ef8..93cdb42b 100644 --- a/ErsatzTV.Application/Libraries/PlexLibraryViewModel.cs +++ b/ErsatzTV.Application/Libraries/PlexLibraryViewModel.cs @@ -3,9 +3,9 @@ namespace ErsatzTV.Application.Libraries; public record PlexLibraryViewModel( - int Id, - string Name, - LibraryMediaKind MediaKind, - int MediaSourceId, - string MediaSourceName) + int Id, + string Name, + LibraryMediaKind MediaKind, + int MediaSourceId, + string MediaSourceName) : LibraryViewModel("Plex", Id, Name, MediaKind, MediaSourceId, MediaSourceName); diff --git a/ErsatzTV.Application/MediaCards/ArtistCardViewModel.cs b/ErsatzTV.Application/MediaCards/ArtistCardViewModel.cs index e1183d0f..1722c7ab 100644 --- a/ErsatzTV.Application/MediaCards/ArtistCardViewModel.cs +++ b/ErsatzTV.Application/MediaCards/ArtistCardViewModel.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.MediaCards; -public record ArtistCardViewModel -( +public record ArtistCardViewModel( int ArtistId, string Title, string Subtitle, diff --git a/ErsatzTV.Application/MediaCards/ImageCardViewModel.cs b/ErsatzTV.Application/MediaCards/ImageCardViewModel.cs index d33e809e..6442558d 100644 --- a/ErsatzTV.Application/MediaCards/ImageCardViewModel.cs +++ b/ErsatzTV.Application/MediaCards/ImageCardViewModel.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.MediaCards; -public record ImageCardViewModel -( +public record ImageCardViewModel( int ImageId, string Title, string Subtitle, diff --git a/ErsatzTV.Application/MediaCards/MovieCardViewModel.cs b/ErsatzTV.Application/MediaCards/MovieCardViewModel.cs index 5b14bd78..3e0db59e 100644 --- a/ErsatzTV.Application/MediaCards/MovieCardViewModel.cs +++ b/ErsatzTV.Application/MediaCards/MovieCardViewModel.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.MediaCards; -public record MovieCardViewModel -( +public record MovieCardViewModel( int MovieId, string Title, string Subtitle, diff --git a/ErsatzTV.Application/MediaCards/MusicVideoCardViewModel.cs b/ErsatzTV.Application/MediaCards/MusicVideoCardViewModel.cs index baa1890f..baa4694d 100644 --- a/ErsatzTV.Application/MediaCards/MusicVideoCardViewModel.cs +++ b/ErsatzTV.Application/MediaCards/MusicVideoCardViewModel.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.MediaCards; -public record MusicVideoCardViewModel -( +public record MusicVideoCardViewModel( int MusicVideoId, string Title, string Subtitle, diff --git a/ErsatzTV.Application/MediaCards/OtherVideoCardViewModel.cs b/ErsatzTV.Application/MediaCards/OtherVideoCardViewModel.cs index f06476a0..914fe118 100644 --- a/ErsatzTV.Application/MediaCards/OtherVideoCardViewModel.cs +++ b/ErsatzTV.Application/MediaCards/OtherVideoCardViewModel.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.MediaCards; -public record OtherVideoCardViewModel -( +public record OtherVideoCardViewModel( int OtherVideoId, string Title, string Subtitle, diff --git a/ErsatzTV.Application/MediaCards/Queries/GetMusicVideoCards.cs b/ErsatzTV.Application/MediaCards/Queries/GetMusicVideoCards.cs index 99cac8aa..e9a4eddd 100644 --- a/ErsatzTV.Application/MediaCards/Queries/GetMusicVideoCards.cs +++ b/ErsatzTV.Application/MediaCards/Queries/GetMusicVideoCards.cs @@ -1,4 +1,3 @@ namespace ErsatzTV.Application.MediaCards; -public record GetMusicVideoCards - (int ArtistId, int PageNumber, int PageSize) : IRequest; +public record GetMusicVideoCards(int ArtistId, int PageNumber, int PageSize) : IRequest; diff --git a/ErsatzTV.Application/MediaCards/Queries/GetTelevisionEpisodeCards.cs b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionEpisodeCards.cs index 345898af..cfc7e502 100644 --- a/ErsatzTV.Application/MediaCards/Queries/GetTelevisionEpisodeCards.cs +++ b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionEpisodeCards.cs @@ -1,4 +1,4 @@ namespace ErsatzTV.Application.MediaCards; -public record GetTelevisionEpisodeCards - (int TelevisionSeasonId, int PageNumber, int PageSize) : IRequest; +public record GetTelevisionEpisodeCards(int TelevisionSeasonId, int PageNumber, int PageSize) + : IRequest; diff --git a/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCards.cs b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCards.cs index 40a30fa9..4eea8118 100644 --- a/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCards.cs +++ b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCards.cs @@ -1,4 +1,4 @@ namespace ErsatzTV.Application.MediaCards; -public record GetTelevisionSeasonCards - (int TelevisionShowId, int PageNumber, int PageSize) : IRequest; +public record GetTelevisionSeasonCards(int TelevisionShowId, int PageNumber, int PageSize) + : IRequest; diff --git a/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCardsHandler.cs b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCardsHandler.cs index 1b343544..7f08dbbb 100644 --- a/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCardsHandler.cs +++ b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCardsHandler.cs @@ -6,7 +6,7 @@ namespace ErsatzTV.Application.MediaCards; public class GetTelevisionSeasonCardsHandler : IRequestHandler + TelevisionSeasonCardResultsViewModel> { private readonly IMediaSourceRepository _mediaSourceRepository; private readonly ITelevisionRepository _televisionRepository; diff --git a/ErsatzTV.Application/MediaCards/SongCardViewModel.cs b/ErsatzTV.Application/MediaCards/SongCardViewModel.cs index 35668fd1..04a15ac9 100644 --- a/ErsatzTV.Application/MediaCards/SongCardViewModel.cs +++ b/ErsatzTV.Application/MediaCards/SongCardViewModel.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.MediaCards; -public record SongCardViewModel -( +public record SongCardViewModel( int SongId, string Title, string Subtitle, diff --git a/ErsatzTV.Application/MediaCards/TelevisionEpisodeCardViewModel.cs b/ErsatzTV.Application/MediaCards/TelevisionEpisodeCardViewModel.cs index 2b52bea8..394d1109 100644 --- a/ErsatzTV.Application/MediaCards/TelevisionEpisodeCardViewModel.cs +++ b/ErsatzTV.Application/MediaCards/TelevisionEpisodeCardViewModel.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.MediaCards; -public record TelevisionEpisodeCardViewModel -( +public record TelevisionEpisodeCardViewModel( int EpisodeId, DateTime Aired, string ShowTitle, diff --git a/ErsatzTV.Application/MediaCards/TelevisionSeasonCardViewModel.cs b/ErsatzTV.Application/MediaCards/TelevisionSeasonCardViewModel.cs index ab5ab474..e51a5bf8 100644 --- a/ErsatzTV.Application/MediaCards/TelevisionSeasonCardViewModel.cs +++ b/ErsatzTV.Application/MediaCards/TelevisionSeasonCardViewModel.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.MediaCards; -public record TelevisionSeasonCardViewModel -( +public record TelevisionSeasonCardViewModel( string ShowTitle, int TelevisionSeasonId, int TelevisionSeasonNumber, diff --git a/ErsatzTV.Application/MediaCards/TelevisionShowCardViewModel.cs b/ErsatzTV.Application/MediaCards/TelevisionShowCardViewModel.cs index addd3888..e6f77cd0 100644 --- a/ErsatzTV.Application/MediaCards/TelevisionShowCardViewModel.cs +++ b/ErsatzTV.Application/MediaCards/TelevisionShowCardViewModel.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.MediaCards; -public record TelevisionShowCardViewModel -( +public record TelevisionShowCardViewModel( int TelevisionShowId, string Title, string Subtitle, diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddArtistToCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/AddArtistToCollection.cs index 63bbee49..01ef7fbe 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddArtistToCollection.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddArtistToCollection.cs @@ -2,5 +2,4 @@ namespace ErsatzTV.Application.MediaCollections; -public record AddArtistToCollection - (int CollectionId, int ArtistId) : IRequest>; +public record AddArtistToCollection(int CollectionId, int ArtistId) : IRequest>; diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddArtistToCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddArtistToCollectionHandler.cs index 713cdb0b..4f261b94 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddArtistToCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddArtistToCollectionHandler.cs @@ -33,7 +33,7 @@ public class AddArtistToCollectionHandler : { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply(validation, parameters => ApplyAddArtistRequest(dbContext, parameters)); + return await validation.Apply(parameters => ApplyAddArtistRequest(dbContext, parameters)); } private async Task ApplyAddArtistRequest(TvContext dbContext, Parameters parameters) diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollectionHandler.cs index bcc49bed..36b1deae 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollectionHandler.cs @@ -33,9 +33,7 @@ public class AddEpisodeToCollectionHandler : { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply( - validation, - parameters => ApplyAddTelevisionEpisodeRequest(dbContext, parameters)); + return await validation.Apply(parameters => ApplyAddTelevisionEpisodeRequest(dbContext, parameters)); } private async Task ApplyAddTelevisionEpisodeRequest(TvContext dbContext, Parameters parameters) diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddItemsToCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/AddItemsToCollection.cs index d6521c96..37c725d0 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddItemsToCollection.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddItemsToCollection.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.MediaCollections; -public record AddItemsToCollection -( +public record AddItemsToCollection( int CollectionId, List MovieIds, List ShowIds, diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddMovieToCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddMovieToCollectionHandler.cs index a7b4ca5f..194911c9 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddMovieToCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddMovieToCollectionHandler.cs @@ -33,7 +33,7 @@ public class AddMovieToCollectionHandler : { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply(validation, parameters => ApplyAddMovieRequest(dbContext, parameters)); + return await validation.Apply(parameters => ApplyAddMovieRequest(dbContext, parameters)); } private async Task ApplyAddMovieRequest(TvContext dbContext, Parameters parameters) diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddMusicVideoToCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/AddMusicVideoToCollection.cs index 97570ed9..8ae69131 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddMusicVideoToCollection.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddMusicVideoToCollection.cs @@ -2,5 +2,4 @@ namespace ErsatzTV.Application.MediaCollections; -public record AddMusicVideoToCollection - (int CollectionId, int MusicVideoId) : IRequest>; +public record AddMusicVideoToCollection(int CollectionId, int MusicVideoId) : IRequest>; diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddMusicVideoToCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddMusicVideoToCollectionHandler.cs index 1d468dd7..6af44700 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddMusicVideoToCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddMusicVideoToCollectionHandler.cs @@ -33,9 +33,7 @@ public class AddMusicVideoToCollectionHandler : { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply( - validation, - parameters => ApplyAddMusicVideoRequest(dbContext, parameters)); + return await validation.Apply(parameters => ApplyAddMusicVideoRequest(dbContext, parameters)); } private async Task ApplyAddMusicVideoRequest(TvContext dbContext, Parameters parameters) diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddOtherVideoToCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/AddOtherVideoToCollection.cs index ccf799d0..10a716e9 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddOtherVideoToCollection.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddOtherVideoToCollection.cs @@ -2,5 +2,4 @@ namespace ErsatzTV.Application.MediaCollections; -public record AddOtherVideoToCollection - (int CollectionId, int OtherVideoId) : IRequest>; +public record AddOtherVideoToCollection(int CollectionId, int OtherVideoId) : IRequest>; diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddOtherVideoToCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddOtherVideoToCollectionHandler.cs index 5f9b847c..9ac8a4ad 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddOtherVideoToCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddOtherVideoToCollectionHandler.cs @@ -33,9 +33,7 @@ public class AddOtherVideoToCollectionHandler : { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply( - validation, - parameters => ApplyAddOtherVideoRequest(dbContext, parameters)); + return await validation.Apply(parameters => ApplyAddOtherVideoRequest(dbContext, parameters)); } private async Task ApplyAddOtherVideoRequest(TvContext dbContext, Parameters parameters) diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollectionHandler.cs index c65fc998..09c74401 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollectionHandler.cs @@ -33,7 +33,7 @@ public class AddSeasonToCollectionHandler : { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply(validation, parameters => ApplyAddSeasonRequest(dbContext, parameters)); + return await validation.Apply(parameters => ApplyAddSeasonRequest(dbContext, parameters)); } private async Task ApplyAddSeasonRequest(TvContext dbContext, Parameters parameters) diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddShowToCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddShowToCollectionHandler.cs index 19e53bb4..507b1b67 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddShowToCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddShowToCollectionHandler.cs @@ -33,7 +33,7 @@ public class AddShowToCollectionHandler : { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply(validation, parameters => ApplyAddShowRequest(dbContext, parameters)); + return await validation.Apply(parameters => ApplyAddShowRequest(dbContext, parameters)); } private async Task ApplyAddShowRequest(TvContext dbContext, Parameters parameters) diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddSongToCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/AddSongToCollection.cs index 5125246b..73d227e7 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddSongToCollection.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddSongToCollection.cs @@ -2,5 +2,4 @@ namespace ErsatzTV.Application.MediaCollections; -public record AddSongToCollection - (int CollectionId, int SongId) : IRequest>; +public record AddSongToCollection(int CollectionId, int SongId) : IRequest>; diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddSongToCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddSongToCollectionHandler.cs index ca58ed3a..0eb64b8e 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddSongToCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddSongToCollectionHandler.cs @@ -33,7 +33,7 @@ public class AddSongToCollectionHandler : { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply(validation, parameters => ApplyAddSongRequest(dbContext, parameters)); + return await validation.Apply(parameters => ApplyAddSongRequest(dbContext, parameters)); } private async Task ApplyAddSongRequest(TvContext dbContext, Parameters parameters) diff --git a/ErsatzTV.Application/MediaCollections/Commands/CreateMultiCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/CreateMultiCollection.cs index bdf6cd1a..a3830c13 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/CreateMultiCollection.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/CreateMultiCollection.cs @@ -9,5 +9,5 @@ public record CreateMultiCollectionItem( bool ScheduleAsGroup, PlaybackOrder PlaybackOrder); -public record CreateMultiCollection - (string Name, List Items) : IRequest>; +public record CreateMultiCollection(string Name, List Items) + : IRequest>; diff --git a/ErsatzTV.Application/MediaCollections/Commands/CreateSmartCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/CreateSmartCollection.cs index d033ddd8..9f1c93c7 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/CreateSmartCollection.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/CreateSmartCollection.cs @@ -2,5 +2,4 @@ namespace ErsatzTV.Application.MediaCollections; -public record CreateSmartCollection - (string Query, string Name) : IRequest>; +public record CreateSmartCollection(string Query, string Name) : IRequest>; diff --git a/ErsatzTV.Application/MediaCollections/Commands/DeleteTraktListHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/DeleteTraktListHandler.cs index eb7fcb3a..31061cbe 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/DeleteTraktListHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/DeleteTraktListHandler.cs @@ -44,7 +44,7 @@ public class DeleteTraktListHandler : TraktCommandBase, IRequestHandler validation = await TraktListMustExist(dbContext, request.TraktListId); - return await LanguageExtensions.Apply(validation, c => DoDeletion(dbContext, c)); + return await validation.Apply(c => DoDeletion(dbContext, c)); } finally { diff --git a/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollectionHandler.cs index 4830caca..fed792d7 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollectionHandler.cs @@ -32,7 +32,7 @@ public class RemoveItemsFromCollectionHandler : IRequestHandler validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply(validation, c => ApplyRemoveItemsRequest(dbContext, request, c)); + return await validation.Apply(c => ApplyRemoveItemsRequest(dbContext, request, c)); } private async Task ApplyRemoveItemsRequest( diff --git a/ErsatzTV.Application/MediaCollections/Commands/UpdateCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/UpdateCollection.cs index ed4b425c..14eb36dd 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/UpdateCollection.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/UpdateCollection.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.MediaCollections; -public record UpdateCollection - (int CollectionId, string Name) : IRequest> +public record UpdateCollection(int CollectionId, string Name) : IRequest> { public Option UseCustomPlaybackOrder { get; set; } = None; } diff --git a/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionCustomOrder.cs b/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionCustomOrder.cs index 48fe22f9..0e7c44b6 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionCustomOrder.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionCustomOrder.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.MediaCollections; -public record UpdateCollectionCustomOrder -( +public record UpdateCollectionCustomOrder( int CollectionId, List MediaItemCustomOrders) : IRequest>; diff --git a/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionCustomOrderHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionCustomOrderHandler.cs index 54231aca..2bb24975 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionCustomOrderHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionCustomOrderHandler.cs @@ -32,7 +32,7 @@ public class UpdateCollectionCustomOrderHandler : IRequestHandler validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply(validation, c => ApplyUpdateRequest(dbContext, c, request)); + return await validation.Apply(c => ApplyUpdateRequest(dbContext, c, request)); } private async Task ApplyUpdateRequest( diff --git a/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionHandler.cs index d46fd061..db18eded 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionHandler.cs @@ -14,9 +14,9 @@ namespace ErsatzTV.Application.MediaCollections; public class UpdateCollectionHandler : IRequestHandler> { private readonly ChannelWriter _channel; - private readonly ISearchTargets _searchTargets; private readonly IDbContextFactory _dbContextFactory; private readonly IMediaCollectionRepository _mediaCollectionRepository; + private readonly ISearchTargets _searchTargets; public UpdateCollectionHandler( IDbContextFactory dbContextFactory, @@ -56,7 +56,7 @@ public class UpdateCollectionHandler : IRequestHandler Items) : IRequest>; diff --git a/ErsatzTV.Application/MediaCollections/Commands/UpdateMultiCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/UpdateMultiCollectionHandler.cs index 53354c6c..1fe93f6a 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/UpdateMultiCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/UpdateMultiCollectionHandler.cs @@ -14,9 +14,9 @@ namespace ErsatzTV.Application.MediaCollections; public class UpdateMultiCollectionHandler : IRequestHandler> { private readonly ChannelWriter _channel; - private readonly ISearchTargets _searchTargets; private readonly IDbContextFactory _dbContextFactory; private readonly IMediaCollectionRepository _mediaCollectionRepository; + private readonly ISearchTargets _searchTargets; public UpdateMultiCollectionHandler( IDbContextFactory dbContextFactory, @@ -36,7 +36,7 @@ public class UpdateMultiCollectionHandler : IRequestHandler validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply(validation, c => ApplyUpdateRequest(dbContext, c, request)); + return await validation.Apply(c => ApplyUpdateRequest(dbContext, c, request)); } private async Task ApplyUpdateRequest(TvContext dbContext, MultiCollection c, UpdateMultiCollection request) @@ -120,7 +120,7 @@ public class UpdateMultiCollectionHandler : IRequestHandler 0) { _searchTargets.SearchTargetsChanged(); - + // refresh all playouts that use this collection foreach (int playoutId in await _mediaCollectionRepository.PlayoutIdsUsingMultiCollection( request.MultiCollectionId)) diff --git a/ErsatzTV.Application/MediaCollections/Commands/UpdateSmartCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/UpdateSmartCollectionHandler.cs index ccb38ae6..38595cf6 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/UpdateSmartCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/UpdateSmartCollectionHandler.cs @@ -14,9 +14,9 @@ namespace ErsatzTV.Application.MediaCollections; public class UpdateSmartCollectionHandler : IRequestHandler> { private readonly ChannelWriter _channel; - private readonly ISearchTargets _searchTargets; private readonly IDbContextFactory _dbContextFactory; private readonly IMediaCollectionRepository _mediaCollectionRepository; + private readonly ISearchTargets _searchTargets; public UpdateSmartCollectionHandler( IDbContextFactory dbContextFactory, diff --git a/ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs b/ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs index 42b40cc8..3849f881 100644 --- a/ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs +++ b/ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs @@ -17,13 +17,13 @@ namespace ErsatzTV.Application.Playouts; public class BuildPlayoutHandler : IRequestHandler> { + private readonly IBlockPlayoutBuilder _blockPlayoutBuilder; private readonly IClient _client; private readonly IDbContextFactory _dbContextFactory; private readonly IEntityLocker _entityLocker; + private readonly IExternalJsonPlayoutBuilder _externalJsonPlayoutBuilder; private readonly IFFmpegSegmenterService _ffmpegSegmenterService; private readonly IPlayoutBuilder _playoutBuilder; - private readonly IBlockPlayoutBuilder _blockPlayoutBuilder; - private readonly IExternalJsonPlayoutBuilder _externalJsonPlayoutBuilder; private readonly ChannelWriter _workerChannel; public BuildPlayoutHandler( @@ -100,7 +100,8 @@ public class BuildPlayoutHandler : IRequestHandler> { - private readonly ILocalFileSystem _localFileSystem; private readonly ChannelWriter _channel; private readonly IDbContextFactory _dbContextFactory; + private readonly ILocalFileSystem _localFileSystem; public CreateExternalJsonPlayoutHandler( ILocalFileSystem localFileSystem, @@ -27,7 +27,7 @@ public class CreateExternalJsonPlayoutHandler _channel = channel; _dbContextFactory = dbContextFactory; } - + public async Task> Handle( CreateExternalJsonPlayout request, CancellationToken cancellationToken) diff --git a/ErsatzTV.Application/Playouts/Commands/CreateFloodPlayoutHandler.cs b/ErsatzTV.Application/Playouts/Commands/CreateFloodPlayoutHandler.cs index 4bd4bc80..ad7f44aa 100644 --- a/ErsatzTV.Application/Playouts/Commands/CreateFloodPlayoutHandler.cs +++ b/ErsatzTV.Application/Playouts/Commands/CreateFloodPlayoutHandler.cs @@ -41,7 +41,9 @@ public class CreateFloodPlayoutHandler : IRequestHandler> Validate(TvContext dbContext, CreateFloodPlayout request) => + private static async Task> Validate( + TvContext dbContext, + CreateFloodPlayout request) => (await ValidateChannel(dbContext, request), await ValidateProgramSchedule(dbContext, request), ValidatePlayoutType(request)) .Apply( diff --git a/ErsatzTV.Application/Playouts/Commands/ReplacePlayoutAlternateScheduleItems.cs b/ErsatzTV.Application/Playouts/Commands/ReplacePlayoutAlternateScheduleItems.cs index 5bb736c4..dd5b7fc7 100644 --- a/ErsatzTV.Application/Playouts/Commands/ReplacePlayoutAlternateScheduleItems.cs +++ b/ErsatzTV.Application/Playouts/Commands/ReplacePlayoutAlternateScheduleItems.cs @@ -2,5 +2,5 @@ using ErsatzTV.Core; namespace ErsatzTV.Application.Playouts; -public record ReplacePlayoutAlternateScheduleItems - (int PlayoutId, List Items) : IRequest>; +public record ReplacePlayoutAlternateScheduleItems(int PlayoutId, List Items) + : IRequest>; diff --git a/ErsatzTV.Application/Playouts/Commands/UpdateExternalJsonPlayoutHandler.cs b/ErsatzTV.Application/Playouts/Commands/UpdateExternalJsonPlayoutHandler.cs index aac9a83a..d76e8fe2 100644 --- a/ErsatzTV.Application/Playouts/Commands/UpdateExternalJsonPlayoutHandler.cs +++ b/ErsatzTV.Application/Playouts/Commands/UpdateExternalJsonPlayoutHandler.cs @@ -8,7 +8,9 @@ using Microsoft.EntityFrameworkCore; namespace ErsatzTV.Application.Playouts; -public class UpdateExternalJsonPlayoutHandler : IRequestHandler> +public class + UpdateExternalJsonPlayoutHandler : IRequestHandler> { private readonly IDbContextFactory _dbContextFactory; private readonly ChannelWriter _workerChannel; @@ -52,7 +54,9 @@ public class UpdateExternalJsonPlayoutHandler : IRequestHandler> Validate(TvContext dbContext, UpdateExternalJsonPlayout request) => + private static Task> Validate( + TvContext dbContext, + UpdateExternalJsonPlayout request) => PlayoutMustExist(dbContext, request); private static Task> PlayoutMustExist( diff --git a/ErsatzTV.Application/Playouts/Commands/UpdatePlayout.cs b/ErsatzTV.Application/Playouts/Commands/UpdatePlayout.cs index 7a04d5f9..b637f79b 100644 --- a/ErsatzTV.Application/Playouts/Commands/UpdatePlayout.cs +++ b/ErsatzTV.Application/Playouts/Commands/UpdatePlayout.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Application.Playouts; -public record UpdatePlayout - (int PlayoutId, Option DailyRebuildTime) : IRequest>; +public record UpdatePlayout(int PlayoutId, Option DailyRebuildTime) + : IRequest>; diff --git a/ErsatzTV.Application/Playouts/Queries/GetFuturePlayoutItemsById.cs b/ErsatzTV.Application/Playouts/Queries/GetFuturePlayoutItemsById.cs index 9f3b04ec..4cd090d5 100644 --- a/ErsatzTV.Application/Playouts/Queries/GetFuturePlayoutItemsById.cs +++ b/ErsatzTV.Application/Playouts/Queries/GetFuturePlayoutItemsById.cs @@ -1,4 +1,4 @@ namespace ErsatzTV.Application.Playouts; -public record GetFuturePlayoutItemsById - (int PlayoutId, bool ShowFiller, int PageNum, int PageSize) : IRequest; +public record GetFuturePlayoutItemsById(int PlayoutId, bool ShowFiller, int PageNum, int PageSize) + : IRequest; diff --git a/ErsatzTV.Application/Plex/Commands/UpdatePlexLibraryPreferences.cs b/ErsatzTV.Application/Plex/Commands/UpdatePlexLibraryPreferences.cs index c29011ba..3cb06c8d 100644 --- a/ErsatzTV.Application/Plex/Commands/UpdatePlexLibraryPreferences.cs +++ b/ErsatzTV.Application/Plex/Commands/UpdatePlexLibraryPreferences.cs @@ -2,7 +2,6 @@ namespace ErsatzTV.Application.Plex; -public record UpdatePlexLibraryPreferences - (List Preferences) : IRequest>; +public record UpdatePlexLibraryPreferences(List Preferences) : IRequest>; public record PlexLibraryPreference(int Id, bool ShouldSyncItems); diff --git a/ErsatzTV.Application/Plex/Commands/UpdatePlexLibraryPreferencesHandler.cs b/ErsatzTV.Application/Plex/Commands/UpdatePlexLibraryPreferencesHandler.cs index 4a3db7f5..23d497f4 100644 --- a/ErsatzTV.Application/Plex/Commands/UpdatePlexLibraryPreferencesHandler.cs +++ b/ErsatzTV.Application/Plex/Commands/UpdatePlexLibraryPreferencesHandler.cs @@ -6,7 +6,7 @@ namespace ErsatzTV.Application.Plex; public class UpdatePlexLibraryPreferencesHandler : IRequestHandler> + Either> { private readonly IMediaSourceRepository _mediaSourceRepository; private readonly ISearchIndex _searchIndex; diff --git a/ErsatzTV.Application/Plex/Commands/UpdatePlexPathReplacements.cs b/ErsatzTV.Application/Plex/Commands/UpdatePlexPathReplacements.cs index 372917b7..ba7a8b38 100644 --- a/ErsatzTV.Application/Plex/Commands/UpdatePlexPathReplacements.cs +++ b/ErsatzTV.Application/Plex/Commands/UpdatePlexPathReplacements.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.Plex; -public record UpdatePlexPathReplacements -( +public record UpdatePlexPathReplacements( int PlexMediaSourceId, List PathReplacements) : IRequest>; diff --git a/ErsatzTV.Application/Plex/Queries/GetPlexConnectionParameters.cs b/ErsatzTV.Application/Plex/Queries/GetPlexConnectionParameters.cs index dd176a3e..0bd7f2ca 100644 --- a/ErsatzTV.Application/Plex/Queries/GetPlexConnectionParameters.cs +++ b/ErsatzTV.Application/Plex/Queries/GetPlexConnectionParameters.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Application.Plex; -public record GetPlexConnectionParameters - (int PlexMediaSourceId) : IRequest>; +public record GetPlexConnectionParameters(int PlexMediaSourceId) + : IRequest>; diff --git a/ErsatzTV.Application/Plex/Queries/GetPlexPathReplacementsBySourceId.cs b/ErsatzTV.Application/Plex/Queries/GetPlexPathReplacementsBySourceId.cs index b8825b40..db332edb 100644 --- a/ErsatzTV.Application/Plex/Queries/GetPlexPathReplacementsBySourceId.cs +++ b/ErsatzTV.Application/Plex/Queries/GetPlexPathReplacementsBySourceId.cs @@ -1,4 +1,3 @@ namespace ErsatzTV.Application.Plex; -public record GetPlexPathReplacementsBySourceId - (int PlexMediaSourceId) : IRequest>; +public record GetPlexPathReplacementsBySourceId(int PlexMediaSourceId) : IRequest>; diff --git a/ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItemHandler.cs b/ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItemHandler.cs index d5b941a5..19897c63 100644 --- a/ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItemHandler.cs +++ b/ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItemHandler.cs @@ -29,7 +29,7 @@ public class AddProgramScheduleItemHandler : ProgramScheduleItemCommandBase, { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply(validation, ps => PersistItem(dbContext, request, ps)); + return await validation.Apply(ps => PersistItem(dbContext, request, ps)); } private async Task PersistItem( diff --git a/ErsatzTV.Application/ProgramSchedules/Commands/CopyProgramSchedule.cs b/ErsatzTV.Application/ProgramSchedules/Commands/CopyProgramSchedule.cs index 2c09f683..6422cc50 100644 --- a/ErsatzTV.Application/ProgramSchedules/Commands/CopyProgramSchedule.cs +++ b/ErsatzTV.Application/ProgramSchedules/Commands/CopyProgramSchedule.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Application.ProgramSchedules; -public record CopyProgramSchedule - (int ProgramScheduleId, string Name) : IRequest>; +public record CopyProgramSchedule(int ProgramScheduleId, string Name) + : IRequest>; diff --git a/ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs b/ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs index 3597eb89..d7822c5c 100644 --- a/ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs +++ b/ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs @@ -32,6 +32,5 @@ public record ReplaceProgramScheduleItem( string PreferredSubtitleLanguageCode, ChannelSubtitleMode? SubtitleMode) : IProgramScheduleItemRequest; -public record ReplaceProgramScheduleItems - (int ProgramScheduleId, List Items) : IRequest< - Either>>; +public record ReplaceProgramScheduleItems(int ProgramScheduleId, List Items) : IRequest< + Either>>; diff --git a/ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramSchedule.cs b/ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramSchedule.cs index 9fcafaa2..fbb061df 100644 --- a/ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramSchedule.cs +++ b/ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramSchedule.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.ProgramSchedules; -public record UpdateProgramSchedule -( +public record UpdateProgramSchedule( int ProgramScheduleId, string Name, bool KeepMultiPartEpisodesTogether, diff --git a/ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramScheduleHandler.cs b/ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramScheduleHandler.cs index 64b6dcf2..bfe67bc5 100644 --- a/ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramScheduleHandler.cs +++ b/ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramScheduleHandler.cs @@ -29,7 +29,7 @@ public class UpdateProgramScheduleHandler : { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); - return await LanguageExtensions.Apply(validation, ps => ApplyUpdateRequest(dbContext, ps, request)); + return await validation.Apply(ps => ApplyUpdateRequest(dbContext, ps, request)); } private async Task ApplyUpdateRequest( diff --git a/ErsatzTV.Application/Scheduling/Commands/CreateBlockGroupHandler.cs b/ErsatzTV.Application/Scheduling/Commands/CreateBlockGroupHandler.cs index 13e46693..2876f291 100644 --- a/ErsatzTV.Application/Scheduling/Commands/CreateBlockGroupHandler.cs +++ b/ErsatzTV.Application/Scheduling/Commands/CreateBlockGroupHandler.cs @@ -8,13 +8,15 @@ namespace ErsatzTV.Application.Scheduling; public class CreateBlockGroupHandler(IDbContextFactory dbContextFactory) : IRequestHandler> { - public async Task> Handle(CreateBlockGroup request, CancellationToken cancellationToken) + public async Task> Handle( + CreateBlockGroup request, + CancellationToken cancellationToken) { await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(request); return await validation.Apply(profile => PersistBlockGroup(dbContext, profile)); } - + private static async Task PersistBlockGroup(TvContext dbContext, BlockGroup blockGroup) { await dbContext.BlockGroups.AddAsync(blockGroup); @@ -24,7 +26,7 @@ public class CreateBlockGroupHandler(IDbContextFactory dbContextFacto private static Task> Validate(CreateBlockGroup request) => Task.FromResult(ValidateName(request).Map(name => new BlockGroup { Name = name, Blocks = [] })); - + private static Validation ValidateName(CreateBlockGroup createBlockGroup) => createBlockGroup.NotEmpty(x => x.Name) .Bind(_ => createBlockGroup.NotLongerThan(50)(x => x.Name)); diff --git a/ErsatzTV.Application/Scheduling/Commands/CreateBlockHandler.cs b/ErsatzTV.Application/Scheduling/Commands/CreateBlockHandler.cs index 2c515516..a87650ad 100644 --- a/ErsatzTV.Application/Scheduling/Commands/CreateBlockHandler.cs +++ b/ErsatzTV.Application/Scheduling/Commands/CreateBlockHandler.cs @@ -13,7 +13,7 @@ public class CreateBlockHandler(IDbContextFactory dbContextFactory) CancellationToken cancellationToken) { await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); - Validation validation = await Validate(request); + Validation validation = await Validate(dbContext, request); return await validation.Apply(profile => PersistBlock(dbContext, profile)); } @@ -24,17 +24,30 @@ public class CreateBlockHandler(IDbContextFactory dbContextFactory) return Mapper.ProjectToViewModel(block); } - private static Task> Validate(CreateBlock request) => - Task.FromResult( - ValidateName(request).Map( - name => new Block - { - BlockGroupId = request.BlockGroupId, - Name = name, - Minutes = 30 - })); + private static async Task> Validate(TvContext dbContext, CreateBlock request) => + await ValidateBlockName(dbContext, request).MapT( + name => new Block + { + BlockGroupId = request.BlockGroupId, + Name = name, + Minutes = 30 + }); - private static Validation ValidateName(CreateBlock createBlock) => - createBlock.NotEmpty(x => x.Name) - .Bind(_ => createBlock.NotLongerThan(50)(x => x.Name)); + private static async Task> ValidateBlockName( + TvContext dbContext, + CreateBlock request) + { + if (request.Name.Length > 50) + { + return BaseError.New($"Block name \"{request.Name}\" is invalid"); + } + + Option maybeExisting = await dbContext.Blocks + .FirstOrDefaultAsync(r => r.BlockGroupId == request.BlockGroupId && r.Name == request.Name) + .Map(Optional); + + return maybeExisting.IsSome + ? BaseError.New($"A block named \"{request.Name}\" already exists in that block group") + : request.Name; + } } diff --git a/ErsatzTV.Application/Scheduling/Commands/EraseBlockPlayoutItemsHandler.cs b/ErsatzTV.Application/Scheduling/Commands/EraseBlockPlayoutItemsHandler.cs index 01ba1528..ff86d6dc 100644 --- a/ErsatzTV.Application/Scheduling/Commands/EraseBlockPlayoutItemsHandler.cs +++ b/ErsatzTV.Application/Scheduling/Commands/EraseBlockPlayoutItemsHandler.cs @@ -40,7 +40,7 @@ public class EraseBlockPlayoutItemsHandler(IDbContextFactory dbContex // save history changes await dbContext.SaveChangesAsync(cancellationToken); - + // delete all playout items await dbContext.Database.ExecuteSqlAsync( $"DELETE FROM PlayoutItem WHERE PlayoutId = {playout.Id}", diff --git a/ErsatzTV.Application/Scheduling/Commands/ReplaceBlockItemsHandler.cs b/ErsatzTV.Application/Scheduling/Commands/ReplaceBlockItemsHandler.cs index cdfccd75..499fbcb2 100644 --- a/ErsatzTV.Application/Scheduling/Commands/ReplaceBlockItemsHandler.cs +++ b/ErsatzTV.Application/Scheduling/Commands/ReplaceBlockItemsHandler.cs @@ -28,7 +28,7 @@ public class ReplaceBlockItemsHandler(IDbContextFactory dbContextFact block.Minutes = request.Minutes; block.StopScheduling = request.StopScheduling; block.DateUpdated = DateTime.UtcNow; - + dbContext.RemoveRange(block.Items); block.Items = request.Items.Map(i => BuildItem(block, i.Index, i)).ToList(); @@ -67,7 +67,7 @@ public class ReplaceBlockItemsHandler(IDbContextFactory dbContextFact .Include(b => b.Items) .SelectOneAsync(b => b.Id, b => b.Id == blockId) .Map(o => o.ToValidation("[BlockId] does not exist.")); - + private static Validation MinutesMustBeValid(ReplaceBlockItems request, Block block) => Optional(block) .Filter(_ => request.Minutes > 0 && request.Minutes % 15 == 0 && request.Minutes <= 24 * 60) @@ -75,7 +75,7 @@ public class ReplaceBlockItemsHandler(IDbContextFactory dbContextFact private static Validation CollectionTypesMustBeValid(ReplaceBlockItems request, Block block) => request.Items.Map(item => CollectionTypeMustBeValid(item, block)).Sequence().Map(_ => block); - + private static Validation CollectionTypeMustBeValid(ReplaceBlockItem item, Block block) { switch (item.CollectionType) diff --git a/ErsatzTV.Application/Scheduling/Commands/ReplacePlayoutTemplateItemsHandler.cs b/ErsatzTV.Application/Scheduling/Commands/ReplacePlayoutTemplateItemsHandler.cs index e1ed3e5a..efd6681a 100644 --- a/ErsatzTV.Application/Scheduling/Commands/ReplacePlayoutTemplateItemsHandler.cs +++ b/ErsatzTV.Application/Scheduling/Commands/ReplacePlayoutTemplateItemsHandler.cs @@ -42,7 +42,7 @@ public class ReplacePlayoutTemplateItemsHandler( playout.Templates.Remove(remove); } - var now = DateTime.UtcNow; + DateTime now = DateTime.UtcNow; foreach (ReplacePlayoutTemplate add in toAdd) { @@ -71,7 +71,7 @@ public class ReplacePlayoutTemplateItemsHandler( ex.DateUpdated = now; } } - + await dbContext.SaveChangesAsync(cancellationToken); } diff --git a/ErsatzTV.Application/Scheduling/Queries/GetTemplateItemsHandler.cs b/ErsatzTV.Application/Scheduling/Queries/GetTemplateItemsHandler.cs index 29c269bd..6b721135 100644 --- a/ErsatzTV.Application/Scheduling/Queries/GetTemplateItemsHandler.cs +++ b/ErsatzTV.Application/Scheduling/Queries/GetTemplateItemsHandler.cs @@ -3,7 +3,8 @@ using Microsoft.EntityFrameworkCore; namespace ErsatzTV.Application.Scheduling; -public class GetTemplateItemsHandler(IDbContextFactory dbContextFactory) : IRequestHandler> +public class GetTemplateItemsHandler(IDbContextFactory dbContextFactory) + : IRequestHandler> { public async Task> Handle(GetTemplateItems request, CancellationToken cancellationToken) { diff --git a/ErsatzTV.Application/Search/Queries/QuerySearchIndexArtists.cs b/ErsatzTV.Application/Search/Queries/QuerySearchIndexArtists.cs index ee37543e..b4e5d898 100644 --- a/ErsatzTV.Application/Search/Queries/QuerySearchIndexArtists.cs +++ b/ErsatzTV.Application/Search/Queries/QuerySearchIndexArtists.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Application.Search; -public record QuerySearchIndexArtists - (string Query, int PageNumber, int PageSize) : IRequest; +public record QuerySearchIndexArtists(string Query, int PageNumber, int PageSize) + : IRequest; diff --git a/ErsatzTV.Application/Search/Queries/QuerySearchIndexEpisodes.cs b/ErsatzTV.Application/Search/Queries/QuerySearchIndexEpisodes.cs index 2dfaff47..9ec34ec7 100644 --- a/ErsatzTV.Application/Search/Queries/QuerySearchIndexEpisodes.cs +++ b/ErsatzTV.Application/Search/Queries/QuerySearchIndexEpisodes.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Application.Search; -public record QuerySearchIndexEpisodes - (string Query, int PageNumber, int PageSize) : IRequest; +public record QuerySearchIndexEpisodes(string Query, int PageNumber, int PageSize) + : IRequest; diff --git a/ErsatzTV.Application/Search/Queries/QuerySearchIndexImages.cs b/ErsatzTV.Application/Search/Queries/QuerySearchIndexImages.cs index a2745531..ed9d4d80 100644 --- a/ErsatzTV.Application/Search/Queries/QuerySearchIndexImages.cs +++ b/ErsatzTV.Application/Search/Queries/QuerySearchIndexImages.cs @@ -2,5 +2,4 @@ namespace ErsatzTV.Application.Search; -public record QuerySearchIndexImages - (string Query, int PageNumber, int PageSize) : IRequest; +public record QuerySearchIndexImages(string Query, int PageNumber, int PageSize) : IRequest; diff --git a/ErsatzTV.Application/Search/Queries/QuerySearchIndexMovies.cs b/ErsatzTV.Application/Search/Queries/QuerySearchIndexMovies.cs index f90f981a..6d1b23ab 100644 --- a/ErsatzTV.Application/Search/Queries/QuerySearchIndexMovies.cs +++ b/ErsatzTV.Application/Search/Queries/QuerySearchIndexMovies.cs @@ -2,5 +2,4 @@ namespace ErsatzTV.Application.Search; -public record QuerySearchIndexMovies - (string Query, int PageNumber, int PageSize) : IRequest; +public record QuerySearchIndexMovies(string Query, int PageNumber, int PageSize) : IRequest; diff --git a/ErsatzTV.Application/Search/Queries/QuerySearchIndexMusicVideos.cs b/ErsatzTV.Application/Search/Queries/QuerySearchIndexMusicVideos.cs index dfe0aae8..115596ac 100644 --- a/ErsatzTV.Application/Search/Queries/QuerySearchIndexMusicVideos.cs +++ b/ErsatzTV.Application/Search/Queries/QuerySearchIndexMusicVideos.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Application.Search; -public record QuerySearchIndexMusicVideos - (string Query, int PageNumber, int PageSize) : IRequest; +public record QuerySearchIndexMusicVideos(string Query, int PageNumber, int PageSize) + : IRequest; diff --git a/ErsatzTV.Application/Search/Queries/QuerySearchIndexOtherVideos.cs b/ErsatzTV.Application/Search/Queries/QuerySearchIndexOtherVideos.cs index 6890ace9..e1c29fe0 100644 --- a/ErsatzTV.Application/Search/Queries/QuerySearchIndexOtherVideos.cs +++ b/ErsatzTV.Application/Search/Queries/QuerySearchIndexOtherVideos.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Application.Search; -public record QuerySearchIndexOtherVideos - (string Query, int PageNumber, int PageSize) : IRequest; +public record QuerySearchIndexOtherVideos(string Query, int PageNumber, int PageSize) + : IRequest; diff --git a/ErsatzTV.Application/Search/Queries/QuerySearchIndexOtherVideosHandler.cs b/ErsatzTV.Application/Search/Queries/QuerySearchIndexOtherVideosHandler.cs index e8555ad2..5fb092df 100644 --- a/ErsatzTV.Application/Search/Queries/QuerySearchIndexOtherVideosHandler.cs +++ b/ErsatzTV.Application/Search/Queries/QuerySearchIndexOtherVideosHandler.cs @@ -9,7 +9,7 @@ namespace ErsatzTV.Application.Search; public class QuerySearchIndexOtherVideosHandler : IRequestHandler + OtherVideoCardResultsViewModel> { private readonly IClient _client; private readonly IOtherVideoRepository _otherVideoRepository; diff --git a/ErsatzTV.Application/Search/Queries/QuerySearchIndexSeasons.cs b/ErsatzTV.Application/Search/Queries/QuerySearchIndexSeasons.cs index c04e5ea5..771ba983 100644 --- a/ErsatzTV.Application/Search/Queries/QuerySearchIndexSeasons.cs +++ b/ErsatzTV.Application/Search/Queries/QuerySearchIndexSeasons.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Application.Search; -public record QuerySearchIndexSeasons - (string Query, int PageNumber, int PageSize) : IRequest; +public record QuerySearchIndexSeasons(string Query, int PageNumber, int PageSize) + : IRequest; diff --git a/ErsatzTV.Application/Search/Queries/QuerySearchIndexShows.cs b/ErsatzTV.Application/Search/Queries/QuerySearchIndexShows.cs index 9e0ce37d..50ce27db 100644 --- a/ErsatzTV.Application/Search/Queries/QuerySearchIndexShows.cs +++ b/ErsatzTV.Application/Search/Queries/QuerySearchIndexShows.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Application.Search; -public record QuerySearchIndexShows - (string Query, int PageNumber, int PageSize) : IRequest; +public record QuerySearchIndexShows(string Query, int PageNumber, int PageSize) + : IRequest; diff --git a/ErsatzTV.Application/Search/Queries/QuerySearchIndexSongs.cs b/ErsatzTV.Application/Search/Queries/QuerySearchIndexSongs.cs index 199ad792..282a2f0b 100644 --- a/ErsatzTV.Application/Search/Queries/QuerySearchIndexSongs.cs +++ b/ErsatzTV.Application/Search/Queries/QuerySearchIndexSongs.cs @@ -2,5 +2,4 @@ namespace ErsatzTV.Application.Search; -public record QuerySearchIndexSongs - (string Query, int PageNumber, int PageSize) : IRequest; +public record QuerySearchIndexSongs(string Query, int PageNumber, int PageSize) : IRequest; diff --git a/ErsatzTV.Application/Streaming/Commands/StartFFmpegSessionHandler.cs b/ErsatzTV.Application/Streaming/Commands/StartFFmpegSessionHandler.cs index 6cf42e68..8e1ab175 100644 --- a/ErsatzTV.Application/Streaming/Commands/StartFFmpegSessionHandler.cs +++ b/ErsatzTV.Application/Streaming/Commands/StartFFmpegSessionHandler.cs @@ -77,7 +77,7 @@ public class StartFFmpegSessionHandler : IRequestHandler _targetFramerate; + private CancellationTokenSource _cancellationTokenSource; private string _channelNumber; private bool _disposedValue; private bool _hasWrittenSegments; @@ -39,7 +40,6 @@ public class HlsSessionWorker : IHlsSessionWorker private HlsSessionState _state; private Timer _timer; private DateTimeOffset _transcodedUntil; - private CancellationTokenSource _cancellationTokenSource; public HlsSessionWorker( IServiceScopeFactory serviceScopeFactory, @@ -136,7 +136,7 @@ public class HlsSessionWorker : IHlsSessionWorker } public void PlayoutUpdated() => _state = HlsSessionState.PlayoutUpdated; - + public HlsSessionModel GetModel() => new(_channelNumber, _state.ToString(), _transcodedUntil, _lastAccess); void IDisposable.Dispose() @@ -240,19 +240,19 @@ public class HlsSessionWorker : IHlsSessionWorker } } } - + public async Task WaitForPlaylistSegments( int initialSegmentCount, CancellationToken cancellationToken) { _logger.LogDebug("Waiting for playlist segments..."); - + var sw = Stopwatch.StartNew(); try { DateTimeOffset start = DateTimeOffset.Now; DateTimeOffset finish = start.AddSeconds(8); - + string playlistFileName = Path.Combine(FileSystemLayout.TranscodeFolder, _channelNumber, "live.m3u8"); _logger.LogDebug("Waiting for playlist to exist"); diff --git a/ErsatzTV.Application/Streaming/HlsSessionWorkerV2.cs b/ErsatzTV.Application/Streaming/HlsSessionWorkerV2.cs index 915a2f96..0d3b8c8c 100644 --- a/ErsatzTV.Application/Streaming/HlsSessionWorkerV2.cs +++ b/ErsatzTV.Application/Streaming/HlsSessionWorkerV2.cs @@ -19,6 +19,7 @@ namespace ErsatzTV.Application.Streaming; public class HlsSessionWorkerV2 : IHlsSessionWorker { private static readonly SemaphoreSlim Slim = new(1, 1); + //private static int _workAheadCount; private readonly IConfigElementRepository _configElementRepository; private readonly string _host; @@ -33,11 +34,11 @@ public class HlsSessionWorkerV2 : IHlsSessionWorker private bool _disposedValue; private bool _hasWrittenSegments; private DateTimeOffset _lastAccess; + private Option _lastProcessModel; private IServiceScope _serviceScope; private HlsSessionState _state; private Timer _timer; private DateTimeOffset _transcodedUntil; - private Option _lastProcessModel; public HlsSessionWorkerV2( IServiceScopeFactory serviceScopeFactory, @@ -90,10 +91,8 @@ public class HlsSessionWorkerV2 : IHlsSessionWorker public Task> TrimPlaylist( DateTimeOffset filterBefore, - CancellationToken cancellationToken) - { - return Task.FromResult(Option.None); - } + CancellationToken cancellationToken) => + Task.FromResult(Option.None); public void PlayoutUpdated() => _state = HlsSessionState.PlayoutUpdated; @@ -250,7 +249,7 @@ public class HlsSessionWorkerV2 : IHlsSessionWorker _logger.LogDebug("WaitForPlaylistSegments took {Duration}", sw.Elapsed); } } - + public async Task> GetNextPlayoutItemProcess() { foreach (PlayoutItemProcessModel processModel in _lastProcessModel) @@ -278,11 +277,11 @@ public class HlsSessionWorkerV2 : IHlsSessionWorker _state = nextState; } } - + _logger.LogDebug("Getting next playout item process with state {@State}", _state); //long ptsOffset = await GetPtsOffset(_channelNumber, CancellationToken.None); - + bool startAtZero = _state is HlsSessionState.ZeroAndRealtime or HlsSessionState.ZeroAndWorkAhead; bool realtime = _state is HlsSessionState.ZeroAndRealtime or HlsSessionState.SeekAndRealtime; @@ -311,7 +310,7 @@ public class HlsSessionWorkerV2 : IHlsSessionWorker { _lastProcessModel = Option.None; } - + return result; } @@ -367,7 +366,7 @@ public class HlsSessionWorkerV2 : IHlsSessionWorker return result; } - + private async Task GetPtsOffset(string channelNumber, CancellationToken cancellationToken) { await Slim.WaitAsync(cancellationToken); diff --git a/ErsatzTV.Application/Streaming/Queries/FFmpegProcessRequest.cs b/ErsatzTV.Application/Streaming/Queries/FFmpegProcessRequest.cs index bc2f3ed4..681b4bbd 100644 --- a/ErsatzTV.Application/Streaming/Queries/FFmpegProcessRequest.cs +++ b/ErsatzTV.Application/Streaming/Queries/FFmpegProcessRequest.cs @@ -2,8 +2,7 @@ namespace ErsatzTV.Application.Streaming; -public record FFmpegProcessRequest -( +public record FFmpegProcessRequest( string ChannelNumber, string Mode, DateTimeOffset Now, diff --git a/ErsatzTV.Application/Streaming/Queries/GetConcatPlaylistByChannelNumber.cs b/ErsatzTV.Application/Streaming/Queries/GetConcatPlaylistByChannelNumber.cs index caed2795..10192488 100644 --- a/ErsatzTV.Application/Streaming/Queries/GetConcatPlaylistByChannelNumber.cs +++ b/ErsatzTV.Application/Streaming/Queries/GetConcatPlaylistByChannelNumber.cs @@ -3,5 +3,5 @@ using ErsatzTV.Core.FFmpeg; namespace ErsatzTV.Application.Streaming; -public record GetConcatPlaylistByChannelNumber - (string Scheme, string Host, string ChannelNumber, string Mode) : IRequest>; +public record GetConcatPlaylistByChannelNumber(string Scheme, string Host, string ChannelNumber, string Mode) + : IRequest>; diff --git a/ErsatzTV.Application/Streaming/Queries/GetConcatPlaylistByChannelNumberHandler.cs b/ErsatzTV.Application/Streaming/Queries/GetConcatPlaylistByChannelNumberHandler.cs index 765e2075..b7623f1a 100644 --- a/ErsatzTV.Application/Streaming/Queries/GetConcatPlaylistByChannelNumberHandler.cs +++ b/ErsatzTV.Application/Streaming/Queries/GetConcatPlaylistByChannelNumberHandler.cs @@ -7,7 +7,7 @@ namespace ErsatzTV.Application.Streaming; public class GetConcatPlaylistByChannelNumberHandler : IRequestHandler> + Either> { private readonly IChannelRepository _channelRepository; diff --git a/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumber.cs b/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumber.cs index da2fb236..9e100ac2 100644 --- a/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumber.cs +++ b/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumber.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Application.Streaming; -public record GetHlsPlaylistByChannelNumber - (string Scheme, string Host, string ChannelNumber, string Mode) : IRequest>; +public record GetHlsPlaylistByChannelNumber(string Scheme, string Host, string ChannelNumber, string Mode) + : IRequest>; diff --git a/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumberHandler.cs b/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumberHandler.cs index 197d2894..ec31b144 100644 --- a/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumberHandler.cs +++ b/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumberHandler.cs @@ -28,9 +28,7 @@ public class GetHlsPlaylistByChannelNumberHandler : await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); DateTimeOffset now = DateTimeOffset.Now; Validation validation = await Validate(dbContext, request, now); - return await LanguageExtensions.Apply( - validation, - parameters => GetPlaylist(dbContext, request, parameters, now)); + return await validation.Apply(parameters => GetPlaylist(dbContext, request, parameters, now)); } private Task GetPlaylist( diff --git a/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs b/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs index 15e8a269..6450d72c 100644 --- a/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs +++ b/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs @@ -26,10 +26,10 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< { private readonly IArtistRepository _artistRepository; private readonly IEmbyPathReplacementService _embyPathReplacementService; + private readonly IExternalJsonPlayoutItemProvider _externalJsonPlayoutItemProvider; private readonly IFFmpegProcessService _ffmpegProcessService; private readonly IJellyfinPathReplacementService _jellyfinPathReplacementService; private readonly ILocalFileSystem _localFileSystem; - private readonly IExternalJsonPlayoutItemProvider _externalJsonPlayoutItemProvider; private readonly ILogger _logger; private readonly IMediaCollectionRepository _mediaCollectionRepository; private readonly IMusicVideoCreditsGenerator _musicVideoCreditsGenerator; @@ -151,12 +151,12 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< .ForChannelAndTime(channel.Id, now) .Map(o => o.ToEither(new UnableToLocatePlayoutItem())) .BindT(item => ValidatePlayoutItemPath(dbContext, item)); - + if (maybePlayoutItem.LeftAsEnumerable().Any(e => e is UnableToLocatePlayoutItem)) { maybePlayoutItem = await _externalJsonPlayoutItemProvider.CheckForExternalJson(channel, now, ffprobePath); } - + if (maybePlayoutItem.LeftAsEnumerable().Any(e => e is UnableToLocatePlayoutItem)) { maybePlayoutItem = await CheckForFallbackFiller(dbContext, channel, now); diff --git a/ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedSubtitlesHandler.cs b/ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedSubtitlesHandler.cs index 3ee1018a..4e4ce661 100644 --- a/ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedSubtitlesHandler.cs +++ b/ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedSubtitlesHandler.cs @@ -23,9 +23,9 @@ namespace ErsatzTV.Application.Subtitles; [SuppressMessage("Security", "CA5351:Do Not Use Broken Cryptographic Algorithms")] public class ExtractEmbeddedSubtitlesHandler : IRequestHandler> { + private readonly IConfigElementRepository _configElementRepository; private readonly IDbContextFactory _dbContextFactory; private readonly IEntityLocker _entityLocker; - private readonly IConfigElementRepository _configElementRepository; private readonly ILocalFileSystem _localFileSystem; private readonly ILogger _logger; private readonly ChannelWriter _workerChannel; @@ -79,7 +79,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler.None; } - + bool extractEmbeddedSubtitles = await _configElementRepository .GetValue(ConfigElementKey.FFmpegExtractEmbeddedSubtitles) .IfNoneAsync(false); @@ -89,7 +89,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler.None; } - + DateTime now = DateTime.UtcNow; DateTime until = now.AddHours(1); @@ -287,7 +287,9 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler s.Codec != "hdmv_pgs_subtitle" && s.Codec != "dvd_subtitle" && s.Codec != "dvdsub" && s.Codec != "vobsub" && s.Codec != "pgssub" && s.Codec != "pgs") - .Filter(s => s.IsExtracted == false || string.IsNullOrWhiteSpace(s.Path) || FileDoesntExist(mediaItem.Id, s)); + .Filter( + s => s.IsExtracted == false || string.IsNullOrWhiteSpace(s.Path) || + FileDoesntExist(mediaItem.Id, s)); // find cache paths for each subtitle foreach (Subtitle subtitle in subtitles) @@ -355,7 +357,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler>; +public record CopyWatermark(int WatermarkId, string Name) : IRequest>; diff --git a/ErsatzTV.Application/Watermarks/Commands/CopyWatermarkHandler.cs b/ErsatzTV.Application/Watermarks/Commands/CopyWatermarkHandler.cs index 5d9681bd..1f4c0157 100644 --- a/ErsatzTV.Application/Watermarks/Commands/CopyWatermarkHandler.cs +++ b/ErsatzTV.Application/Watermarks/Commands/CopyWatermarkHandler.cs @@ -41,7 +41,7 @@ public class CopyWatermarkHandler : clone.Name = request.Name; await dbContext.SaveChangesAsync(); - + _searchTargets.SearchTargetsChanged(); return ProjectToViewModel(clone); diff --git a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj index 78fc33ff..6f0c020f 100644 --- a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj +++ b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj @@ -10,19 +10,19 @@ - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/ErsatzTV.Core.Tests/Scheduling/BlockScheduling/BlockPlayoutChangeDetectionTests.cs b/ErsatzTV.Core.Tests/Scheduling/BlockScheduling/BlockPlayoutChangeDetectionTests.cs index 62cc37fc..a9db5c47 100644 --- a/ErsatzTV.Core.Tests/Scheduling/BlockScheduling/BlockPlayoutChangeDetectionTests.cs +++ b/ErsatzTV.Core.Tests/Scheduling/BlockScheduling/BlockPlayoutChangeDetectionTests.cs @@ -15,24 +15,24 @@ public static class BlockPlayoutChangeDetectionTests { // takes playout items, item block keys and effective blocks // returns blocks to schedule and playout items to remove - + // test case: nothing has changed - + // test case: block has moved from one time to another time, nothing after // test case: block has moved from one time to another time, same block after // test case: block has moved from one time to another time, different block with same collection after // test case: block was moved from one time to another time, different block with different collection after - + // test case: block was removed, nothing after // test case: block was removed, same block after // test case: block was removed, different block with same collection after // test case: block was removed, different block with different collection after - + // test case: block was added, nothing after // test case: block was added, same block after // test case: block was added, different block with same collection after // test case: block was added, different block with different collection after - + [Test] public void Should_Work_When_Nothing_Has_Changed() @@ -65,7 +65,7 @@ public static class BlockPlayoutChangeDetectionTests List effectiveBlocks = [ new EffectiveBlock(block1, blockKey1, GetLocalDate(2024, 1, 17).AddHours(9), 1), - new EffectiveBlock(block2, blockKey2, GetLocalDate(2024, 1, 17).AddHours(13), 2), + new EffectiveBlock(block2, blockKey2, GetLocalDate(2024, 1, 17).AddHours(13), 2) ]; Map collectionEtags = LanguageExt.Map.Empty; @@ -80,7 +80,7 @@ public static class BlockPlayoutChangeDetectionTests // nothing to schedule result.Item1.Should().HaveCount(0); - + // do not need to remove any playout items or history result.Item2.Should().HaveCount(0); } @@ -165,7 +165,7 @@ public static class BlockPlayoutChangeDetectionTests CollectionKey = JsonConvert.SerializeObject(collectionKey), CollectionEtag = JsonConvert.SerializeObject(collectionKey) }; - + private static DateTimeOffset GetLocalDate(int year, int month, int day) => new(year, month, day, 0, 0, 0, TimeSpan.FromHours(-6)); } diff --git a/ErsatzTV.Core.Tests/Scheduling/BlockScheduling/EffectiveBlockTests.cs b/ErsatzTV.Core.Tests/Scheduling/BlockScheduling/EffectiveBlockTests.cs index f0243193..109c0a05 100644 --- a/ErsatzTV.Core.Tests/Scheduling/BlockScheduling/EffectiveBlockTests.cs +++ b/ErsatzTV.Core.Tests/Scheduling/BlockScheduling/EffectiveBlockTests.cs @@ -7,6 +7,38 @@ namespace ErsatzTV.Core.Tests.Scheduling.BlockScheduling; public static class EffectiveBlockTests { + private static DateTimeOffset GetLocalDate(int year, int month, int day) => + new(year, month, day, 0, 0, 0, TimeSpan.FromHours(-6)); + + private static Template SingleBlockTemplate(DateTimeOffset dateUpdated) + { + var template = new Template + { + Id = 1, + Items = + [ + new TemplateItem + { + Block = new Block + { + Id = 1, + DateUpdated = dateUpdated.UtcDateTime + }, + StartTime = TimeSpan.FromHours(9) + } + ], + DateUpdated = dateUpdated.UtcDateTime + }; + + // this is used for navigation + foreach (TemplateItem item in template.Items) + { + item.Template = template; + } + + return template; + } + [TestFixture] public class GetEffectiveBlocks { @@ -14,7 +46,7 @@ public static class EffectiveBlockTests public void Should_Work_With_No_Matching_Days() { DateTimeOffset now = DateTimeOffset.Now; - + List templates = [ new PlayoutTemplate @@ -27,19 +59,19 @@ public static class EffectiveBlockTests DateUpdated = now.UtcDateTime } ]; - + DateTimeOffset start = GetLocalDate(2024, 1, 15).AddHours(9); - List result = EffectiveBlock.GetEffectiveBlocks(templates, start, daysToBuild: 5); + List result = EffectiveBlock.GetEffectiveBlocks(templates, start, 5); result.Should().HaveCount(0); } - + [Test] public void Should_Work_With_Blank_Days() { DateTimeOffset now = DateTimeOffset.Now; - + List templates = [ new PlayoutTemplate @@ -55,55 +87,23 @@ public static class EffectiveBlockTests DateTimeOffset start = GetLocalDate(2024, 1, 15).AddHours(9); - List result = EffectiveBlock.GetEffectiveBlocks(templates, start, daysToBuild: 5); + List result = EffectiveBlock.GetEffectiveBlocks(templates, start, 5); result.Should().HaveCount(3); - + result[0].Start.DayOfWeek.Should().Be(DayOfWeek.Monday); result[0].Start.Date.Should().Be(GetLocalDate(2024, 1, 15).Date); - + result[1].Start.DayOfWeek.Should().Be(DayOfWeek.Wednesday); result[1].Start.Date.Should().Be(GetLocalDate(2024, 1, 17).Date); result[2].Start.DayOfWeek.Should().Be(DayOfWeek.Friday); result[2].Start.Date.Should().Be(GetLocalDate(2024, 1, 19).Date); } - + // TODO: test when clocks spring forward // TODO: test when clocks fall back - - // TODO: offset may be incorrect on days with time change, since start offset is re-used - } - - private static DateTimeOffset GetLocalDate(int year, int month, int day) => - new(year, month, day, 0, 0, 0, TimeSpan.FromHours(-6)); - - private static Template SingleBlockTemplate(DateTimeOffset dateUpdated) - { - var template = new Template - { - Id = 1, - Items = - [ - new TemplateItem - { - Block = new Block - { - Id = 1, - DateUpdated = dateUpdated.UtcDateTime - }, - StartTime = TimeSpan.FromHours(9) - } - ], - DateUpdated = dateUpdated.UtcDateTime - }; - // this is used for navigation - foreach (TemplateItem item in template.Items) - { - item.Template = template; - } - - return template; + // TODO: offset may be incorrect on days with time change, since start offset is re-used } } diff --git a/ErsatzTV.Core/Domain/MediaItem/Image.cs b/ErsatzTV.Core/Domain/MediaItem/Image.cs index 8d7da0c5..e9520abf 100644 --- a/ErsatzTV.Core/Domain/MediaItem/Image.cs +++ b/ErsatzTV.Core/Domain/MediaItem/Image.cs @@ -3,7 +3,7 @@ namespace ErsatzTV.Core.Domain; public class Image : MediaItem { public static readonly int DefaultSeconds = 15; - + public List ImageMetadata { get; set; } public List MediaVersions { get; set; } } diff --git a/ErsatzTV.Core/Domain/MediaItem/MediaFile.cs b/ErsatzTV.Core/Domain/MediaItem/MediaFile.cs index 99b50791..6f566a2f 100644 --- a/ErsatzTV.Core/Domain/MediaItem/MediaFile.cs +++ b/ErsatzTV.Core/Domain/MediaItem/MediaFile.cs @@ -7,7 +7,7 @@ public class MediaFile public int MediaVersionId { get; set; } public MediaVersion MediaVersion { get; set; } - + public int? LibraryFolderId { get; set; } public LibraryFolder LibraryFolder { get; set; } } diff --git a/ErsatzTV.Core/Domain/ProgramScheduleItemCollectionType.cs b/ErsatzTV.Core/Domain/ProgramScheduleItemCollectionType.cs index 32f6f94b..2adcb01b 100644 --- a/ErsatzTV.Core/Domain/ProgramScheduleItemCollectionType.cs +++ b/ErsatzTV.Core/Domain/ProgramScheduleItemCollectionType.cs @@ -8,6 +8,6 @@ public enum ProgramScheduleItemCollectionType Artist = 3, MultiCollection = 4, SmartCollection = 5, - + FakeCollection = 100 } diff --git a/ErsatzTV.Core/Domain/Scheduling/PlayoutHistory.cs b/ErsatzTV.Core/Domain/Scheduling/PlayoutHistory.cs index d7f83c6a..0b927e08 100644 --- a/ErsatzTV.Core/Domain/Scheduling/PlayoutHistory.cs +++ b/ErsatzTV.Core/Domain/Scheduling/PlayoutHistory.cs @@ -3,18 +3,18 @@ namespace ErsatzTV.Core.Domain.Scheduling; public class PlayoutHistory { public int Id { get; set; } - + public int PlayoutId { get; set; } public Playout Playout { get; set; } - + public int BlockId { get; set; } public Block Block { get; set; } public PlaybackOrder PlaybackOrder { get; set; } public int Index { get; set; } - + // something that uniquely identifies the collection within the block public string Key { get; set; } - + // last occurence of an item from this collection in the playout public DateTime When { get; set; } diff --git a/ErsatzTV.Core/ErsatzTV.Core.csproj b/ErsatzTV.Core/ErsatzTV.Core.csproj index dbb5efd7..3973ab7f 100644 --- a/ErsatzTV.Core/ErsatzTV.Core.csproj +++ b/ErsatzTV.Core/ErsatzTV.Core.csproj @@ -10,17 +10,17 @@ - + - - + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs b/ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs index 51ad508e..39719a19 100644 --- a/ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs +++ b/ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs @@ -237,7 +237,8 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService Option subtitleInputFile = maybeSubtitle.Map>( subtitle => { - if (!subtitle.IsImage && subtitle.SubtitleKind == SubtitleKind.Embedded && (!subtitle.IsExtracted || string.IsNullOrWhiteSpace(subtitle.Path))) + if (!subtitle.IsImage && subtitle.SubtitleKind == SubtitleKind.Embedded && + (!subtitle.IsExtracted || string.IsNullOrWhiteSpace(subtitle.Path))) { _logger.LogWarning("Subtitles are not yet available for this item"); return None; @@ -591,7 +592,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService FFmpegPlaybackSettings playbackSettings = FFmpegPlaybackSettingsCalculator.CalculateConcatSegmenterSettings( channel.FFmpegProfile, Option.None); - + playbackSettings.AudioDuration = Option.None; string audioFormat = playbackSettings.AudioFormat switch @@ -622,25 +623,25 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService }; var ffmpegVideoStream = new VideoStream( - Index: 0, - Codec: VideoFormat.Raw, + 0, + VideoFormat.Raw, Some(pixelFormat), ColorParams.Default, resolution, - MaybeSampleAspectRatio: "1:1", - DisplayAspectRatio: string.Empty, - FrameRate: Option.None, - StillImage: false, + "1:1", + string.Empty, + Option.None, + false, ScanKind.Progressive); var videoInputFile = new VideoInputFile(concatInputFile.Url, new List { ffmpegVideoStream }); - var ffmpegAudioStream = new AudioStream(Index: 1, Codec: string.Empty, channel.FFmpegProfile.AudioChannels); + var ffmpegAudioStream = new AudioStream(1, string.Empty, channel.FFmpegProfile.AudioChannels); Option audioInputFile = new AudioInputFile( concatInputFile.Url, new List { ffmpegAudioStream }, audioState); - + Option subtitleInputFile = Option.None; Option watermarkInputFile = Option.None; @@ -649,7 +650,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService HardwareAccelerationMode hwAccel = GetHardwareAccelerationMode(playbackSettings, FillerKind.None); Option hlsPlaylistPath = Path.Combine(FileSystemLayout.TranscodeFolder, channel.Number, "live.m3u8"); - + Option hlsSegmentTemplate = Path.Combine( FileSystemLayout.TranscodeFolder, channel.Number, @@ -657,13 +658,13 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService var desiredState = new FrameState( playbackSettings.RealtimeOutput, - InfiniteLoop: true, + true, videoFormat, - VideoProfile: Option.None, + Option.None, Optional(playbackSettings.PixelFormat), - ScaledSize: resolution, - PaddedSize: resolution, - CroppedSize: Option.None, + resolution, + resolution, + Option.None, false, playbackSettings.FrameRate, playbackSettings.VideoBitrate, @@ -676,22 +677,22 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService var ffmpegState = new FFmpegState( saveReports, - DecoderHardwareAccelerationMode: HardwareAccelerationMode.None, - EncoderHardwareAccelerationMode: hwAccel, + HardwareAccelerationMode.None, + hwAccel, vaapiDriver, vaapiDevice, playbackSettings.StreamSeek, - Finish: Option.None, + Option.None, channel.StreamingMode != StreamingMode.HttpLiveStreamingDirect, "ErsatzTV", channel.Name, - MetadataAudioLanguage: Option.None, - MetadataSubtitleLanguage: Option.None, - MetadataSubtitleTitle: Option.None, - OutputFormat: OutputFormatKind.Hls, + Option.None, + Option.None, + Option.None, + OutputFormatKind.Hls, hlsPlaylistPath, hlsSegmentTemplate, - PtsOffset: 0, + 0, playbackSettings.ThreadCount, Optional(channel.FFmpegProfile.QsvExtraHardwareFrames)); @@ -711,7 +712,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService ffmpegPath); FFmpegPipeline pipeline = pipelineBuilder.Build(ffmpegState, desiredState); - + // copy video input options to concat input concatInputFile.InputOptions.AddRange(videoInputFile.InputOptions); diff --git a/ErsatzTV.Core/FFmpeg/FFmpegSegmenterService.cs b/ErsatzTV.Core/FFmpeg/FFmpegSegmenterService.cs index b90c1d1c..bc3392aa 100644 --- a/ErsatzTV.Core/FFmpeg/FFmpegSegmenterService.cs +++ b/ErsatzTV.Core/FFmpeg/FFmpegSegmenterService.cs @@ -11,14 +11,14 @@ public class FFmpegSegmenterService(ILogger logger) : IF public event EventHandler OnWorkersChanged; public ICollection Workers => _sessionWorkers.Values; - + public bool TryGetWorker(string channelNumber, out IHlsSessionWorker worker) => _sessionWorkers.TryGetValue(channelNumber, out worker); public bool TryAddWorker(string channelNumber, IHlsSessionWorker worker) { var result = false; - + // check for worker if (TryGetWorker(channelNumber, out IHlsSessionWorker existing)) { @@ -27,7 +27,7 @@ public class FFmpegSegmenterService(ILogger logger) : IF { result = true; } - + // if worker is not null, we cannot add one (so result should stay false) } else @@ -35,12 +35,12 @@ public class FFmpegSegmenterService(ILogger logger) : IF // worker does not exist, so try adding a null one result = _sessionWorkers.TryAdd(channelNumber, worker); } - + if (result) { OnWorkersChanged?.Invoke(this, EventArgs.Empty); } - + return result; } diff --git a/ErsatzTV.Core/FFmpeg/FFmpegStreamSelector.cs b/ErsatzTV.Core/FFmpeg/FFmpegStreamSelector.cs index edf22372..4c056794 100644 --- a/ErsatzTV.Core/FFmpeg/FFmpegStreamSelector.cs +++ b/ErsatzTV.Core/FFmpeg/FFmpegStreamSelector.cs @@ -148,7 +148,8 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector subtitles = subtitles.Filter(s => s.SubtitleKind is not SubtitleKind.Embedded).ToList(); } - foreach (Subtitle subtitle in subtitles.Filter(s => s.SubtitleKind is SubtitleKind.Embedded && !s.IsImage).ToList()) + foreach (Subtitle subtitle in subtitles.Filter(s => s.SubtitleKind is SubtitleKind.Embedded && !s.IsImage) + .ToList()) { if (subtitle.IsExtracted == false) { @@ -167,7 +168,7 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector subtitles.Remove(subtitle); } } - + var allCodes = new List(); string language = (preferredSubtitleLanguage ?? string.Empty).ToLowerInvariant(); if (string.IsNullOrWhiteSpace(language)) diff --git a/ErsatzTV.Core/FileSystemLayout.cs b/ErsatzTV.Core/FileSystemLayout.cs index 440f42e0..cbf1bd3c 100644 --- a/ErsatzTV.Core/FileSystemLayout.cs +++ b/ErsatzTV.Core/FileSystemLayout.cs @@ -16,7 +16,7 @@ public static class FileSystemLayout "etv-transcode"); public static readonly string DataProtectionFolder = Path.Combine(AppDataFolder, "data-protection"); - + public static readonly string LogsFolder = Path.Combine(AppDataFolder, "logs"); public static readonly string DatabasePath = Path.Combine(AppDataFolder, "ersatztv.sqlite3"); diff --git a/ErsatzTV.Core/Interfaces/FFmpeg/IFFmpegSegmenterService.cs b/ErsatzTV.Core/Interfaces/FFmpeg/IFFmpegSegmenterService.cs index ec8e34e0..fa42e705 100644 --- a/ErsatzTV.Core/Interfaces/FFmpeg/IFFmpegSegmenterService.cs +++ b/ErsatzTV.Core/Interfaces/FFmpeg/IFFmpegSegmenterService.cs @@ -2,8 +2,8 @@ public interface IFFmpegSegmenterService { - event EventHandler OnWorkersChanged; ICollection Workers { get; } + event EventHandler OnWorkersChanged; bool TryGetWorker(string channelNumber, out IHlsSessionWorker worker); bool TryAddWorker(string channelNumber, IHlsSessionWorker worker); void AddOrUpdateWorker(string channelNumber, IHlsSessionWorker worker); diff --git a/ErsatzTV.Core/Interfaces/Metadata/ILocalStatisticsProvider.cs b/ErsatzTV.Core/Interfaces/Metadata/ILocalStatisticsProvider.cs index d8682c8e..235e4f8e 100644 --- a/ErsatzTV.Core/Interfaces/Metadata/ILocalStatisticsProvider.cs +++ b/ErsatzTV.Core/Interfaces/Metadata/ILocalStatisticsProvider.cs @@ -5,7 +5,7 @@ namespace ErsatzTV.Core.Interfaces.Metadata; public interface ILocalStatisticsProvider { Task> GetStatistics(string ffprobePath, string path); - + Task> RefreshStatistics(string ffmpegPath, string ffprobePath, MediaItem mediaItem); Either> GetSongTags(MediaItem mediaItem); diff --git a/ErsatzTV.Core/Interfaces/Repositories/IImageRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/IImageRepository.cs index 65107b1d..fac2b80e 100644 --- a/ErsatzTV.Core/Interfaces/Repositories/IImageRepository.cs +++ b/ErsatzTV.Core/Interfaces/Repositories/IImageRepository.cs @@ -9,6 +9,7 @@ public interface IImageRepository LibraryPath libraryPath, LibraryFolder libraryFolder, string path); + Task> FindImagePaths(LibraryPath libraryPath); Task> DeleteByPath(LibraryPath libraryPath, string path); Task AddTag(ImageMetadata metadata, Tag tag); diff --git a/ErsatzTV.Core/Interfaces/Repositories/IOtherVideoRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/IOtherVideoRepository.cs index 99025182..744978b4 100644 --- a/ErsatzTV.Core/Interfaces/Repositories/IOtherVideoRepository.cs +++ b/ErsatzTV.Core/Interfaces/Repositories/IOtherVideoRepository.cs @@ -9,6 +9,7 @@ public interface IOtherVideoRepository LibraryPath libraryPath, LibraryFolder libraryFolder, string path); + Task> FindOtherVideoPaths(LibraryPath libraryPath); Task> DeleteByPath(LibraryPath libraryPath, string path); Task AddGenre(OtherVideoMetadata metadata, Genre genre); diff --git a/ErsatzTV.Core/Interfaces/Repositories/ISongRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/ISongRepository.cs index ad6b864d..ef1b5b27 100644 --- a/ErsatzTV.Core/Interfaces/Repositories/ISongRepository.cs +++ b/ErsatzTV.Core/Interfaces/Repositories/ISongRepository.cs @@ -9,6 +9,7 @@ public interface ISongRepository LibraryPath libraryPath, LibraryFolder libraryFolder, string path); + Task> FindSongPaths(LibraryPath libraryPath); Task> DeleteByPath(LibraryPath libraryPath, string path); Task AddGenre(SongMetadata metadata, Genre genre); diff --git a/ErsatzTV.Core/Jellyfin/JellyfinConnectionParameters.cs b/ErsatzTV.Core/Jellyfin/JellyfinConnectionParameters.cs index 4a103f5c..a388b39c 100644 --- a/ErsatzTV.Core/Jellyfin/JellyfinConnectionParameters.cs +++ b/ErsatzTV.Core/Jellyfin/JellyfinConnectionParameters.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Core.Jellyfin; -public record JellyfinConnectionParameters - (string Address, string ApiKey, int MediaSourceId) : MediaServerConnectionParameters; +public record JellyfinConnectionParameters(string Address, string ApiKey, int MediaSourceId) + : MediaServerConnectionParameters; diff --git a/ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs b/ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs index c9e428bc..1d25edd9 100644 --- a/ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs +++ b/ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs @@ -327,7 +327,7 @@ public partial class FallbackMetadataProvider : IFallbackMetadataProvider return None; } } - + private Option GetImageMetadata(string path, ImageMetadata metadata) { try diff --git a/ErsatzTV.Core/Scheduling/BlockScheduling/BlockKey.cs b/ErsatzTV.Core/Scheduling/BlockScheduling/BlockKey.cs index 5632aaed..54c86c69 100644 --- a/ErsatzTV.Core/Scheduling/BlockScheduling/BlockKey.cs +++ b/ErsatzTV.Core/Scheduling/BlockScheduling/BlockKey.cs @@ -21,32 +21,32 @@ public record BlockKey } /// - /// Block Id + /// Block Id /// public int b { get; set; } - + /// - /// Template Id + /// Template Id /// public int t { get; set; } - + /// - /// Playout Template Id + /// Playout Template Id /// public int pt { get; set; } /// - /// Block Date Updated Ticks + /// Block Date Updated Ticks /// public long bt { get; set; } - + /// - /// Template Date Updated Ticks + /// Template Date Updated Ticks /// public long tt { get; set; } - + /// - /// Playout Template Date Updated Ticks + /// Playout Template Date Updated Ticks /// public long ptt { get; set; } } diff --git a/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutBuilder.cs b/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutBuilder.cs index 9431632a..f4b1310e 100644 --- a/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutBuilder.cs +++ b/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutBuilder.cs @@ -7,6 +7,7 @@ using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Core.Interfaces.Scheduling; using Microsoft.Extensions.Logging; using Newtonsoft.Json; +using Map = LanguageExt.Map; namespace ErsatzTV.Core.Scheduling.BlockScheduling; @@ -24,7 +25,12 @@ public class BlockPlayoutBuilder( NullValueHandling = NullValueHandling.Ignore }; - public virtual async Task Build(Playout playout, PlayoutBuildMode mode, CancellationToken cancellationToken) + protected virtual ILogger Logger => logger; + + public virtual async Task Build( + Playout playout, + PlayoutBuildMode mode, + CancellationToken cancellationToken) { Logger.LogDebug( "Building block playout {PlayoutId} for channel {ChannelNumber} - {ChannelName}", @@ -57,7 +63,7 @@ public class BlockPlayoutBuilder( // remove items without a block key (shouldn't happen often, just upgrades) playout.Items.RemoveAll(i => !itemBlockKeys.ContainsKey(i)); - + // remove old items // importantly, this should not remove their history playout.Items.RemoveAll(i => i.FinishOffset < start); @@ -132,7 +138,7 @@ public class BlockPlayoutBuilder( historyKey, collectionMediaItems); - bool pastTime = false; + var pastTime = false; foreach (MediaItem mediaItem in enumerator.Current) { @@ -144,7 +150,7 @@ public class BlockPlayoutBuilder( TimeSpan itemDuration = DurationForMediaItem(mediaItem); var collectionKey = CollectionKey.ForBlockItem(blockItem); - + // create a playout item var playoutItem = new PlayoutItem { @@ -201,7 +207,7 @@ public class BlockPlayoutBuilder( currentTime += itemDuration; enumerator.MoveNext(); } - + if (pastTime) { break; @@ -214,14 +220,10 @@ public class BlockPlayoutBuilder( return playout; } - protected virtual ILogger Logger => logger; - - protected virtual async Task GetDaysToBuild() - { - return await configElementRepository + protected virtual async Task GetDaysToBuild() => + await configElementRepository .GetValue(ConfigElementKey.PlayoutDaysToBuild) .IfNoneAsync(2); - } protected virtual IMediaCollectionEnumerator GetEnumerator( Playout playout, @@ -331,7 +333,7 @@ public class BlockPlayoutBuilder( artistRepository, collectionKey))).SequenceParallel(); - return LanguageExt.Map.createRange(tuples); + return Map.createRange(tuples); } private Map GetCollectionEtags( diff --git a/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutChangeDetection.cs b/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutChangeDetection.cs index d6725725..edd62bbe 100644 --- a/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutChangeDetection.cs +++ b/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutChangeDetection.cs @@ -2,6 +2,7 @@ using System.Collections.Immutable; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain.Scheduling; using Newtonsoft.Json; +using Serilog; namespace ErsatzTV.Core.Scheduling.BlockScheduling; @@ -39,7 +40,7 @@ internal static class BlockPlayoutChangeDetection var earliestEffectiveBlocks = new Dictionary(); var earliestBlocks = new Dictionary(); - + // check for changed collections foreach (EffectiveBlock effectiveBlock in blocksToSchedule.OrderBy(b => b.Start)) { @@ -54,18 +55,19 @@ internal static class BlockPlayoutChangeDetection bool isUpdated = string.IsNullOrWhiteSpace(playoutItem.CollectionKey); if (!isUpdated) { - CollectionKey collectionKey = JsonConvert.DeserializeObject(playoutItem.CollectionKey); + CollectionKey collectionKey = + JsonConvert.DeserializeObject(playoutItem.CollectionKey); // collection is no longer present or collection has been modified isUpdated = !collectionEtags.ContainsKey(collectionKey) || collectionEtags[collectionKey] != playoutItem.CollectionEtag; } - + if (isUpdated) { // playout item needs to be removed/re-added updatedItemIds.Add(playoutItem.Id); - + // block needs to be scheduled again updatedBlocks.Add(effectiveBlock); @@ -114,12 +116,12 @@ internal static class BlockPlayoutChangeDetection foreach ((BlockKey key, DateTimeOffset value) in earliestEffectiveBlocks) { - Serilog.Log.Logger.Debug("Earliest effective block: {Key} => {Value}", key, value); + Log.Logger.Debug("Earliest effective block: {Key} => {Value}", key, value); } foreach ((int blockId, DateTimeOffset value) in earliestBlocks) { - Serilog.Log.Logger.Debug("Earliest block id: {Id} => {Value}", blockId, value); + Log.Logger.Debug("Earliest block id: {Id} => {Value}", blockId, value); } // find affected playout items @@ -131,8 +133,8 @@ internal static class BlockPlayoutChangeDetection value <= item.StartOffset; bool blockIdIsAffected = earliestBlocks.TryGetValue(blockKey.b, out DateTimeOffset value2) && - value2 <= item.StartOffset; - + value2 <= item.StartOffset; + if (!blockKeysToSchedule.Contains(blockKey) || blockKeyIsAffected || blockIdIsAffected) { updatedItemIds.Add(item.Id); diff --git a/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutEnumerator.cs b/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutEnumerator.cs index 99c5aa36..b86c8e34 100644 --- a/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutEnumerator.cs +++ b/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutEnumerator.cs @@ -1,9 +1,7 @@ -using System.Collections.Immutable; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain.Scheduling; using ErsatzTV.Core.Interfaces.Scheduling; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; namespace ErsatzTV.Core.Scheduling.BlockScheduling; @@ -28,7 +26,7 @@ public static class BlockPlayoutEnumerator var state = new CollectionEnumeratorState { Seed = 0, Index = 0 }; var enumerator = new ChronologicalMediaCollectionEnumerator(collectionItems, state); - + // seek to the appropriate place in the collection enumerator foreach (PlayoutHistory h in maybeHistory) { @@ -43,7 +41,7 @@ public static class BlockPlayoutEnumerator return enumerator; } - + public static IMediaCollectionEnumerator SeasonEpisode( List collectionItems, DateTimeOffset currentTime, @@ -63,7 +61,7 @@ public static class BlockPlayoutEnumerator var state = new CollectionEnumeratorState { Seed = 0, Index = 0 }; var enumerator = new SeasonEpisodeMediaCollectionEnumerator(collectionItems, state); - + // seek to the appropriate place in the collection enumerator foreach (PlayoutHistory h in maybeHistory) { @@ -78,7 +76,7 @@ public static class BlockPlayoutEnumerator return enumerator; } - + public static IMediaCollectionEnumerator Shuffle( List collectionItems, DateTimeOffset currentTime, diff --git a/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutShuffledMediaCollectionEnumerator.cs b/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutShuffledMediaCollectionEnumerator.cs index b04615fe..ce69d2a6 100644 --- a/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutShuffledMediaCollectionEnumerator.cs +++ b/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutShuffledMediaCollectionEnumerator.cs @@ -6,9 +6,9 @@ namespace ErsatzTV.Core.Scheduling.BlockScheduling; public class BlockPlayoutShuffledMediaCollectionEnumerator : IMediaCollectionEnumerator { - private readonly IList _mediaItems; private readonly Lazy> _lazyMinimumDuration; private readonly int _mediaItemCount; + private readonly IList _mediaItems; private IList _shuffled; public BlockPlayoutShuffledMediaCollectionEnumerator( @@ -42,10 +42,7 @@ public class BlockPlayoutShuffledMediaCollectionEnumerator : IMediaCollectionEnu public Option Current => _shuffled.Any() ? _shuffled[State.Index % _mediaItemCount] : None; - public void MoveNext() - { - State.Index++; - } + public void MoveNext() => State.Index++; public Option MinimumDuration => _lazyMinimumDuration.Value; @@ -58,7 +55,7 @@ public class BlockPlayoutShuffledMediaCollectionEnumerator : IMediaCollectionEnu var superShuffle = new SuperShuffle(); for (var i = 0; i < list.Count; i++) { - int toSelect = superShuffle.Shuffle(i, State.Seed + (State.Index / list.Count), list.Count); + int toSelect = superShuffle.Shuffle(i, State.Seed + State.Index / list.Count, list.Count); copy[i] = list[toSelect]; } diff --git a/ErsatzTV.Core/Scheduling/BlockScheduling/EffectiveBlock.cs b/ErsatzTV.Core/Scheduling/BlockScheduling/EffectiveBlock.cs index 33ac5295..0726e50c 100644 --- a/ErsatzTV.Core/Scheduling/BlockScheduling/EffectiveBlock.cs +++ b/ErsatzTV.Core/Scheduling/BlockScheduling/EffectiveBlock.cs @@ -24,7 +24,7 @@ internal record EffectiveBlock(Block Block, BlockKey BlockKey, DateTimeOffset St // playoutTemplate.Template.Name); DateTimeOffset today = current; - + var newBlocks = playoutTemplate.Template.Items .Map(i => ToEffectiveBlock(playoutTemplate, i, today, start)) .Map(NormalizeGuideMode) diff --git a/ErsatzTV.Core/Scheduling/BlockScheduling/HistoryDetails.cs b/ErsatzTV.Core/Scheduling/BlockScheduling/HistoryDetails.cs index d8ef7442..4f1c2f51 100644 --- a/ErsatzTV.Core/Scheduling/BlockScheduling/HistoryDetails.cs +++ b/ErsatzTV.Core/Scheduling/BlockScheduling/HistoryDetails.cs @@ -11,7 +11,7 @@ internal static class HistoryDetails { NullValueHandling = NullValueHandling.Ignore }; - + public static string KeyForBlockItem(BlockItem blockItem) { dynamic key = new @@ -36,7 +36,7 @@ internal static class HistoryDetails Movie m => ForMovie(m), _ => new Details(mediaItem.Id, null, null, null) }; - + return JsonConvert.SerializeObject(details, Formatting.None, JsonSettings); } @@ -50,16 +50,16 @@ internal static class HistoryDetails { return; } - + Option maybeMatchedItem = Option.None; var copy = collectionItems.ToList(); - + Details details = JsonConvert.DeserializeObject
(detailsString); if (details.SeasonNumber.HasValue && details.EpisodeNumber.HasValue) { int season = details.SeasonNumber.Value; int episode = details.EpisodeNumber.Value; - + maybeMatchedItem = Optional(collectionItems.Find(ci => MatchSeasonAndEpisode(ci, season, episode))); if (maybeMatchedItem.IsNone) @@ -93,13 +93,13 @@ internal static class HistoryDetails } } // TODO: match media item - + foreach (MediaItem matchedItem in maybeMatchedItem) { IComparer comparer = playbackOrder switch { PlaybackOrder.Chronological => new ChronologicalMediaComparer(), - _ => new SeasonEpisodeMediaComparer(), + _ => new SeasonEpisodeMediaComparer() }; copy.Sort(comparer); diff --git a/ErsatzTV.Core/Scheduling/CollectionKey.cs b/ErsatzTV.Core/Scheduling/CollectionKey.cs index 0eac565b..afb43124 100644 --- a/ErsatzTV.Core/Scheduling/CollectionKey.cs +++ b/ErsatzTV.Core/Scheduling/CollectionKey.cs @@ -12,43 +12,43 @@ public class CollectionKey : Record public int? SmartCollectionId { get; set; } public int? MediaItemId { get; set; } public string FakeCollectionKey { get; set; } - + public static CollectionKey ForBlockItem(BlockItem item) => item.CollectionType switch { ProgramScheduleItemCollectionType.Collection => new CollectionKey { CollectionType = item.CollectionType, - CollectionId = item.CollectionId, + CollectionId = item.CollectionId }, ProgramScheduleItemCollectionType.TelevisionShow => new CollectionKey { CollectionType = item.CollectionType, - MediaItemId = item.MediaItemId, + MediaItemId = item.MediaItemId }, ProgramScheduleItemCollectionType.TelevisionSeason => new CollectionKey { CollectionType = item.CollectionType, - MediaItemId = item.MediaItemId, + MediaItemId = item.MediaItemId }, ProgramScheduleItemCollectionType.Artist => new CollectionKey { CollectionType = item.CollectionType, - MediaItemId = item.MediaItemId, + MediaItemId = item.MediaItemId }, ProgramScheduleItemCollectionType.MultiCollection => new CollectionKey { CollectionType = item.CollectionType, - MultiCollectionId = item.MultiCollectionId, + MultiCollectionId = item.MultiCollectionId }, ProgramScheduleItemCollectionType.SmartCollection => new CollectionKey { CollectionType = item.CollectionType, - SmartCollectionId = item.SmartCollectionId, + SmartCollectionId = item.SmartCollectionId }, ProgramScheduleItemCollectionType.FakeCollection => new CollectionKey { - CollectionType = item.CollectionType, + CollectionType = item.CollectionType }, _ => throw new ArgumentOutOfRangeException(nameof(item)) }; diff --git a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs index a02d7aea..aaf46661 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs @@ -53,7 +53,7 @@ public class PlayoutBuilder : IPlayoutBuilder return playout; } - + foreach (PlayoutParameters parameters in await Validate(playout)) { // for testing purposes @@ -459,7 +459,7 @@ public class PlayoutBuilder : IPlayoutBuilder var fakeCollections = _mediaCollectionRepository.GroupIntoFakeCollections(mediaItems, collectionKeyString) .Filter(c => c.ShowId > 0 || c.ArtistId > 0 || !string.IsNullOrWhiteSpace(c.Key)) .ToList(); - List fakeScheduleItems = []; + List fakeScheduleItems = []; // this will be used to clone a schedule item MethodInfo generic = typeof(JsonConvert).GetMethods() @@ -495,7 +495,7 @@ public class PlayoutBuilder : IPlayoutBuilder { continue; } - + string serialized = JsonConvert.SerializeObject(scheduleItem); var copyScheduleItem = generic.Invoke(this, [serialized]) as ProgramScheduleItem; copyScheduleItem.CollectionType = key.CollectionType; diff --git a/ErsatzTV.Core/Scheduling/SuperShuffle.cs b/ErsatzTV.Core/Scheduling/SuperShuffle.cs index b1f55198..7481995a 100644 --- a/ErsatzTV.Core/Scheduling/SuperShuffle.cs +++ b/ErsatzTV.Core/Scheduling/SuperShuffle.cs @@ -4,29 +4,33 @@ namespace ErsatzTV.Core.Scheduling; public class SuperShuffle { - private int userSID = 1; - private int si, r1, r2, r3, r4; private int randR, halfN, rx, rkey; - - public int Shuffle(int inx, int shuffleId, int listSize) { + private int si, r1, r2, r3, r4; + private readonly int userSID = 1; + + public int Shuffle(int inx, int shuffleId, int listSize) + { int si, hi, offset; - int halfSize = listSize / 2; // for 1/2 the processing range + int halfSize = listSize / 2; // for 1/2 the processing range - shuffleId += 131 * (inx / listSize); // have inx overflows supported - si = (inx % listSize); - if (si < halfSize) { + shuffleId += 131 * (inx / listSize); // have inx overflows supported + si = inx % listSize; + if (si < halfSize) + { hi = si; offset = 0; - } else { + } + else + { hi = listSize - 1 - si; offset = halfSize; halfSize = listSize - halfSize; shuffleId++; } - hi = MillerShuffleE(hi, shuffleId, halfSize); // use any STD MSA() shuffle (aka: a PRIG function) - si = MillerShuffleE(hi + offset, userSID, listSize); // indexing into the baseline shuffle - return(si); + hi = MillerShuffleE(hi, shuffleId, halfSize); // use any STD MSA() shuffle (aka: a PRIG function) + si = MillerShuffleE(hi + offset, userSID, listSize); // indexing into the baseline shuffle + return si; } private int MillerShuffleE(int inx, int shuffleId, int listSize) @@ -42,23 +46,41 @@ public class SuperShuffle r3 = randR % p2; r4 = randR % 2749; halfN = listSize / 2 + 1; - rx = (randR / listSize) % listSize + 1; - rkey = (randR / listSize / listSize) % listSize + 1; + rx = randR / listSize % listSize + 1; + rkey = randR / listSize / listSize % listSize + 1; // perform the conditional multi-faceted mathematical mixing (on avg 2 5/6 shuffle ops done + 2 simple Xors) - if (si % 3 == 0) si = ((si / 3 * p1 + r1) % ((listSize + 2) / 3)) * 3; // spin multiples of 3 + if (si % 3 == 0) + { + si = (si / 3 * p1 + r1) % ((listSize + 2) / 3) * 3; // spin multiples of 3 + } + if (si <= halfN) { si = (si + r3) % (halfN + 1); si = halfN - si; } // improves large permu distro - if (si % 2 == 0) si = ((si / 2 * p2 + r2) % ((listSize + 1) / 2)) * 2; // spin multiples of 2 - if (si < halfN) si = (si * p3 + r3) % halfN; + if (si % 2 == 0) + { + si = (si / 2 * p2 + r2) % ((listSize + 1) / 2) * 2; // spin multiples of 2 + } + + if (si < halfN) + { + si = (si * p3 + r3) % halfN; + } + + if ((si ^ rx) < listSize) + { + si ^= rx; // flip some bits with Xor + } - if ((si ^ rx) < listSize) si ^= rx; // flip some bits with Xor si = (si * p3 + r4) % listSize; // a relatively prime gears churning operation - if ((si ^ rkey) < listSize) si ^= rkey; + if ((si ^ rkey) < listSize) + { + si ^= rkey; + } return si; } diff --git a/ErsatzTV.Core/Streaming/ExternalJsonChannel.cs b/ErsatzTV.Core/Streaming/ExternalJsonChannel.cs index c54f24d2..6ac3bca0 100644 --- a/ErsatzTV.Core/Streaming/ExternalJsonChannel.cs +++ b/ErsatzTV.Core/Streaming/ExternalJsonChannel.cs @@ -6,10 +6,10 @@ public class ExternalJsonChannel { [JsonProperty("startTime")] public string StartTime { get; set; } - + [JsonProperty("guideMinimumDurationSeconds")] public int GuideMinimumDurationSeconds { get; set; } [JsonProperty("programs")] public ExternalJsonProgram[] Programs { get; set; } -} \ No newline at end of file +} diff --git a/ErsatzTV.Core/Streaming/ExternalJsonProgram.cs b/ErsatzTV.Core/Streaming/ExternalJsonProgram.cs index 98ed263b..3b99e512 100644 --- a/ErsatzTV.Core/Streaming/ExternalJsonProgram.cs +++ b/ErsatzTV.Core/Streaming/ExternalJsonProgram.cs @@ -6,40 +6,40 @@ public class ExternalJsonProgram { [JsonProperty("title")] public string Title { get; set; } - + [JsonProperty("showTitle")] public string ShowTitle { get; set; } - + [JsonProperty("season")] public int Season { get; set; } - + [JsonProperty("episode")] public int Episode { get; set; } [JsonProperty("key")] public string Key { get; set; } - + [JsonProperty("ratingKey")] public string RatingKey { get; set; } - + [JsonProperty("icon")] public string Icon { get; set; } - + [JsonProperty("year")] public int? Year { get; set; } - + [JsonProperty("type")] public string Type { get; set; } - + [JsonProperty("duration")] public int Duration { get; set; } - + [JsonProperty("plexFile")] public string PlexFile { get; set; } - + [JsonProperty("file")] public string File { get; set; } - + [JsonProperty("serverKey")] public string ServerKey { get; set; } } diff --git a/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj b/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj index 7fcf18b1..94a1b9b6 100644 --- a/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj +++ b/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj @@ -10,15 +10,15 @@ - + - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/ErsatzTV.FFmpeg/Encoder/AvailableEncoders.cs b/ErsatzTV.FFmpeg/Encoder/AvailableEncoders.cs index a492e8ff..b7d95a68 100644 --- a/ErsatzTV.FFmpeg/Encoder/AvailableEncoders.cs +++ b/ErsatzTV.FFmpeg/Encoder/AvailableEncoders.cs @@ -13,7 +13,7 @@ public static class AvailableEncoders { return new EncoderPcmS16Le(); } - + return desiredState.AudioFormat.Match( audioFormat => audioFormat switch diff --git a/ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderH264Vaapi.cs b/ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderH264Vaapi.cs index c0fd015b..5405f05a 100644 --- a/ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderH264Vaapi.cs +++ b/ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderH264Vaapi.cs @@ -23,7 +23,7 @@ public class EncoderH264Vaapi : EncoderBase result.Add("-rc_mode"); result.Add("1"); } - + result.Add("-sei"); result.Add("-a53_cc"); diff --git a/ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderHevcVaapi.cs b/ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderHevcVaapi.cs index f287235f..bab4a5cf 100644 --- a/ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderHevcVaapi.cs +++ b/ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderHevcVaapi.cs @@ -23,7 +23,7 @@ public class EncoderHevcVaapi : EncoderBase result.Add("-rc_mode"); result.Add("1"); } - + result.Add("-sei"); result.Add("-a53_cc"); diff --git a/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj b/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj index 0ea11219..e7b1a17a 100644 --- a/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj +++ b/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj @@ -10,7 +10,7 @@ - + diff --git a/ErsatzTV.FFmpeg/Filter/AudioPadFilter.cs b/ErsatzTV.FFmpeg/Filter/AudioPadFilter.cs index 827aebc3..262b838f 100644 --- a/ErsatzTV.FFmpeg/Filter/AudioPadFilter.cs +++ b/ErsatzTV.FFmpeg/Filter/AudioPadFilter.cs @@ -2,7 +2,6 @@ public class AudioPadFilter : BaseFilter { - public override string Filter => "apad"; public override FrameState NextState(FrameState currentState) => currentState; diff --git a/ErsatzTV.FFmpeg/Filter/LoopFilter.cs b/ErsatzTV.FFmpeg/Filter/LoopFilter.cs index d1750412..4bfb6122 100644 --- a/ErsatzTV.FFmpeg/Filter/LoopFilter.cs +++ b/ErsatzTV.FFmpeg/Filter/LoopFilter.cs @@ -2,7 +2,6 @@ namespace ErsatzTV.FFmpeg.Filter; public class LoopFilter : BaseFilter { - public override FrameState NextState(FrameState currentState) => currentState; - public override string Filter => "loop=-1:1"; + public override FrameState NextState(FrameState currentState) => currentState; } diff --git a/ErsatzTV.FFmpeg/Filter/Qsv/ScaleQsvFilter.cs b/ErsatzTV.FFmpeg/Filter/Qsv/ScaleQsvFilter.cs index 93cadb30..f7f9a886 100644 --- a/ErsatzTV.FFmpeg/Filter/Qsv/ScaleQsvFilter.cs +++ b/ErsatzTV.FFmpeg/Filter/Qsv/ScaleQsvFilter.cs @@ -4,13 +4,13 @@ namespace ErsatzTV.FFmpeg.Filter.Qsv; public class ScaleQsvFilter : BaseFilter { + private readonly Option _croppedSize; private readonly FrameState _currentState; private readonly int _extraHardwareFrames; private readonly bool _isAnamorphicEdgeCase; + private readonly FrameSize _paddedSize; private readonly string _sampleAspectRatio; private readonly FrameSize _scaledSize; - private readonly FrameSize _paddedSize; - private readonly Option _croppedSize; public ScaleQsvFilter( FrameState currentState, @@ -49,7 +49,7 @@ public class ScaleQsvFilter : BaseFilter else { string squareScale = string.Empty; - var targetSize = _croppedSize.IsSome + string targetSize = _croppedSize.IsSome ? $"w={_paddedSize.Width}:h={_paddedSize.Height}" : $"w={_scaledSize.Width}:h={_scaledSize.Height}"; string format = string.Empty; diff --git a/ErsatzTV.FFmpeg/Filter/RealtimeFilter.cs b/ErsatzTV.FFmpeg/Filter/RealtimeFilter.cs index ba61a21f..bac8e7fd 100644 --- a/ErsatzTV.FFmpeg/Filter/RealtimeFilter.cs +++ b/ErsatzTV.FFmpeg/Filter/RealtimeFilter.cs @@ -2,7 +2,6 @@ namespace ErsatzTV.FFmpeg.Filter; public class RealtimeFilter : BaseFilter { - public override FrameState NextState(FrameState currentState) => currentState with { Realtime = true }; - public override string Filter => "realtime"; + public override FrameState NextState(FrameState currentState) => currentState with { Realtime = true }; } diff --git a/ErsatzTV.FFmpeg/Filter/VideoFilter.cs b/ErsatzTV.FFmpeg/Filter/VideoFilter.cs index 9a852808..6efc80c8 100644 --- a/ErsatzTV.FFmpeg/Filter/VideoFilter.cs +++ b/ErsatzTV.FFmpeg/Filter/VideoFilter.cs @@ -18,6 +18,6 @@ public class VideoFilter : IPipelineStep private string[] Arguments() => [ "-vf", - string.Join(",", _filterSteps.Map(fs => fs.Filter)) + string.Join(",", _filterSteps.Map(fs => fs.Filter)) ]; } diff --git a/ErsatzTV.FFmpeg/InputFile.cs b/ErsatzTV.FFmpeg/InputFile.cs index 468b4bc4..cea52bba 100644 --- a/ErsatzTV.FFmpeg/InputFile.cs +++ b/ErsatzTV.FFmpeg/InputFile.cs @@ -73,8 +73,8 @@ public record VideoInputFile(string Path, IList VideoStreams) : Inp } } -public record WatermarkInputFile - (string Path, IList VideoStreams, WatermarkState DesiredState) : VideoInputFile(Path, VideoStreams); +public record WatermarkInputFile(string Path, IList VideoStreams, WatermarkState DesiredState) + : VideoInputFile(Path, VideoStreams); public record SubtitleInputFile(string Path, IList SubtitleStreams, SubtitleMethod Method) : InputFile( Path, diff --git a/ErsatzTV.FFmpeg/OutputFormat/OutputFormatConcatHls.cs b/ErsatzTV.FFmpeg/OutputFormat/OutputFormatConcatHls.cs index af25355f..d63ed461 100644 --- a/ErsatzTV.FFmpeg/OutputFormat/OutputFormatConcatHls.cs +++ b/ErsatzTV.FFmpeg/OutputFormat/OutputFormatConcatHls.cs @@ -19,7 +19,7 @@ public class OutputFormatConcatHls : IPipelineStep public string[] FilterOptions => Array.Empty(); public string[] OutputOptions => - [ + [ //"-g", $"{gop}", //"-keyint_min", $"{FRAME_RATE * OutputFormatHls.SegmentSeconds}", "-force_key_frames", $"expr:gte(t,n_forced*{OutputFormatHls.SegmentSeconds}/2)", diff --git a/ErsatzTV.FFmpeg/OutputFormat/OutputFormatHls.cs b/ErsatzTV.FFmpeg/OutputFormat/OutputFormatHls.cs index 4caedc5b..d35f7179 100644 --- a/ErsatzTV.FFmpeg/OutputFormat/OutputFormatHls.cs +++ b/ErsatzTV.FFmpeg/OutputFormat/OutputFormatHls.cs @@ -5,12 +5,12 @@ namespace ErsatzTV.FFmpeg.OutputFormat; public class OutputFormatHls : IPipelineStep { public const int SegmentSeconds = 4; - + private readonly FrameState _desiredState; + private readonly bool _isFirstTranscode; private readonly Option _mediaFrameRate; private readonly bool _oneSecondGop; private readonly string _playlistPath; - private readonly bool _isFirstTranscode; private readonly string _segmentTemplate; public OutputFormatHls( diff --git a/ErsatzTV.FFmpeg/OutputFormat/OutputFormatKind.cs b/ErsatzTV.FFmpeg/OutputFormat/OutputFormatKind.cs index 965e48b0..1d6ffc7a 100644 --- a/ErsatzTV.FFmpeg/OutputFormat/OutputFormatKind.cs +++ b/ErsatzTV.FFmpeg/OutputFormat/OutputFormatKind.cs @@ -7,6 +7,6 @@ public enum OutputFormatKind MpegTs, Mp4, Hls, - + Nut } diff --git a/ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs b/ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs index e82c8f93..ae524a2a 100644 --- a/ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs +++ b/ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs @@ -64,7 +64,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder desiredState.VideoFormat, desiredState.VideoProfile, desiredState.PixelFormat); - + // use software encoding (rawvideo) when piping to parent hls segmenter if (ffmpegState.OutputFormat is OutputFormatKind.Nut) { @@ -393,7 +393,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder pipelineSteps.Add(new PixelFormatOutputOption(format)); } } - + if (ffmpegState.OutputFormat is OutputFormatKind.Nut && format.BitDepth == 10) { pipelineSteps.Add(new PixelFormatOutputOption(format)); @@ -455,7 +455,9 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder IPixelFormat pf = desiredPixelFormat; if (desiredPixelFormat is PixelFormatNv12 nv12) { - foreach (IPixelFormat availablePixelFormat in AvailablePixelFormats.ForPixelFormat(nv12.Name, null)) + foreach (IPixelFormat availablePixelFormat in AvailablePixelFormats.ForPixelFormat( + nv12.Name, + null)) { pf = availablePixelFormat; } diff --git a/ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs b/ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs index db5369c4..7474a7b7 100644 --- a/ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs +++ b/ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs @@ -2,12 +2,10 @@ using System.Diagnostics; using ErsatzTV.FFmpeg.Capabilities; using ErsatzTV.FFmpeg.Decoder; using ErsatzTV.FFmpeg.Encoder; -using ErsatzTV.FFmpeg.Encoder.Vaapi; using ErsatzTV.FFmpeg.Environment; using ErsatzTV.FFmpeg.Filter; using ErsatzTV.FFmpeg.Format; using ErsatzTV.FFmpeg.GlobalOption; -using ErsatzTV.FFmpeg.GlobalOption.HardwareAcceleration; using ErsatzTV.FFmpeg.InputOption; using ErsatzTV.FFmpeg.OutputFormat; using ErsatzTV.FFmpeg.OutputOption; @@ -20,13 +18,13 @@ namespace ErsatzTV.FFmpeg.Pipeline; public abstract class PipelineBuilderBase : IPipelineBuilder { private readonly Option _audioInputFile; + private readonly Option _concatInputFile; private readonly IFFmpegCapabilities _ffmpegCapabilities; private readonly string _fontsFolder; private readonly HardwareAccelerationMode _hardwareAccelerationMode; private readonly ILogger _logger; private readonly string _reportsFolder; private readonly Option _subtitleInputFile; - private readonly Option _concatInputFile; private readonly Option _videoInputFile; private readonly Option _watermarkInputFile; @@ -120,7 +118,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder return new FFmpegPipeline(pipelineSteps, false); } - + public FFmpegPipeline WrapSegmenter(ConcatInputFile concatInputFile, FFmpegState ffmpegState) { var pipelineSteps = new List @@ -163,7 +161,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder new StandardFormatFlags(), new NoDemuxDecodeDelayOutputOption(), outputOption, - new ClosedGopOutputOption(), + new ClosedGopOutputOption() }; if (desiredState.VideoFormat != VideoFormat.Copy) @@ -176,7 +174,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder concatInputFile.AddOption(new ConcatInputFormat()); concatInputFile.AddOption(new InfiniteLoopInputOption(HardwareAccelerationMode.None)); } - + Debug.Assert(_videoInputFile.IsSome, "Pipeline builder requires exactly one video input file"); VideoInputFile videoInputFile = _videoInputFile.Head(); @@ -313,7 +311,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder videoStream.FrameRate, segmentTemplate, playlistPath, - isFirstTranscode: ffmpegState.PtsOffset == 0, + ffmpegState.PtsOffset == 0, ffmpegState.EncoderHardwareAccelerationMode is HardwareAccelerationMode.Qsv)); } } @@ -367,7 +365,10 @@ public abstract class PipelineBuilderBase : IPipelineBuilder } } - private void BuildAudioPipeline(FFmpegState ffmpegState, AudioInputFile audioInputFile, List pipelineSteps) + private void BuildAudioPipeline( + FFmpegState ffmpegState, + AudioInputFile audioInputFile, + List pipelineSteps) { // always need to specify audio codec so ffmpeg doesn't default to a codec we don't want foreach (IEncoder step in AvailableEncoders.ForAudioFormat(ffmpegState, audioInputFile.DesiredState, _logger)) @@ -538,13 +539,16 @@ public abstract class PipelineBuilderBase : IPipelineBuilder return maybeDecoder; } - protected Option GetSoftwareEncoder(FFmpegState ffmpegState, FrameState currentState, FrameState desiredState) + protected Option GetSoftwareEncoder( + FFmpegState ffmpegState, + FrameState currentState, + FrameState desiredState) { if (ffmpegState.OutputFormat is OutputFormatKind.Nut) { return new EncoderRawVideo(); } - + return desiredState.VideoFormat switch { VideoFormat.Hevc => new EncoderLibx265( diff --git a/ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs b/ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs index 80f6f908..6b84ca28 100644 --- a/ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs +++ b/ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs @@ -66,7 +66,7 @@ public class QsvPipelineBuilder : SoftwarePipelineBuilder desiredState.VideoFormat, desiredState.VideoProfile, desiredState.PixelFormat); - + // use software encoding (rawvideo) when piping to parent hls segmenter if (ffmpegState.OutputFormat is OutputFormatKind.Nut) { @@ -360,7 +360,7 @@ public class QsvPipelineBuilder : SoftwarePipelineBuilder _logger.LogDebug("FrameDataLocation == FrameDataLocation.Hardware"); formatForDownload = new PixelFormatNv12(formatForDownload.Name); - + var hardwareDownload = new HardwareDownloadFilter(currentState with { PixelFormat = Some(formatForDownload) }); currentState = hardwareDownload.NextState(currentState); @@ -396,7 +396,7 @@ public class QsvPipelineBuilder : SoftwarePipelineBuilder { pipelineSteps.Remove(pf); } - + pipelineSteps.Add(new PixelFormatOutputOption(format)); } } diff --git a/ErsatzTV.Infrastructure.MySql/ErsatzTV.Infrastructure.MySql.csproj b/ErsatzTV.Infrastructure.MySql/ErsatzTV.Infrastructure.MySql.csproj index 154a647b..d23b481a 100644 --- a/ErsatzTV.Infrastructure.MySql/ErsatzTV.Infrastructure.MySql.csproj +++ b/ErsatzTV.Infrastructure.MySql/ErsatzTV.Infrastructure.MySql.csproj @@ -16,8 +16,8 @@ - - + + diff --git a/ErsatzTV.Infrastructure.MySql/Migrations/20240305161535_Update_BlockUniqueIndex.Designer.cs b/ErsatzTV.Infrastructure.MySql/Migrations/20240305161535_Update_BlockUniqueIndex.Designer.cs new file mode 100644 index 00000000..b37085fa --- /dev/null +++ b/ErsatzTV.Infrastructure.MySql/Migrations/20240305161535_Update_BlockUniqueIndex.Designer.cs @@ -0,0 +1,5309 @@ +// +using System; +using ErsatzTV.Infrastructure.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace ErsatzTV.Infrastructure.MySql.Migrations +{ + [DbContext(typeof(TvContext))] + [Migration("20240305161535_Update_BlockUniqueIndex")] + partial class Update_BlockUniqueIndex + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Actor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ArtistMetadataId") + .HasColumnType("int"); + + b.Property("ArtworkId") + .HasColumnType("int"); + + b.Property("EpisodeMetadataId") + .HasColumnType("int"); + + b.Property("ImageMetadataId") + .HasColumnType("int"); + + b.Property("MovieMetadataId") + .HasColumnType("int"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("int"); + + b.Property("Role") + .HasColumnType("longtext"); + + b.Property("SeasonMetadataId") + .HasColumnType("int"); + + b.Property("ShowMetadataId") + .HasColumnType("int"); + + b.Property("SongMetadataId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("ArtworkId") + .IsUnique(); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("Actor", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ArtistMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ArtistId") + .HasColumnType("int"); + + b.Property("Biography") + .HasColumnType("longtext"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)"); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("Disambiguation") + .HasColumnType("longtext"); + + b.Property("Formed") + .HasColumnType("longtext"); + + b.Property("MetadataKind") + .HasColumnType("int"); + + b.Property("OriginalTitle") + .HasColumnType("longtext"); + + b.Property("ReleaseDate") + .HasColumnType("datetime(6)"); + + b.Property("SortTitle") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ArtistId"); + + b.ToTable("ArtistMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Artwork", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ArtistMetadataId") + .HasColumnType("int"); + + b.Property("ArtworkKind") + .HasColumnType("int"); + + b.Property("BlurHash43") + .HasColumnType("longtext"); + + b.Property("BlurHash54") + .HasColumnType("longtext"); + + b.Property("BlurHash64") + .HasColumnType("longtext"); + + b.Property("ChannelId") + .HasColumnType("int"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)"); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("EpisodeMetadataId") + .HasColumnType("int"); + + b.Property("ImageMetadataId") + .HasColumnType("int"); + + b.Property("MovieMetadataId") + .HasColumnType("int"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("int"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("int"); + + b.Property("Path") + .HasColumnType("longtext"); + + b.Property("SeasonMetadataId") + .HasColumnType("int"); + + b.Property("ShowMetadataId") + .HasColumnType("int"); + + b.Property("SongMetadataId") + .HasColumnType("int"); + + b.Property("SourcePath") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("ChannelId"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("Artwork", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Channel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Categories") + .HasColumnType("longtext"); + + b.Property("FFmpegProfileId") + .HasColumnType("int"); + + b.Property("FallbackFillerId") + .HasColumnType("int"); + + b.Property("Group") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("longtext") + .HasDefaultValue("ErsatzTV"); + + b.Property("MusicVideoCreditsMode") + .HasColumnType("int"); + + b.Property("MusicVideoCreditsTemplate") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("Number") + .HasColumnType("varchar(255)"); + + b.Property("PreferredAudioLanguageCode") + .HasColumnType("longtext"); + + b.Property("PreferredAudioTitle") + .HasColumnType("longtext"); + + b.Property("PreferredSubtitleLanguageCode") + .HasColumnType("longtext"); + + b.Property("StreamingMode") + .HasColumnType("int"); + + b.Property("SubtitleMode") + .HasColumnType("int"); + + b.Property("UniqueId") + .HasColumnType("char(36)"); + + b.Property("WatermarkId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("FFmpegProfileId"); + + b.HasIndex("FallbackFillerId"); + + b.HasIndex("Number") + .IsUnique(); + + b.HasIndex("WatermarkId"); + + b.ToTable("Channel", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ChannelWatermark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DurationSeconds") + .HasColumnType("int"); + + b.Property("FrequencyMinutes") + .HasColumnType("int"); + + b.Property("HorizontalMarginPercent") + .HasColumnType("int"); + + b.Property("Image") + .HasColumnType("longtext"); + + b.Property("ImageSource") + .HasColumnType("int"); + + b.Property("Location") + .HasColumnType("int"); + + b.Property("Mode") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("Opacity") + .HasColumnType("int"); + + b.Property("PlaceWithinSourceContent") + .HasColumnType("tinyint(1)"); + + b.Property("Size") + .HasColumnType("int"); + + b.Property("VerticalMarginPercent") + .HasColumnType("int"); + + b.Property("WidthPercent") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("ChannelWatermark", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Collection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("UseCustomPlaybackOrder") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.CollectionItem", b => + { + b.Property("CollectionId") + .HasColumnType("int"); + + b.Property("MediaItemId") + .HasColumnType("int"); + + b.Property("CustomIndex") + .HasColumnType("int"); + + b.HasKey("CollectionId", "MediaItemId"); + + b.HasIndex("MediaItemId"); + + b.ToTable("CollectionItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ConfigElement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Key") + .HasColumnType("varchar(255)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.ToTable("ConfigElement", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Director", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("EpisodeMetadataId") + .HasColumnType("int"); + + b.Property("MovieMetadataId") + .HasColumnType("int"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.ToTable("Director", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("ItemId") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("EmbyCollection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Address") + .HasColumnType("longtext"); + + b.Property("EmbyMediaSourceId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("EmbyMediaSourceId"); + + b.ToTable("EmbyConnection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyPathReplacement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("EmbyMediaSourceId") + .HasColumnType("int"); + + b.Property("EmbyPath") + .HasColumnType("longtext"); + + b.Property("LocalPath") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("EmbyMediaSourceId"); + + b.ToTable("EmbyPathReplacement", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EpisodeMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)"); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("EpisodeId") + .HasColumnType("int"); + + b.Property("EpisodeNumber") + .HasColumnType("int"); + + b.Property("MetadataKind") + .HasColumnType("int"); + + b.Property("OriginalTitle") + .HasColumnType("longtext"); + + b.Property("Outline") + .HasColumnType("longtext"); + + b.Property("Plot") + .HasColumnType("longtext"); + + b.Property("ReleaseDate") + .HasColumnType("datetime(6)"); + + b.Property("SortTitle") + .HasColumnType("longtext"); + + b.Property("Tagline") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("EpisodeId"); + + b.ToTable("EpisodeMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.FFmpegProfile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AudioBitrate") + .HasColumnType("int"); + + b.Property("AudioBufferSize") + .HasColumnType("int"); + + b.Property("AudioChannels") + .HasColumnType("int"); + + b.Property("AudioFormat") + .HasColumnType("int"); + + b.Property("AudioSampleRate") + .HasColumnType("int"); + + b.Property("BitDepth") + .HasColumnType("int"); + + b.Property("DeinterlaceVideo") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(true); + + b.Property("HardwareAcceleration") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("NormalizeFramerate") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("NormalizeLoudnessMode") + .HasColumnType("int"); + + b.Property("QsvExtraHardwareFrames") + .HasColumnType("int"); + + b.Property("ResolutionId") + .HasColumnType("int"); + + b.Property("ScalingBehavior") + .HasColumnType("int"); + + b.Property("ThreadCount") + .HasColumnType("int"); + + b.Property("VaapiDevice") + .HasColumnType("longtext"); + + b.Property("VaapiDriver") + .HasColumnType("int"); + + b.Property("VideoBitrate") + .HasColumnType("int"); + + b.Property("VideoBufferSize") + .HasColumnType("int"); + + b.Property("VideoFormat") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ResolutionId"); + + b.ToTable("FFmpegProfile", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Filler.FillerPreset", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AllowWatermarks") + .HasColumnType("tinyint(1)"); + + b.Property("CollectionId") + .HasColumnType("int"); + + b.Property("CollectionType") + .HasColumnType("int"); + + b.Property("Count") + .HasColumnType("int"); + + b.Property("Duration") + .HasColumnType("time(6)"); + + b.Property("FillerKind") + .HasColumnType("int"); + + b.Property("FillerMode") + .HasColumnType("int"); + + b.Property("MediaItemId") + .HasColumnType("int"); + + b.Property("MultiCollectionId") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("PadToNearestMinute") + .HasColumnType("int"); + + b.Property("SmartCollectionId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CollectionId"); + + b.HasIndex("MediaItemId"); + + b.HasIndex("MultiCollectionId"); + + b.HasIndex("SmartCollectionId"); + + b.ToTable("FillerPreset", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ArtistMetadataId") + .HasColumnType("int"); + + b.Property("EpisodeMetadataId") + .HasColumnType("int"); + + b.Property("ImageMetadataId") + .HasColumnType("int"); + + b.Property("MovieMetadataId") + .HasColumnType("int"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("int"); + + b.Property("SeasonMetadataId") + .HasColumnType("int"); + + b.Property("ShowMetadataId") + .HasColumnType("int"); + + b.Property("SongMetadataId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ImageFolderDuration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DurationSeconds") + .HasColumnType("double"); + + b.Property("LibraryFolderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("LibraryFolderId") + .IsUnique(); + + b.ToTable("ImageFolderDuration", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ImageMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)"); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("DurationSeconds") + .HasColumnType("double"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("MetadataKind") + .HasColumnType("int"); + + b.Property("OriginalTitle") + .HasColumnType("longtext"); + + b.Property("ReleaseDate") + .HasColumnType("datetime(6)"); + + b.Property("SortTitle") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("ImageMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("ItemId") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("JellyfinCollection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Address") + .HasColumnType("longtext"); + + b.Property("JellyfinMediaSourceId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("JellyfinMediaSourceId"); + + b.ToTable("JellyfinConnection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinPathReplacement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("JellyfinMediaSourceId") + .HasColumnType("int"); + + b.Property("JellyfinPath") + .HasColumnType("longtext"); + + b.Property("LocalPath") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("JellyfinMediaSourceId"); + + b.ToTable("JellyfinPathReplacement", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LanguageCode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("EnglishName") + .HasColumnType("longtext"); + + b.Property("FrenchName") + .HasColumnType("longtext"); + + b.Property("ThreeCode1") + .HasColumnType("longtext"); + + b.Property("ThreeCode2") + .HasColumnType("longtext"); + + b.Property("TwoCode") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("LanguageCode", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("LastScan") + .HasColumnType("datetime(6)"); + + b.Property("MediaKind") + .HasColumnType("int"); + + b.Property("MediaSourceId") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("MediaSourceId"); + + b.ToTable("Library", (string)null); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LibraryFolder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("LibraryPathId") + .HasColumnType("int"); + + b.Property("ParentId") + .HasColumnType("int"); + + b.Property("Path") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("LibraryPathId"); + + b.HasIndex("ParentId"); + + b.ToTable("LibraryFolder", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LibraryPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("LastScan") + .HasColumnType("datetime(6)"); + + b.Property("LibraryId") + .HasColumnType("int"); + + b.Property("Path") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("LibraryPath", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaChapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChapterId") + .HasColumnType("bigint"); + + b.Property("EndTime") + .HasColumnType("time(6)"); + + b.Property("MediaVersionId") + .HasColumnType("int"); + + b.Property("StartTime") + .HasColumnType("time(6)"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("MediaVersionId"); + + b.ToTable("MediaChapter", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("LibraryFolderId") + .HasColumnType("int"); + + b.Property("MediaVersionId") + .HasColumnType("int"); + + b.Property("Path") + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("LibraryFolderId"); + + b.HasIndex("MediaVersionId"); + + b.HasIndex("Path") + .IsUnique(); + + b.ToTable("MediaFile", (string)null); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("LibraryPathId") + .HasColumnType("int"); + + b.Property("State") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("LibraryPathId"); + + b.ToTable("MediaItem", (string)null); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaSource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.HasKey("Id"); + + b.ToTable("MediaSource", (string)null); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AttachedPic") + .HasColumnType("tinyint(1)"); + + b.Property("BitsPerRawSample") + .HasColumnType("int"); + + b.Property("Channels") + .HasColumnType("int"); + + b.Property("Codec") + .HasColumnType("longtext"); + + b.Property("ColorPrimaries") + .HasColumnType("longtext"); + + b.Property("ColorRange") + .HasColumnType("longtext"); + + b.Property("ColorSpace") + .HasColumnType("longtext"); + + b.Property("ColorTransfer") + .HasColumnType("longtext"); + + b.Property("Default") + .HasColumnType("tinyint(1)"); + + b.Property("FileName") + .HasColumnType("longtext"); + + b.Property("Forced") + .HasColumnType("tinyint(1)"); + + b.Property("Index") + .HasColumnType("int"); + + b.Property("Language") + .HasColumnType("longtext"); + + b.Property("MediaStreamKind") + .HasColumnType("int"); + + b.Property("MediaVersionId") + .HasColumnType("int"); + + b.Property("MimeType") + .HasColumnType("longtext"); + + b.Property("PixelFormat") + .HasColumnType("longtext"); + + b.Property("Profile") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("MediaVersionId"); + + b.ToTable("MediaStream", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)"); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("DisplayAspectRatio") + .HasColumnType("longtext"); + + b.Property("Duration") + .HasColumnType("time(6)"); + + b.Property("EpisodeId") + .HasColumnType("int"); + + b.Property("Height") + .HasColumnType("int"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("MovieId") + .HasColumnType("int"); + + b.Property("MusicVideoId") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OtherVideoId") + .HasColumnType("int"); + + b.Property("RFrameRate") + .HasColumnType("longtext"); + + b.Property("SampleAspectRatio") + .HasColumnType("longtext"); + + b.Property("SongId") + .HasColumnType("int"); + + b.Property("VideoScanKind") + .HasColumnType("int"); + + b.Property("Width") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("EpisodeId"); + + b.HasIndex("ImageId"); + + b.HasIndex("MovieId"); + + b.HasIndex("MusicVideoId"); + + b.HasIndex("OtherVideoId"); + + b.HasIndex("SongId"); + + b.ToTable("MediaVersion", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MetadataGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ArtistMetadataId") + .HasColumnType("int"); + + b.Property("EpisodeMetadataId") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("longtext"); + + b.Property("ImageMetadataId") + .HasColumnType("int"); + + b.Property("MovieMetadataId") + .HasColumnType("int"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("int"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("int"); + + b.Property("SeasonMetadataId") + .HasColumnType("int"); + + b.Property("ShowMetadataId") + .HasColumnType("int"); + + b.Property("SongMetadataId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("MetadataGuid", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Mood", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ArtistMetadataId") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.ToTable("Mood"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MovieMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ContentRating") + .HasColumnType("longtext"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)"); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("MetadataKind") + .HasColumnType("int"); + + b.Property("MovieId") + .HasColumnType("int"); + + b.Property("OriginalTitle") + .HasColumnType("longtext"); + + b.Property("Outline") + .HasColumnType("longtext"); + + b.Property("Plot") + .HasColumnType("longtext"); + + b.Property("ReleaseDate") + .HasColumnType("datetime(6)"); + + b.Property("SortTitle") + .HasColumnType("longtext"); + + b.Property("Tagline") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("MovieId"); + + b.ToTable("MovieMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("MultiCollection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollectionItem", b => + { + b.Property("MultiCollectionId") + .HasColumnType("int"); + + b.Property("CollectionId") + .HasColumnType("int"); + + b.Property("PlaybackOrder") + .HasColumnType("int"); + + b.Property("ScheduleAsGroup") + .HasColumnType("tinyint(1)"); + + b.HasKey("MultiCollectionId", "CollectionId"); + + b.HasIndex("CollectionId"); + + b.ToTable("MultiCollectionItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollectionSmartItem", b => + { + b.Property("MultiCollectionId") + .HasColumnType("int"); + + b.Property("SmartCollectionId") + .HasColumnType("int"); + + b.Property("PlaybackOrder") + .HasColumnType("int"); + + b.Property("ScheduleAsGroup") + .HasColumnType("tinyint(1)"); + + b.HasKey("MultiCollectionId", "SmartCollectionId"); + + b.HasIndex("SmartCollectionId"); + + b.ToTable("MultiCollectionSmartItem"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoArtist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("MusicVideoMetadataId") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("MusicVideoMetadataId"); + + b.ToTable("MusicVideoArtist"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Album") + .HasColumnType("longtext"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)"); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("MetadataKind") + .HasColumnType("int"); + + b.Property("MusicVideoId") + .HasColumnType("int"); + + b.Property("OriginalTitle") + .HasColumnType("longtext"); + + b.Property("Plot") + .HasColumnType("longtext"); + + b.Property("ReleaseDate") + .HasColumnType("datetime(6)"); + + b.Property("SortTitle") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("Track") + .HasColumnType("int"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("MusicVideoId"); + + b.ToTable("MusicVideoMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.OtherVideoMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ContentRating") + .HasColumnType("longtext"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)"); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("MetadataKind") + .HasColumnType("int"); + + b.Property("OriginalTitle") + .HasColumnType("longtext"); + + b.Property("OtherVideoId") + .HasColumnType("int"); + + b.Property("Outline") + .HasColumnType("longtext"); + + b.Property("Plot") + .HasColumnType("longtext"); + + b.Property("ReleaseDate") + .HasColumnType("datetime(6)"); + + b.Property("SortTitle") + .HasColumnType("longtext"); + + b.Property("Tagline") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OtherVideoId"); + + b.ToTable("OtherVideoMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Playout", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("int"); + + b.Property("DailyRebuildTime") + .HasColumnType("time(6)"); + + b.Property("ExternalJsonFile") + .HasColumnType("longtext"); + + b.Property("ProgramScheduleId") + .HasColumnType("int"); + + b.Property("ProgramSchedulePlayoutType") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ChannelId"); + + b.HasIndex("ProgramScheduleId"); + + b.ToTable("Playout", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlayoutItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("BlockKey") + .HasColumnType("longtext"); + + b.Property("ChapterTitle") + .HasColumnType("longtext"); + + b.Property("CollectionEtag") + .HasColumnType("longtext"); + + b.Property("CollectionKey") + .HasColumnType("longtext"); + + b.Property("CustomTitle") + .HasColumnType("longtext"); + + b.Property("DisableWatermarks") + .HasColumnType("tinyint(1)"); + + b.Property("FillerKind") + .HasColumnType("int"); + + b.Property("Finish") + .HasColumnType("datetime(6)"); + + b.Property("GuideFinish") + .HasColumnType("datetime(6)"); + + b.Property("GuideGroup") + .HasColumnType("int"); + + b.Property("GuideStart") + .HasColumnType("datetime(6)"); + + b.Property("InPoint") + .HasColumnType("time(6)"); + + b.Property("MediaItemId") + .HasColumnType("int"); + + b.Property("OutPoint") + .HasColumnType("time(6)"); + + b.Property("PlayoutId") + .HasColumnType("int"); + + b.Property("PreferredAudioLanguageCode") + .HasColumnType("longtext"); + + b.Property("PreferredAudioTitle") + .HasColumnType("longtext"); + + b.Property("PreferredSubtitleLanguageCode") + .HasColumnType("longtext"); + + b.Property("Start") + .HasColumnType("datetime(6)"); + + b.Property("SubtitleMode") + .HasColumnType("int"); + + b.Property("WatermarkId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("MediaItemId"); + + b.HasIndex("PlayoutId"); + + b.HasIndex("WatermarkId"); + + b.ToTable("PlayoutItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlayoutProgramScheduleAnchor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AnchorDate") + .HasColumnType("datetime(6)"); + + b.Property("CollectionId") + .HasColumnType("int"); + + b.Property("CollectionType") + .HasColumnType("int"); + + b.Property("FakeCollectionKey") + .HasColumnType("longtext"); + + b.Property("MediaItemId") + .HasColumnType("int"); + + b.Property("MultiCollectionId") + .HasColumnType("int"); + + b.Property("PlayoutId") + .HasColumnType("int"); + + b.Property("SmartCollectionId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CollectionId"); + + b.HasIndex("MediaItemId"); + + b.HasIndex("MultiCollectionId"); + + b.HasIndex("PlayoutId"); + + b.HasIndex("SmartCollectionId"); + + b.ToTable("PlayoutProgramScheduleAnchor", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlayoutScheduleItemFillGroupIndex", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("PlayoutId") + .HasColumnType("int"); + + b.Property("ProgramScheduleItemId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PlayoutId"); + + b.HasIndex("ProgramScheduleItemId"); + + b.ToTable("PlayoutScheduleItemFillGroupIndex", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("PlexCollection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("PlexMediaSourceId") + .HasColumnType("int"); + + b.Property("Uri") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("PlexMediaSourceId"); + + b.ToTable("PlexConnection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexPathReplacement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("LocalPath") + .HasColumnType("longtext"); + + b.Property("PlexMediaSourceId") + .HasColumnType("int"); + + b.Property("PlexPath") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("PlexMediaSourceId"); + + b.ToTable("PlexPathReplacement", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("KeepMultiPartEpisodesTogether") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("RandomStartPoint") + .HasColumnType("tinyint(1)"); + + b.Property("ShuffleScheduleItems") + .HasColumnType("tinyint(1)"); + + b.Property("TreatCollectionsAsShows") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("ProgramSchedule", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleAlternate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DaysOfMonth") + .HasColumnType("longtext"); + + b.Property("DaysOfWeek") + .HasColumnType("longtext"); + + b.Property("Index") + .HasColumnType("int"); + + b.Property("MonthsOfYear") + .HasColumnType("longtext"); + + b.Property("PlayoutId") + .HasColumnType("int"); + + b.Property("ProgramScheduleId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PlayoutId"); + + b.HasIndex("ProgramScheduleId"); + + b.ToTable("ProgramScheduleAlternate", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CollectionId") + .HasColumnType("int"); + + b.Property("CollectionType") + .HasColumnType("int"); + + b.Property("CustomTitle") + .HasColumnType("longtext"); + + b.Property("FakeCollectionKey") + .HasColumnType("longtext"); + + b.Property("FallbackFillerId") + .HasColumnType("int"); + + b.Property("FillWithGroupMode") + .HasColumnType("int"); + + b.Property("GuideMode") + .HasColumnType("int"); + + b.Property("Index") + .HasColumnType("int"); + + b.Property("MediaItemId") + .HasColumnType("int"); + + b.Property("MidRollFillerId") + .HasColumnType("int"); + + b.Property("MultiCollectionId") + .HasColumnType("int"); + + b.Property("PlaybackOrder") + .HasColumnType("int"); + + b.Property("PostRollFillerId") + .HasColumnType("int"); + + b.Property("PreRollFillerId") + .HasColumnType("int"); + + b.Property("PreferredAudioLanguageCode") + .HasColumnType("longtext"); + + b.Property("PreferredAudioTitle") + .HasColumnType("longtext"); + + b.Property("PreferredSubtitleLanguageCode") + .HasColumnType("longtext"); + + b.Property("ProgramScheduleId") + .HasColumnType("int"); + + b.Property("SmartCollectionId") + .HasColumnType("int"); + + b.Property("StartTime") + .HasColumnType("time(6)"); + + b.Property("SubtitleMode") + .HasColumnType("int"); + + b.Property("TailFillerId") + .HasColumnType("int"); + + b.Property("WatermarkId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CollectionId"); + + b.HasIndex("FallbackFillerId"); + + b.HasIndex("MediaItemId"); + + b.HasIndex("MidRollFillerId"); + + b.HasIndex("MultiCollectionId"); + + b.HasIndex("PostRollFillerId"); + + b.HasIndex("PreRollFillerId"); + + b.HasIndex("ProgramScheduleId"); + + b.HasIndex("SmartCollectionId"); + + b.HasIndex("TailFillerId"); + + b.HasIndex("WatermarkId"); + + b.ToTable("ProgramScheduleItem", (string)null); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Resolution", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Height") + .HasColumnType("int"); + + b.Property("IsCustom") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("Width") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Resolution", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Block", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("BlockGroupId") + .HasColumnType("int"); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("Minutes") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("StopScheduling") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("BlockGroupId", "Name") + .IsUnique(); + + b.ToTable("Block", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.BlockGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("BlockGroup", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.BlockItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("BlockId") + .HasColumnType("int"); + + b.Property("CollectionId") + .HasColumnType("int"); + + b.Property("CollectionType") + .HasColumnType("int"); + + b.Property("IncludeInProgramGuide") + .HasColumnType("tinyint(1)"); + + b.Property("Index") + .HasColumnType("int"); + + b.Property("MediaItemId") + .HasColumnType("int"); + + b.Property("MultiCollectionId") + .HasColumnType("int"); + + b.Property("PlaybackOrder") + .HasColumnType("int"); + + b.Property("SmartCollectionId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("BlockId"); + + b.HasIndex("CollectionId"); + + b.HasIndex("MediaItemId"); + + b.HasIndex("MultiCollectionId"); + + b.HasIndex("SmartCollectionId"); + + b.ToTable("BlockItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.PlayoutHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("BlockId") + .HasColumnType("int"); + + b.Property("Details") + .HasColumnType("longtext"); + + b.Property("Index") + .HasColumnType("int"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("PlaybackOrder") + .HasColumnType("int"); + + b.Property("PlayoutId") + .HasColumnType("int"); + + b.Property("When") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("BlockId"); + + b.HasIndex("PlayoutId"); + + b.ToTable("PlayoutHistory", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.PlayoutTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("DaysOfMonth") + .HasColumnType("longtext"); + + b.Property("DaysOfWeek") + .HasColumnType("longtext"); + + b.Property("EndDate") + .HasColumnType("datetime(6)"); + + b.Property("Index") + .HasColumnType("int"); + + b.Property("MonthsOfYear") + .HasColumnType("longtext"); + + b.Property("PlayoutId") + .HasColumnType("int"); + + b.Property("StartDate") + .HasColumnType("datetime(6)"); + + b.Property("TemplateId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PlayoutId"); + + b.HasIndex("TemplateId"); + + b.ToTable("PlayoutTemplate", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Template", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("TemplateGroupId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("TemplateGroupId"); + + b.ToTable("Template", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.TemplateGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("TemplateGroup", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.TemplateItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("BlockId") + .HasColumnType("int"); + + b.Property("StartTime") + .HasColumnType("time(6)"); + + b.Property("TemplateId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("BlockId"); + + b.HasIndex("TemplateId"); + + b.ToTable("TemplateItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SeasonMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)"); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("MetadataKind") + .HasColumnType("int"); + + b.Property("OriginalTitle") + .HasColumnType("longtext"); + + b.Property("Outline") + .HasColumnType("longtext"); + + b.Property("ReleaseDate") + .HasColumnType("datetime(6)"); + + b.Property("SeasonId") + .HasColumnType("int"); + + b.Property("SortTitle") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("SeasonId"); + + b.ToTable("SeasonMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ShowMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ContentRating") + .HasColumnType("longtext"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)"); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("MetadataKind") + .HasColumnType("int"); + + b.Property("OriginalTitle") + .HasColumnType("longtext"); + + b.Property("Outline") + .HasColumnType("longtext"); + + b.Property("Plot") + .HasColumnType("longtext"); + + b.Property("ReleaseDate") + .HasColumnType("datetime(6)"); + + b.Property("ShowId") + .HasColumnType("int"); + + b.Property("SortTitle") + .HasColumnType("longtext"); + + b.Property("Tagline") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ShowId"); + + b.ToTable("ShowMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SmartCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("Query") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("SmartCollection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SongMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Album") + .HasColumnType("longtext"); + + b.Property("AlbumArtists") + .HasColumnType("longtext"); + + b.Property("Artists") + .HasColumnType("longtext"); + + b.Property("Comment") + .HasColumnType("longtext"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)"); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("MetadataKind") + .HasColumnType("int"); + + b.Property("OriginalTitle") + .HasColumnType("longtext"); + + b.Property("ReleaseDate") + .HasColumnType("datetime(6)"); + + b.Property("SongId") + .HasColumnType("int"); + + b.Property("SortTitle") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("Track") + .HasColumnType("longtext"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("SongId"); + + b.ToTable("SongMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Studio", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ArtistMetadataId") + .HasColumnType("int"); + + b.Property("EpisodeMetadataId") + .HasColumnType("int"); + + b.Property("ImageMetadataId") + .HasColumnType("int"); + + b.Property("MovieMetadataId") + .HasColumnType("int"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("int"); + + b.Property("SeasonMetadataId") + .HasColumnType("int"); + + b.Property("ShowMetadataId") + .HasColumnType("int"); + + b.Property("SongMetadataId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("Studio", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Style", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ArtistMetadataId") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.ToTable("Style"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Subtitle", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ArtistMetadataId") + .HasColumnType("int"); + + b.Property("Codec") + .HasColumnType("longtext"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)"); + + b.Property("DateUpdated") + .HasColumnType("datetime(6)"); + + b.Property("Default") + .HasColumnType("tinyint(1)"); + + b.Property("EpisodeMetadataId") + .HasColumnType("int"); + + b.Property("Forced") + .HasColumnType("tinyint(1)"); + + b.Property("ImageMetadataId") + .HasColumnType("int"); + + b.Property("IsExtracted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("Language") + .HasColumnType("longtext"); + + b.Property("MovieMetadataId") + .HasColumnType("int"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("int"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("int"); + + b.Property("Path") + .HasColumnType("longtext"); + + b.Property("SDH") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("SeasonMetadataId") + .HasColumnType("int"); + + b.Property("ShowMetadataId") + .HasColumnType("int"); + + b.Property("SongMetadataId") + .HasColumnType("int"); + + b.Property("StreamIndex") + .HasColumnType("int"); + + b.Property("SubtitleKind") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("Subtitle", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ArtistMetadataId") + .HasColumnType("int"); + + b.Property("EpisodeMetadataId") + .HasColumnType("int"); + + b.Property("ExternalCollectionId") + .HasColumnType("longtext"); + + b.Property("ImageMetadataId") + .HasColumnType("int"); + + b.Property("MovieMetadataId") + .HasColumnType("int"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("int"); + + b.Property("SeasonMetadataId") + .HasColumnType("int"); + + b.Property("ShowMetadataId") + .HasColumnType("int"); + + b.Property("SongMetadataId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("Tag"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ItemCount") + .HasColumnType("int"); + + b.Property("List") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("TraktId") + .HasColumnType("int"); + + b.Property("User") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("TraktList", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Episode") + .HasColumnType("int"); + + b.Property("Kind") + .HasColumnType("int"); + + b.Property("MediaItemId") + .HasColumnType("int"); + + b.Property("Rank") + .HasColumnType("int"); + + b.Property("Season") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("TraktId") + .HasColumnType("int"); + + b.Property("TraktListId") + .HasColumnType("int"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("MediaItemId"); + + b.HasIndex("TraktListId"); + + b.ToTable("TraktListItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktListItemGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("longtext"); + + b.Property("TraktListItemId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TraktListItemId"); + + b.ToTable("TraktListItemGuid", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Writer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("EpisodeMetadataId") + .HasColumnType("int"); + + b.Property("MovieMetadataId") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.ToTable("Writer", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Emby.EmbyPathInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("EmbyLibraryId") + .HasColumnType("int"); + + b.Property("NetworkPath") + .HasColumnType("longtext"); + + b.Property("Path") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("EmbyLibraryId"); + + b.ToTable("EmbyPathInfo"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Jellyfin.JellyfinPathInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("JellyfinLibraryId") + .HasColumnType("int"); + + b.Property("NetworkPath") + .HasColumnType("longtext"); + + b.Property("Path") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("JellyfinLibraryId"); + + b.ToTable("JellyfinPathInfo"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyLibrary", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Library"); + + b.Property("ItemId") + .HasColumnType("longtext"); + + b.Property("ShouldSyncItems") + .HasColumnType("tinyint(1)"); + + b.ToTable("EmbyLibrary", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinLibrary", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Library"); + + b.Property("ItemId") + .HasColumnType("longtext"); + + b.Property("ShouldSyncItems") + .HasColumnType("tinyint(1)"); + + b.ToTable("JellyfinLibrary", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LocalLibrary", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Library"); + + b.ToTable("LocalLibrary", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexLibrary", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Library"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("ShouldSyncItems") + .HasColumnType("tinyint(1)"); + + b.ToTable("PlexLibrary", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMediaFile", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaFile"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("PlexId") + .HasColumnType("int"); + + b.ToTable("PlexMediaFile", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Artist", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.ToTable("Artist", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Episode", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.Property("SeasonId") + .HasColumnType("int"); + + b.HasIndex("SeasonId"); + + b.ToTable("Episode", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Image", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.ToTable("Image", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Movie", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.ToTable("Movie", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideo", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.Property("ArtistId") + .HasColumnType("int"); + + b.HasIndex("ArtistId"); + + b.ToTable("MusicVideo", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.OtherVideo", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.ToTable("OtherVideo", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Season", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.Property("SeasonNumber") + .HasColumnType("int"); + + b.Property("ShowId") + .HasColumnType("int"); + + b.HasIndex("ShowId"); + + b.ToTable("Season", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Show", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.ToTable("Show", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Song", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.ToTable("Song", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyMediaSource", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaSource"); + + b.Property("LastCollectionsScan") + .HasColumnType("datetime(6)"); + + b.Property("OperatingSystem") + .HasColumnType("longtext"); + + b.Property("ServerName") + .HasColumnType("longtext"); + + b.ToTable("EmbyMediaSource", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinMediaSource", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaSource"); + + b.Property("LastCollectionsScan") + .HasColumnType("datetime(6)"); + + b.Property("OperatingSystem") + .HasColumnType("longtext"); + + b.Property("ServerName") + .HasColumnType("longtext"); + + b.ToTable("JellyfinMediaSource", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LocalMediaSource", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaSource"); + + b.ToTable("LocalMediaSource", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMediaSource", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaSource"); + + b.Property("ClientIdentifier") + .HasColumnType("longtext"); + + b.Property("LastCollectionsScan") + .HasColumnType("datetime(6)"); + + b.Property("Platform") + .HasColumnType("longtext"); + + b.Property("PlatformVersion") + .HasColumnType("longtext"); + + b.Property("ProductVersion") + .HasColumnType("longtext"); + + b.Property("ServerName") + .HasColumnType("longtext"); + + b.ToTable("PlexMediaSource", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemDuration", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.ProgramScheduleItem"); + + b.Property("DiscardToFillAttempts") + .HasColumnType("int"); + + b.Property("PlayoutDuration") + .HasColumnType("time(6)"); + + b.Property("TailMode") + .HasColumnType("int"); + + b.ToTable("ProgramScheduleDurationItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemFlood", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.ProgramScheduleItem"); + + b.ToTable("ProgramScheduleFloodItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemMultiple", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.ProgramScheduleItem"); + + b.Property("Count") + .HasColumnType("int"); + + b.ToTable("ProgramScheduleMultipleItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemOne", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.ProgramScheduleItem"); + + b.ToTable("ProgramScheduleOneItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyEpisode", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Episode"); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("ItemId") + .HasColumnType("longtext"); + + b.ToTable("EmbyEpisode", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinEpisode", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Episode"); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("ItemId") + .HasColumnType("longtext"); + + b.ToTable("JellyfinEpisode", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexEpisode", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Episode"); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.ToTable("PlexEpisode", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyMovie", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Movie"); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("ItemId") + .HasColumnType("longtext"); + + b.ToTable("EmbyMovie", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinMovie", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Movie"); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("ItemId") + .HasColumnType("longtext"); + + b.ToTable("JellyfinMovie", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMovie", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Movie"); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.ToTable("PlexMovie", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbySeason", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Season"); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("ItemId") + .HasColumnType("longtext"); + + b.ToTable("EmbySeason", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinSeason", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Season"); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("ItemId") + .HasColumnType("longtext"); + + b.ToTable("JellyfinSeason", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexSeason", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Season"); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.ToTable("PlexSeason", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyShow", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Show"); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("ItemId") + .HasColumnType("longtext"); + + b.ToTable("EmbyShow", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinShow", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Show"); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("ItemId") + .HasColumnType("longtext"); + + b.ToTable("JellyfinShow", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexShow", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Show"); + + b.Property("Etag") + .HasColumnType("longtext"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.ToTable("PlexShow", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Actor", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Actors") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Artwork", "Artwork") + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Actor", "ArtworkId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Actors") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Actors") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Actors") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Actors") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Actors") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Actors") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Actors") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Actors") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Artwork"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ArtistMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Artist", "Artist") + .WithMany("ArtistMetadata") + .HasForeignKey("ArtistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Artist"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Artwork", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Artwork") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Channel", null) + .WithMany("Artwork") + .HasForeignKey("ChannelId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Artwork") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Artwork") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Artwork") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Artwork") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Artwork") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Artwork") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Artwork") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Artwork") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Channel", b => + { + b.HasOne("ErsatzTV.Core.Domain.FFmpegProfile", "FFmpegProfile") + .WithMany() + .HasForeignKey("FFmpegProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Filler.FillerPreset", "FallbackFiller") + .WithMany() + .HasForeignKey("FallbackFillerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.ChannelWatermark", "Watermark") + .WithMany() + .HasForeignKey("WatermarkId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("FFmpegProfile"); + + b.Navigation("FallbackFiller"); + + b.Navigation("Watermark"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.CollectionItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.Collection", "Collection") + .WithMany("CollectionItems") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany("CollectionItems") + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("MediaItem"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Director", b => + { + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Directors") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Directors") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Directors") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Directors") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyConnection", b => + { + b.HasOne("ErsatzTV.Core.Domain.EmbyMediaSource", "EmbyMediaSource") + .WithMany("Connections") + .HasForeignKey("EmbyMediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EmbyMediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyPathReplacement", b => + { + b.HasOne("ErsatzTV.Core.Domain.EmbyMediaSource", "EmbyMediaSource") + .WithMany("PathReplacements") + .HasForeignKey("EmbyMediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EmbyMediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EpisodeMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Episode", "Episode") + .WithMany("EpisodeMetadata") + .HasForeignKey("EpisodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Episode"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.FFmpegProfile", b => + { + b.HasOne("ErsatzTV.Core.Domain.Resolution", "Resolution") + .WithMany() + .HasForeignKey("ResolutionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Resolution"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Filler.FillerPreset", b => + { + b.HasOne("ErsatzTV.Core.Domain.Collection", "Collection") + .WithMany() + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany() + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection") + .WithMany() + .HasForeignKey("MultiCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SmartCollection", "SmartCollection") + .WithMany() + .HasForeignKey("SmartCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Collection"); + + b.Navigation("MediaItem"); + + b.Navigation("MultiCollection"); + + b.Navigation("SmartCollection"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Genre", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Genres") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Genres") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Genres") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Genres") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Genres") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Genres") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Genres") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Genres") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Genres") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ImageFolderDuration", b => + { + b.HasOne("ErsatzTV.Core.Domain.LibraryFolder", "LibraryFolder") + .WithOne("ImageFolderDuration") + .HasForeignKey("ErsatzTV.Core.Domain.ImageFolderDuration", "LibraryFolderId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("LibraryFolder"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ImageMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Image", "Image") + .WithMany("ImageMetadata") + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinConnection", b => + { + b.HasOne("ErsatzTV.Core.Domain.JellyfinMediaSource", "JellyfinMediaSource") + .WithMany("Connections") + .HasForeignKey("JellyfinMediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("JellyfinMediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinPathReplacement", b => + { + b.HasOne("ErsatzTV.Core.Domain.JellyfinMediaSource", "JellyfinMediaSource") + .WithMany("PathReplacements") + .HasForeignKey("JellyfinMediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("JellyfinMediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Library", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaSource", "MediaSource") + .WithMany("Libraries") + .HasForeignKey("MediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LibraryFolder", b => + { + b.HasOne("ErsatzTV.Core.Domain.LibraryPath", "LibraryPath") + .WithMany("LibraryFolders") + .HasForeignKey("LibraryPathId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.LibraryFolder", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("LibraryPath"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LibraryPath", b => + { + b.HasOne("ErsatzTV.Core.Domain.Library", "Library") + .WithMany("Paths") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaChapter", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaVersion", "MediaVersion") + .WithMany("Chapters") + .HasForeignKey("MediaVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaVersion"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaFile", b => + { + b.HasOne("ErsatzTV.Core.Domain.LibraryFolder", "LibraryFolder") + .WithMany("MediaFiles") + .HasForeignKey("LibraryFolderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("ErsatzTV.Core.Domain.MediaVersion", "MediaVersion") + .WithMany("MediaFiles") + .HasForeignKey("MediaVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LibraryFolder"); + + b.Navigation("MediaVersion"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.LibraryPath", "LibraryPath") + .WithMany("MediaItems") + .HasForeignKey("LibraryPathId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LibraryPath"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaStream", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaVersion", "MediaVersion") + .WithMany("Streams") + .HasForeignKey("MediaVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaVersion"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaVersion", b => + { + b.HasOne("ErsatzTV.Core.Domain.Episode", null) + .WithMany("MediaVersions") + .HasForeignKey("EpisodeId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Image", null) + .WithMany("MediaVersions") + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Movie", null) + .WithMany("MediaVersions") + .HasForeignKey("MovieId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideo", null) + .WithMany("MediaVersions") + .HasForeignKey("MusicVideoId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideo", null) + .WithMany("MediaVersions") + .HasForeignKey("OtherVideoId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Song", null) + .WithMany("MediaVersions") + .HasForeignKey("SongId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MetadataGuid", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Guids") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Guids") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Guids") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Guids") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Guids") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Guids") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Guids") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Guids") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Guids") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Mood", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Moods") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MovieMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Movie", "Movie") + .WithMany("MovieMetadata") + .HasForeignKey("MovieId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Movie"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollectionItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.Collection", "Collection") + .WithMany("MultiCollectionItems") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection") + .WithMany("MultiCollectionItems") + .HasForeignKey("MultiCollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("MultiCollection"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollectionSmartItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection") + .WithMany("MultiCollectionSmartItems") + .HasForeignKey("MultiCollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.SmartCollection", "SmartCollection") + .WithMany("MultiCollectionSmartItems") + .HasForeignKey("SmartCollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MultiCollection"); + + b.Navigation("SmartCollection"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoArtist", b => + { + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Artists") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.MusicVideo", "MusicVideo") + .WithMany("MusicVideoMetadata") + .HasForeignKey("MusicVideoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MusicVideo"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.OtherVideoMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.OtherVideo", "OtherVideo") + .WithMany("OtherVideoMetadata") + .HasForeignKey("OtherVideoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("OtherVideo"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Playout", b => + { + b.HasOne("ErsatzTV.Core.Domain.Channel", "Channel") + .WithMany("Playouts") + .HasForeignKey("ChannelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.ProgramSchedule", "ProgramSchedule") + .WithMany("Playouts") + .HasForeignKey("ProgramScheduleId") + .OnDelete(DeleteBehavior.Cascade); + + b.OwnsOne("ErsatzTV.Core.Domain.PlayoutAnchor", "Anchor", b1 => + { + b1.Property("PlayoutId") + .HasColumnType("int"); + + b1.Property("DurationFinish") + .HasColumnType("datetime(6)"); + + b1.Property("InDurationFiller") + .HasColumnType("tinyint(1)"); + + b1.Property("InFlood") + .HasColumnType("tinyint(1)"); + + b1.Property("MultipleRemaining") + .HasColumnType("int"); + + b1.Property("NextGuideGroup") + .HasColumnType("int"); + + b1.Property("NextStart") + .HasColumnType("datetime(6)"); + + b1.HasKey("PlayoutId"); + + b1.ToTable("PlayoutAnchor", (string)null); + + b1.WithOwner() + .HasForeignKey("PlayoutId"); + + b1.OwnsOne("ErsatzTV.Core.Domain.CollectionEnumeratorState", "ScheduleItemsEnumeratorState", b2 => + { + b2.Property("PlayoutAnchorPlayoutId") + .HasColumnType("int"); + + b2.Property("Index") + .HasColumnType("int"); + + b2.Property("Seed") + .HasColumnType("int"); + + b2.HasKey("PlayoutAnchorPlayoutId"); + + b2.ToTable("ScheduleItemsEnumeratorState", (string)null); + + b2.WithOwner() + .HasForeignKey("PlayoutAnchorPlayoutId"); + }); + + b1.Navigation("ScheduleItemsEnumeratorState"); + }); + + b.Navigation("Anchor"); + + b.Navigation("Channel"); + + b.Navigation("ProgramSchedule"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlayoutItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany() + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Playout", "Playout") + .WithMany("Items") + .HasForeignKey("PlayoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.ChannelWatermark", "Watermark") + .WithMany() + .HasForeignKey("WatermarkId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("MediaItem"); + + b.Navigation("Playout"); + + b.Navigation("Watermark"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlayoutProgramScheduleAnchor", b => + { + b.HasOne("ErsatzTV.Core.Domain.Collection", "Collection") + .WithMany() + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany() + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection") + .WithMany() + .HasForeignKey("MultiCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Playout", "Playout") + .WithMany("ProgramScheduleAnchors") + .HasForeignKey("PlayoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.SmartCollection", "SmartCollection") + .WithMany() + .HasForeignKey("SmartCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.OwnsOne("ErsatzTV.Core.Domain.CollectionEnumeratorState", "EnumeratorState", b1 => + { + b1.Property("PlayoutProgramScheduleAnchorId") + .HasColumnType("int"); + + b1.Property("Index") + .HasColumnType("int"); + + b1.Property("Seed") + .HasColumnType("int"); + + b1.HasKey("PlayoutProgramScheduleAnchorId"); + + b1.ToTable("CollectionEnumeratorState", (string)null); + + b1.WithOwner() + .HasForeignKey("PlayoutProgramScheduleAnchorId"); + }); + + b.Navigation("Collection"); + + b.Navigation("EnumeratorState"); + + b.Navigation("MediaItem"); + + b.Navigation("MultiCollection"); + + b.Navigation("Playout"); + + b.Navigation("SmartCollection"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlayoutScheduleItemFillGroupIndex", b => + { + b.HasOne("ErsatzTV.Core.Domain.Playout", "Playout") + .WithMany("FillGroupIndices") + .HasForeignKey("PlayoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", "ProgramScheduleItem") + .WithMany() + .HasForeignKey("ProgramScheduleItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("ErsatzTV.Core.Domain.CollectionEnumeratorState", "EnumeratorState", b1 => + { + b1.Property("PlayoutScheduleItemFillGroupIndexId") + .HasColumnType("int"); + + b1.Property("Index") + .HasColumnType("int"); + + b1.Property("Seed") + .HasColumnType("int"); + + b1.HasKey("PlayoutScheduleItemFillGroupIndexId"); + + b1.ToTable("FillGroupEnumeratorState", (string)null); + + b1.WithOwner() + .HasForeignKey("PlayoutScheduleItemFillGroupIndexId"); + }); + + b.Navigation("EnumeratorState"); + + b.Navigation("Playout"); + + b.Navigation("ProgramScheduleItem"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexConnection", b => + { + b.HasOne("ErsatzTV.Core.Domain.PlexMediaSource", "PlexMediaSource") + .WithMany("Connections") + .HasForeignKey("PlexMediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PlexMediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexPathReplacement", b => + { + b.HasOne("ErsatzTV.Core.Domain.PlexMediaSource", "PlexMediaSource") + .WithMany("PathReplacements") + .HasForeignKey("PlexMediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PlexMediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleAlternate", b => + { + b.HasOne("ErsatzTV.Core.Domain.Playout", "Playout") + .WithMany("ProgramScheduleAlternates") + .HasForeignKey("PlayoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.ProgramSchedule", "ProgramSchedule") + .WithMany("ProgramScheduleAlternates") + .HasForeignKey("ProgramScheduleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Playout"); + + b.Navigation("ProgramSchedule"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.Collection", "Collection") + .WithMany() + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Filler.FillerPreset", "FallbackFiller") + .WithMany() + .HasForeignKey("FallbackFillerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany() + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Filler.FillerPreset", "MidRollFiller") + .WithMany() + .HasForeignKey("MidRollFillerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection") + .WithMany() + .HasForeignKey("MultiCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Filler.FillerPreset", "PostRollFiller") + .WithMany() + .HasForeignKey("PostRollFillerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.Filler.FillerPreset", "PreRollFiller") + .WithMany() + .HasForeignKey("PreRollFillerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.ProgramSchedule", "ProgramSchedule") + .WithMany("Items") + .HasForeignKey("ProgramScheduleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SmartCollection", "SmartCollection") + .WithMany() + .HasForeignKey("SmartCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Filler.FillerPreset", "TailFiller") + .WithMany() + .HasForeignKey("TailFillerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.ChannelWatermark", "Watermark") + .WithMany() + .HasForeignKey("WatermarkId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Collection"); + + b.Navigation("FallbackFiller"); + + b.Navigation("MediaItem"); + + b.Navigation("MidRollFiller"); + + b.Navigation("MultiCollection"); + + b.Navigation("PostRollFiller"); + + b.Navigation("PreRollFiller"); + + b.Navigation("ProgramSchedule"); + + b.Navigation("SmartCollection"); + + b.Navigation("TailFiller"); + + b.Navigation("Watermark"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Block", b => + { + b.HasOne("ErsatzTV.Core.Domain.Scheduling.BlockGroup", "BlockGroup") + .WithMany("Blocks") + .HasForeignKey("BlockGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BlockGroup"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.BlockItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.Scheduling.Block", "Block") + .WithMany("Items") + .HasForeignKey("BlockId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Collection", "Collection") + .WithMany() + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany() + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection") + .WithMany() + .HasForeignKey("MultiCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SmartCollection", "SmartCollection") + .WithMany() + .HasForeignKey("SmartCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Block"); + + b.Navigation("Collection"); + + b.Navigation("MediaItem"); + + b.Navigation("MultiCollection"); + + b.Navigation("SmartCollection"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.PlayoutHistory", b => + { + b.HasOne("ErsatzTV.Core.Domain.Scheduling.Block", "Block") + .WithMany("PlayoutHistory") + .HasForeignKey("BlockId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Playout", "Playout") + .WithMany("PlayoutHistory") + .HasForeignKey("PlayoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Block"); + + b.Navigation("Playout"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.PlayoutTemplate", b => + { + b.HasOne("ErsatzTV.Core.Domain.Playout", "Playout") + .WithMany("Templates") + .HasForeignKey("PlayoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Scheduling.Template", "Template") + .WithMany("PlayoutTemplates") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Playout"); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Template", b => + { + b.HasOne("ErsatzTV.Core.Domain.Scheduling.TemplateGroup", "TemplateGroup") + .WithMany("Templates") + .HasForeignKey("TemplateGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TemplateGroup"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.TemplateItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.Scheduling.Block", "Block") + .WithMany("TemplateItems") + .HasForeignKey("BlockId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Scheduling.Template", "Template") + .WithMany("Items") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Block"); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SeasonMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Season", "Season") + .WithMany("SeasonMetadata") + .HasForeignKey("SeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Season"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ShowMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Show", "Show") + .WithMany("ShowMetadata") + .HasForeignKey("ShowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Show"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SongMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Song", "Song") + .WithMany("SongMetadata") + .HasForeignKey("SongId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Song"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Studio", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Studios") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Studios") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Studios") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Studios") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Studios") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Studios") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Studios") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Studios") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Studios") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Style", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Styles") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Subtitle", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Tag", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Tags") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Tags") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Tags") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Tags") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Tags") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Tags") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Tags") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Tags") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Tags") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktListItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany("TraktListItems") + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.TraktList", "TraktList") + .WithMany("Items") + .HasForeignKey("TraktListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaItem"); + + b.Navigation("TraktList"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktListItemGuid", b => + { + b.HasOne("ErsatzTV.Core.Domain.TraktListItem", "TraktListItem") + .WithMany("Guids") + .HasForeignKey("TraktListItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TraktListItem"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Writer", b => + { + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Writers") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Writers") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Writers") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Emby.EmbyPathInfo", b => + { + b.HasOne("ErsatzTV.Core.Domain.EmbyLibrary", null) + .WithMany("PathInfos") + .HasForeignKey("EmbyLibraryId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Jellyfin.JellyfinPathInfo", b => + { + b.HasOne("ErsatzTV.Core.Domain.JellyfinLibrary", null) + .WithMany("PathInfos") + .HasForeignKey("JellyfinLibraryId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyLibrary", b => + { + b.HasOne("ErsatzTV.Core.Domain.Library", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.EmbyLibrary", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinLibrary", b => + { + b.HasOne("ErsatzTV.Core.Domain.Library", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.JellyfinLibrary", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LocalLibrary", b => + { + b.HasOne("ErsatzTV.Core.Domain.Library", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.LocalLibrary", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexLibrary", b => + { + b.HasOne("ErsatzTV.Core.Domain.Library", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexLibrary", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMediaFile", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaFile", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexMediaFile", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Artist", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Artist", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Episode", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Episode", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Season", "Season") + .WithMany("Episodes") + .HasForeignKey("SeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Season"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Image", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Image", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Movie", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Movie", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideo", b => + { + b.HasOne("ErsatzTV.Core.Domain.Artist", "Artist") + .WithMany("MusicVideos") + .HasForeignKey("ArtistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.MusicVideo", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Artist"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.OtherVideo", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.OtherVideo", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Season", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Season", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Show", "Show") + .WithMany("Seasons") + .HasForeignKey("ShowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Show"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Show", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Show", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Song", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Song", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyMediaSource", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaSource", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.EmbyMediaSource", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinMediaSource", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaSource", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.JellyfinMediaSource", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LocalMediaSource", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaSource", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.LocalMediaSource", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMediaSource", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaSource", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexMediaSource", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemDuration", b => + { + b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.ProgramScheduleItemDuration", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemFlood", b => + { + b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.ProgramScheduleItemFlood", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemMultiple", b => + { + b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.ProgramScheduleItemMultiple", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemOne", b => + { + b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.ProgramScheduleItemOne", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyEpisode", b => + { + b.HasOne("ErsatzTV.Core.Domain.Episode", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.EmbyEpisode", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinEpisode", b => + { + b.HasOne("ErsatzTV.Core.Domain.Episode", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.JellyfinEpisode", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexEpisode", b => + { + b.HasOne("ErsatzTV.Core.Domain.Episode", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexEpisode", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyMovie", b => + { + b.HasOne("ErsatzTV.Core.Domain.Movie", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.EmbyMovie", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinMovie", b => + { + b.HasOne("ErsatzTV.Core.Domain.Movie", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.JellyfinMovie", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMovie", b => + { + b.HasOne("ErsatzTV.Core.Domain.Movie", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexMovie", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbySeason", b => + { + b.HasOne("ErsatzTV.Core.Domain.Season", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.EmbySeason", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinSeason", b => + { + b.HasOne("ErsatzTV.Core.Domain.Season", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.JellyfinSeason", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexSeason", b => + { + b.HasOne("ErsatzTV.Core.Domain.Season", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexSeason", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyShow", b => + { + b.HasOne("ErsatzTV.Core.Domain.Show", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.EmbyShow", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinShow", b => + { + b.HasOne("ErsatzTV.Core.Domain.Show", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.JellyfinShow", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexShow", b => + { + b.HasOne("ErsatzTV.Core.Domain.Show", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexShow", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ArtistMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Moods"); + + b.Navigation("Studios"); + + b.Navigation("Styles"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Channel", b => + { + b.Navigation("Artwork"); + + b.Navigation("Playouts"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Collection", b => + { + b.Navigation("CollectionItems"); + + b.Navigation("MultiCollectionItems"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EpisodeMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Directors"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + + b.Navigation("Writers"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ImageMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Library", b => + { + b.Navigation("Paths"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LibraryFolder", b => + { + b.Navigation("Children"); + + b.Navigation("ImageFolderDuration"); + + b.Navigation("MediaFiles"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LibraryPath", b => + { + b.Navigation("LibraryFolders"); + + b.Navigation("MediaItems"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaItem", b => + { + b.Navigation("CollectionItems"); + + b.Navigation("TraktListItems"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaSource", b => + { + b.Navigation("Libraries"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaVersion", b => + { + b.Navigation("Chapters"); + + b.Navigation("MediaFiles"); + + b.Navigation("Streams"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MovieMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Directors"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + + b.Navigation("Writers"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollection", b => + { + b.Navigation("MultiCollectionItems"); + + b.Navigation("MultiCollectionSmartItems"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artists"); + + b.Navigation("Artwork"); + + b.Navigation("Directors"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.OtherVideoMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Directors"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + + b.Navigation("Writers"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Playout", b => + { + b.Navigation("FillGroupIndices"); + + b.Navigation("Items"); + + b.Navigation("PlayoutHistory"); + + b.Navigation("ProgramScheduleAlternates"); + + b.Navigation("ProgramScheduleAnchors"); + + b.Navigation("Templates"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramSchedule", b => + { + b.Navigation("Items"); + + b.Navigation("Playouts"); + + b.Navigation("ProgramScheduleAlternates"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Block", b => + { + b.Navigation("Items"); + + b.Navigation("PlayoutHistory"); + + b.Navigation("TemplateItems"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.BlockGroup", b => + { + b.Navigation("Blocks"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Template", b => + { + b.Navigation("Items"); + + b.Navigation("PlayoutTemplates"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.TemplateGroup", b => + { + b.Navigation("Templates"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SeasonMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ShowMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SmartCollection", b => + { + b.Navigation("MultiCollectionSmartItems"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SongMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktListItem", b => + { + b.Navigation("Guids"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyLibrary", b => + { + b.Navigation("PathInfos"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinLibrary", b => + { + b.Navigation("PathInfos"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Artist", b => + { + b.Navigation("ArtistMetadata"); + + b.Navigation("MusicVideos"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Episode", b => + { + b.Navigation("EpisodeMetadata"); + + b.Navigation("MediaVersions"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Image", b => + { + b.Navigation("ImageMetadata"); + + b.Navigation("MediaVersions"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Movie", b => + { + b.Navigation("MediaVersions"); + + b.Navigation("MovieMetadata"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideo", b => + { + b.Navigation("MediaVersions"); + + b.Navigation("MusicVideoMetadata"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.OtherVideo", b => + { + b.Navigation("MediaVersions"); + + b.Navigation("OtherVideoMetadata"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Season", b => + { + b.Navigation("Episodes"); + + b.Navigation("SeasonMetadata"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Show", b => + { + b.Navigation("Seasons"); + + b.Navigation("ShowMetadata"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Song", b => + { + b.Navigation("MediaVersions"); + + b.Navigation("SongMetadata"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyMediaSource", b => + { + b.Navigation("Connections"); + + b.Navigation("PathReplacements"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinMediaSource", b => + { + b.Navigation("Connections"); + + b.Navigation("PathReplacements"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMediaSource", b => + { + b.Navigation("Connections"); + + b.Navigation("PathReplacements"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ErsatzTV.Infrastructure.MySql/Migrations/20240305161535_Update_BlockUniqueIndex.cs b/ErsatzTV.Infrastructure.MySql/Migrations/20240305161535_Update_BlockUniqueIndex.cs new file mode 100644 index 00000000..f4545915 --- /dev/null +++ b/ErsatzTV.Infrastructure.MySql/Migrations/20240305161535_Update_BlockUniqueIndex.cs @@ -0,0 +1,1308 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ErsatzTV.Infrastructure.MySql.Migrations +{ + /// + public partial class Update_BlockUniqueIndex : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Block_BlockGroupId", + table: "Block"); + + migrationBuilder.DropIndex( + name: "IX_Block_Name", + table: "Block"); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Writer", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "TraktListItemGuid", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "TraktListItem", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "TraktList", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "TemplateItem", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "TemplateGroup", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Template", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Tag", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Subtitle", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Style", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Studio", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "SongMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "SmartCollection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ShowMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "SeasonMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Resolution", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ProgramScheduleItem", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ProgramScheduleAlternate", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ProgramSchedule", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlexPathReplacement", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlexConnection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlexCollection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlayoutTemplate", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlayoutScheduleItemFillGroupIndex", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlayoutProgramScheduleAnchor", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlayoutItem", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlayoutHistory", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Playout", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "OtherVideoMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MusicVideoMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MusicVideoArtist", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MultiCollection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MovieMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Mood", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MetadataGuid", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MediaVersion", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MediaStream", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MediaSource", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MediaItem", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MediaFile", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MediaChapter", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "LibraryPath", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "LibraryFolder", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Library", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "LanguageCode", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "JellyfinPathReplacement", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "JellyfinPathInfo", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "JellyfinConnection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "JellyfinCollection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ImageMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ImageFolderDuration", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Genre", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "FillerPreset", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "FFmpegProfile", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "EpisodeMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "EmbyPathReplacement", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "EmbyPathInfo", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "EmbyConnection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "EmbyCollection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Director", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ConfigElement", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Collection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ChannelWatermark", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Channel", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "BlockItem", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "BlockGroup", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Block", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Artwork", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ArtistMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Actor", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.CreateIndex( + name: "IX_Block_BlockGroupId_Name", + table: "Block", + columns: new[] { "BlockGroupId", "Name" }, + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Block_BlockGroupId_Name", + table: "Block"); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Writer", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "TraktListItemGuid", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "TraktListItem", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "TraktList", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "TemplateItem", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "TemplateGroup", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Template", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Tag", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Subtitle", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Style", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Studio", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "SongMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "SmartCollection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ShowMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "SeasonMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Resolution", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ProgramScheduleItem", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ProgramScheduleAlternate", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ProgramSchedule", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlexPathReplacement", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlexConnection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlexCollection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlayoutTemplate", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlayoutScheduleItemFillGroupIndex", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlayoutProgramScheduleAnchor", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlayoutItem", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "PlayoutHistory", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Playout", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "OtherVideoMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MusicVideoMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MusicVideoArtist", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MultiCollection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MovieMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Mood", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MetadataGuid", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MediaVersion", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MediaStream", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MediaSource", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MediaItem", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MediaFile", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "MediaChapter", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "LibraryPath", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "LibraryFolder", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Library", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "LanguageCode", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "JellyfinPathReplacement", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "JellyfinPathInfo", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "JellyfinConnection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "JellyfinCollection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ImageMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ImageFolderDuration", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Genre", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "FillerPreset", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "FFmpegProfile", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "EpisodeMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "EmbyPathReplacement", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "EmbyPathInfo", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "EmbyConnection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "EmbyCollection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Director", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ConfigElement", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Collection", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ChannelWatermark", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Channel", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "BlockItem", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "BlockGroup", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Block", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Artwork", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "ArtistMetadata", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Actor", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.CreateIndex( + name: "IX_Block_BlockGroupId", + table: "Block", + column: "BlockGroupId"); + + migrationBuilder.CreateIndex( + name: "IX_Block_Name", + table: "Block", + column: "Name", + unique: true); + } + } +} diff --git a/ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs b/ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs index 003eb3c5..ebae8d14 100644 --- a/ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs +++ b/ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs @@ -3,6 +3,7 @@ using System; using ErsatzTV.Infrastructure.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; #nullable disable @@ -16,15 +17,19 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.1") + .HasAnnotation("ProductVersion", "8.0.2") .HasAnnotation("Relational:MaxIdentifierLength", 64); + MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + modelBuilder.Entity("ErsatzTV.Core.Domain.Actor", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ArtistMetadataId") .HasColumnType("int"); @@ -96,6 +101,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ArtistId") .HasColumnType("int"); @@ -145,6 +152,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ArtistMetadataId") .HasColumnType("int"); @@ -230,6 +239,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Categories") .HasColumnType("longtext"); @@ -298,6 +309,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("DurationSeconds") .HasColumnType("int"); @@ -348,6 +361,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Name") .HasColumnType("longtext"); @@ -383,6 +398,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Key") .HasColumnType("varchar(255)"); @@ -403,6 +420,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("EpisodeMetadataId") .HasColumnType("int"); @@ -437,6 +456,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Etag") .HasColumnType("longtext"); @@ -457,6 +478,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Address") .HasColumnType("longtext"); @@ -476,6 +499,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("EmbyMediaSourceId") .HasColumnType("int"); @@ -498,6 +523,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("DateAdded") .HasColumnType("datetime(6)"); @@ -550,6 +577,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("AudioBitrate") .HasColumnType("int"); @@ -627,6 +656,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("AllowWatermarks") .HasColumnType("tinyint(1)"); @@ -682,6 +713,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ArtistMetadataId") .HasColumnType("int"); @@ -741,6 +774,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("DurationSeconds") .HasColumnType("double"); @@ -761,6 +796,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("DateAdded") .HasColumnType("datetime(6)"); @@ -804,6 +841,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Etag") .HasColumnType("longtext"); @@ -824,6 +863,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Address") .HasColumnType("longtext"); @@ -843,6 +884,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("JellyfinMediaSourceId") .HasColumnType("int"); @@ -865,6 +908,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("EnglishName") .HasColumnType("longtext"); @@ -891,6 +936,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("LastScan") .HasColumnType("datetime(6)"); @@ -918,6 +965,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Etag") .HasColumnType("longtext"); @@ -945,6 +994,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("LastScan") .HasColumnType("datetime(6)"); @@ -967,6 +1018,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ChapterId") .HasColumnType("bigint"); @@ -995,6 +1048,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("LibraryFolderId") .HasColumnType("int"); @@ -1024,6 +1079,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("LibraryPathId") .HasColumnType("int"); @@ -1045,6 +1102,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.HasKey("Id"); b.ToTable("MediaSource", (string)null); @@ -1058,6 +1117,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("AttachedPic") .HasColumnType("tinyint(1)"); @@ -1128,6 +1189,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("DateAdded") .HasColumnType("datetime(6)"); @@ -1199,6 +1262,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ArtistMetadataId") .HasColumnType("int"); @@ -1258,6 +1323,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ArtistMetadataId") .HasColumnType("int"); @@ -1277,6 +1344,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ContentRating") .HasColumnType("longtext"); @@ -1329,6 +1398,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Name") .HasColumnType("longtext"); @@ -1385,6 +1456,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("MusicVideoMetadataId") .HasColumnType("int"); @@ -1404,6 +1477,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Album") .HasColumnType("longtext"); @@ -1453,6 +1528,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ContentRating") .HasColumnType("longtext"); @@ -1505,6 +1582,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ChannelId") .HasColumnType("int"); @@ -1538,6 +1617,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("BlockKey") .HasColumnType("longtext"); @@ -1618,6 +1699,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("AnchorDate") .HasColumnType("datetime(6)"); @@ -1663,6 +1746,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("PlayoutId") .HasColumnType("int"); @@ -1684,6 +1769,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Etag") .HasColumnType("longtext"); @@ -1704,6 +1791,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("IsActive") .HasColumnType("tinyint(1)"); @@ -1726,6 +1815,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("LocalPath") .HasColumnType("longtext"); @@ -1748,6 +1839,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("KeepMultiPartEpisodesTogether") .HasColumnType("tinyint(1)"); @@ -1777,6 +1870,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("DaysOfMonth") .HasColumnType("longtext"); @@ -1810,6 +1905,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("CollectionId") .HasColumnType("int"); @@ -1914,6 +2011,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Height") .HasColumnType("int"); @@ -1939,6 +2038,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("BlockGroupId") .HasColumnType("int"); @@ -1956,9 +2057,7 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations b.HasKey("Id"); - b.HasIndex("BlockGroupId"); - - b.HasIndex("Name") + b.HasIndex("BlockGroupId", "Name") .IsUnique(); b.ToTable("Block", (string)null); @@ -1970,6 +2069,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Name") .HasColumnType("varchar(255)"); @@ -1987,6 +2088,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("BlockId") .HasColumnType("int"); @@ -2035,6 +2138,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("BlockId") .HasColumnType("int"); @@ -2071,6 +2176,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("DateUpdated") .HasColumnType("datetime(6)"); @@ -2113,6 +2220,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("DateUpdated") .HasColumnType("datetime(6)"); @@ -2138,6 +2247,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Name") .HasColumnType("varchar(255)"); @@ -2155,6 +2266,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("BlockId") .HasColumnType("int"); @@ -2179,6 +2292,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("DateAdded") .HasColumnType("datetime(6)"); @@ -2222,6 +2337,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ContentRating") .HasColumnType("longtext"); @@ -2274,6 +2391,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Name") .HasColumnType("longtext"); @@ -2291,6 +2410,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Album") .HasColumnType("longtext"); @@ -2346,6 +2467,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ArtistMetadataId") .HasColumnType("int"); @@ -2405,6 +2528,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ArtistMetadataId") .HasColumnType("int"); @@ -2424,6 +2549,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ArtistMetadataId") .HasColumnType("int"); @@ -2520,6 +2647,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("ArtistMetadataId") .HasColumnType("int"); @@ -2582,6 +2711,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Description") .HasColumnType("longtext"); @@ -2611,6 +2742,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Episode") .HasColumnType("int"); @@ -2653,6 +2786,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("Guid") .HasColumnType("longtext"); @@ -2672,6 +2807,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("EpisodeMetadataId") .HasColumnType("int"); @@ -2701,6 +2838,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("EmbyLibraryId") .HasColumnType("int"); @@ -2723,6 +2862,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + b.Property("JellyfinLibraryId") .HasColumnType("int"); diff --git a/ErsatzTV.Infrastructure.Sqlite/ErsatzTV.Infrastructure.Sqlite.csproj b/ErsatzTV.Infrastructure.Sqlite/ErsatzTV.Infrastructure.Sqlite.csproj index 1565c921..ae69863c 100644 --- a/ErsatzTV.Infrastructure.Sqlite/ErsatzTV.Infrastructure.Sqlite.csproj +++ b/ErsatzTV.Infrastructure.Sqlite/ErsatzTV.Infrastructure.Sqlite.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/ErsatzTV.Infrastructure.Sqlite/Migrations/20240305094323_Update_BlockUniqueIndex.Designer.cs b/ErsatzTV.Infrastructure.Sqlite/Migrations/20240305094323_Update_BlockUniqueIndex.Designer.cs new file mode 100644 index 00000000..ac083bc9 --- /dev/null +++ b/ErsatzTV.Infrastructure.Sqlite/Migrations/20240305094323_Update_BlockUniqueIndex.Designer.cs @@ -0,0 +1,5164 @@ +// +using System; +using ErsatzTV.Infrastructure.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace ErsatzTV.Infrastructure.Sqlite.Migrations +{ + [DbContext(typeof(TvContext))] + [Migration("20240305094323_Update_BlockUniqueIndex")] + partial class Update_BlockUniqueIndex + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.2"); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Actor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArtistMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ArtworkId") + .HasColumnType("INTEGER"); + + b.Property("EpisodeMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ImageMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MovieMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("TEXT"); + + b.Property("SeasonMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ShowMetadataId") + .HasColumnType("INTEGER"); + + b.Property("SongMetadataId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("ArtworkId") + .IsUnique(); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("Actor", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ArtistMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArtistId") + .HasColumnType("INTEGER"); + + b.Property("Biography") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("Disambiguation") + .HasColumnType("TEXT"); + + b.Property("Formed") + .HasColumnType("TEXT"); + + b.Property("MetadataKind") + .HasColumnType("INTEGER"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("SortTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Year") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ArtistId"); + + b.ToTable("ArtistMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Artwork", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArtistMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ArtworkKind") + .HasColumnType("INTEGER"); + + b.Property("BlurHash43") + .HasColumnType("TEXT"); + + b.Property("BlurHash54") + .HasColumnType("TEXT"); + + b.Property("BlurHash64") + .HasColumnType("TEXT"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("EpisodeMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ImageMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MovieMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("SeasonMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ShowMetadataId") + .HasColumnType("INTEGER"); + + b.Property("SongMetadataId") + .HasColumnType("INTEGER"); + + b.Property("SourcePath") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("ChannelId"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("Artwork", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Channel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Categories") + .HasColumnType("TEXT"); + + b.Property("FFmpegProfileId") + .HasColumnType("INTEGER"); + + b.Property("FallbackFillerId") + .HasColumnType("INTEGER"); + + b.Property("Group") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("ErsatzTV"); + + b.Property("MusicVideoCreditsMode") + .HasColumnType("INTEGER"); + + b.Property("MusicVideoCreditsTemplate") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("PreferredAudioLanguageCode") + .HasColumnType("TEXT"); + + b.Property("PreferredAudioTitle") + .HasColumnType("TEXT"); + + b.Property("PreferredSubtitleLanguageCode") + .HasColumnType("TEXT"); + + b.Property("StreamingMode") + .HasColumnType("INTEGER"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("UniqueId") + .HasColumnType("TEXT"); + + b.Property("WatermarkId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("FFmpegProfileId"); + + b.HasIndex("FallbackFillerId"); + + b.HasIndex("Number") + .IsUnique(); + + b.HasIndex("WatermarkId"); + + b.ToTable("Channel", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ChannelWatermark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DurationSeconds") + .HasColumnType("INTEGER"); + + b.Property("FrequencyMinutes") + .HasColumnType("INTEGER"); + + b.Property("HorizontalMarginPercent") + .HasColumnType("INTEGER"); + + b.Property("Image") + .HasColumnType("TEXT"); + + b.Property("ImageSource") + .HasColumnType("INTEGER"); + + b.Property("Location") + .HasColumnType("INTEGER"); + + b.Property("Mode") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Opacity") + .HasColumnType("INTEGER"); + + b.Property("PlaceWithinSourceContent") + .HasColumnType("INTEGER"); + + b.Property("Size") + .HasColumnType("INTEGER"); + + b.Property("VerticalMarginPercent") + .HasColumnType("INTEGER"); + + b.Property("WidthPercent") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("ChannelWatermark", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Collection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("UseCustomPlaybackOrder") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.CollectionItem", b => + { + b.Property("CollectionId") + .HasColumnType("INTEGER"); + + b.Property("MediaItemId") + .HasColumnType("INTEGER"); + + b.Property("CustomIndex") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionId", "MediaItemId"); + + b.HasIndex("MediaItemId"); + + b.ToTable("CollectionItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ConfigElement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.ToTable("ConfigElement", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Director", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EpisodeMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MovieMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.ToTable("Director", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("EmbyCollection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Address") + .HasColumnType("TEXT"); + + b.Property("EmbyMediaSourceId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("EmbyMediaSourceId"); + + b.ToTable("EmbyConnection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyPathReplacement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EmbyMediaSourceId") + .HasColumnType("INTEGER"); + + b.Property("EmbyPath") + .HasColumnType("TEXT"); + + b.Property("LocalPath") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("EmbyMediaSourceId"); + + b.ToTable("EmbyPathReplacement", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EpisodeMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("EpisodeId") + .HasColumnType("INTEGER"); + + b.Property("EpisodeNumber") + .HasColumnType("INTEGER"); + + b.Property("MetadataKind") + .HasColumnType("INTEGER"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Outline") + .HasColumnType("TEXT"); + + b.Property("Plot") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("SortTitle") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Year") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("EpisodeId"); + + b.ToTable("EpisodeMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.FFmpegProfile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AudioBitrate") + .HasColumnType("INTEGER"); + + b.Property("AudioBufferSize") + .HasColumnType("INTEGER"); + + b.Property("AudioChannels") + .HasColumnType("INTEGER"); + + b.Property("AudioFormat") + .HasColumnType("INTEGER"); + + b.Property("AudioSampleRate") + .HasColumnType("INTEGER"); + + b.Property("BitDepth") + .HasColumnType("INTEGER"); + + b.Property("DeinterlaceVideo") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("HardwareAcceleration") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizeFramerate") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(false); + + b.Property("NormalizeLoudnessMode") + .HasColumnType("INTEGER"); + + b.Property("QsvExtraHardwareFrames") + .HasColumnType("INTEGER"); + + b.Property("ResolutionId") + .HasColumnType("INTEGER"); + + b.Property("ScalingBehavior") + .HasColumnType("INTEGER"); + + b.Property("ThreadCount") + .HasColumnType("INTEGER"); + + b.Property("VaapiDevice") + .HasColumnType("TEXT"); + + b.Property("VaapiDriver") + .HasColumnType("INTEGER"); + + b.Property("VideoBitrate") + .HasColumnType("INTEGER"); + + b.Property("VideoBufferSize") + .HasColumnType("INTEGER"); + + b.Property("VideoFormat") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ResolutionId"); + + b.ToTable("FFmpegProfile", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Filler.FillerPreset", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AllowWatermarks") + .HasColumnType("INTEGER"); + + b.Property("CollectionId") + .HasColumnType("INTEGER"); + + b.Property("CollectionType") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("Duration") + .HasColumnType("TEXT"); + + b.Property("FillerKind") + .HasColumnType("INTEGER"); + + b.Property("FillerMode") + .HasColumnType("INTEGER"); + + b.Property("MediaItemId") + .HasColumnType("INTEGER"); + + b.Property("MultiCollectionId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("PadToNearestMinute") + .HasColumnType("INTEGER"); + + b.Property("SmartCollectionId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("CollectionId"); + + b.HasIndex("MediaItemId"); + + b.HasIndex("MultiCollectionId"); + + b.HasIndex("SmartCollectionId"); + + b.ToTable("FillerPreset", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArtistMetadataId") + .HasColumnType("INTEGER"); + + b.Property("EpisodeMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ImageMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MovieMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("SeasonMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ShowMetadataId") + .HasColumnType("INTEGER"); + + b.Property("SongMetadataId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ImageFolderDuration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DurationSeconds") + .HasColumnType("REAL"); + + b.Property("LibraryFolderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("LibraryFolderId") + .IsUnique(); + + b.ToTable("ImageFolderDuration", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ImageMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("DurationSeconds") + .HasColumnType("REAL"); + + b.Property("ImageId") + .HasColumnType("INTEGER"); + + b.Property("MetadataKind") + .HasColumnType("INTEGER"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("SortTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Year") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("ImageMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("JellyfinCollection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Address") + .HasColumnType("TEXT"); + + b.Property("JellyfinMediaSourceId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("JellyfinMediaSourceId"); + + b.ToTable("JellyfinConnection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinPathReplacement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("JellyfinMediaSourceId") + .HasColumnType("INTEGER"); + + b.Property("JellyfinPath") + .HasColumnType("TEXT"); + + b.Property("LocalPath") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("JellyfinMediaSourceId"); + + b.ToTable("JellyfinPathReplacement", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LanguageCode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EnglishName") + .HasColumnType("TEXT"); + + b.Property("FrenchName") + .HasColumnType("TEXT"); + + b.Property("ThreeCode1") + .HasColumnType("TEXT"); + + b.Property("ThreeCode2") + .HasColumnType("TEXT"); + + b.Property("TwoCode") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("LanguageCode", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScan") + .HasColumnType("TEXT"); + + b.Property("MediaKind") + .HasColumnType("INTEGER"); + + b.Property("MediaSourceId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MediaSourceId"); + + b.ToTable("Library", (string)null); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LibraryFolder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("LibraryPathId") + .HasColumnType("INTEGER"); + + b.Property("ParentId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryPathId"); + + b.HasIndex("ParentId"); + + b.ToTable("LibraryFolder", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LibraryPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScan") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("LibraryPath", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaChapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("EndTime") + .HasColumnType("TEXT"); + + b.Property("MediaVersionId") + .HasColumnType("INTEGER"); + + b.Property("StartTime") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MediaVersionId"); + + b.ToTable("MediaChapter", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LibraryFolderId") + .HasColumnType("INTEGER"); + + b.Property("MediaVersionId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryFolderId"); + + b.HasIndex("MediaVersionId"); + + b.HasIndex("Path") + .IsUnique(); + + b.ToTable("MediaFile", (string)null); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LibraryPathId") + .HasColumnType("INTEGER"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("LibraryPathId"); + + b.ToTable("MediaItem", (string)null); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaSource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSource", (string)null); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AttachedPic") + .HasColumnType("INTEGER"); + + b.Property("BitsPerRawSample") + .HasColumnType("INTEGER"); + + b.Property("Channels") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("ColorPrimaries") + .HasColumnType("TEXT"); + + b.Property("ColorRange") + .HasColumnType("TEXT"); + + b.Property("ColorSpace") + .HasColumnType("TEXT"); + + b.Property("ColorTransfer") + .HasColumnType("TEXT"); + + b.Property("Default") + .HasColumnType("INTEGER"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("Forced") + .HasColumnType("INTEGER"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("MediaStreamKind") + .HasColumnType("INTEGER"); + + b.Property("MediaVersionId") + .HasColumnType("INTEGER"); + + b.Property("MimeType") + .HasColumnType("TEXT"); + + b.Property("PixelFormat") + .HasColumnType("TEXT"); + + b.Property("Profile") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MediaVersionId"); + + b.ToTable("MediaStream", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("DisplayAspectRatio") + .HasColumnType("TEXT"); + + b.Property("Duration") + .HasColumnType("TEXT"); + + b.Property("EpisodeId") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("ImageId") + .HasColumnType("INTEGER"); + + b.Property("MovieId") + .HasColumnType("INTEGER"); + + b.Property("MusicVideoId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OtherVideoId") + .HasColumnType("INTEGER"); + + b.Property("RFrameRate") + .HasColumnType("TEXT"); + + b.Property("SampleAspectRatio") + .HasColumnType("TEXT"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("VideoScanKind") + .HasColumnType("INTEGER"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("EpisodeId"); + + b.HasIndex("ImageId"); + + b.HasIndex("MovieId"); + + b.HasIndex("MusicVideoId"); + + b.HasIndex("OtherVideoId"); + + b.HasIndex("SongId"); + + b.ToTable("MediaVersion", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MetadataGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArtistMetadataId") + .HasColumnType("INTEGER"); + + b.Property("EpisodeMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Guid") + .HasColumnType("TEXT"); + + b.Property("ImageMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MovieMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("SeasonMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ShowMetadataId") + .HasColumnType("INTEGER"); + + b.Property("SongMetadataId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("MetadataGuid", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Mood", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArtistMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.ToTable("Mood"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MovieMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ContentRating") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("MetadataKind") + .HasColumnType("INTEGER"); + + b.Property("MovieId") + .HasColumnType("INTEGER"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Outline") + .HasColumnType("TEXT"); + + b.Property("Plot") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("SortTitle") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Year") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("MovieId"); + + b.ToTable("MovieMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("MultiCollection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollectionItem", b => + { + b.Property("MultiCollectionId") + .HasColumnType("INTEGER"); + + b.Property("CollectionId") + .HasColumnType("INTEGER"); + + b.Property("PlaybackOrder") + .HasColumnType("INTEGER"); + + b.Property("ScheduleAsGroup") + .HasColumnType("INTEGER"); + + b.HasKey("MultiCollectionId", "CollectionId"); + + b.HasIndex("CollectionId"); + + b.ToTable("MultiCollectionItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollectionSmartItem", b => + { + b.Property("MultiCollectionId") + .HasColumnType("INTEGER"); + + b.Property("SmartCollectionId") + .HasColumnType("INTEGER"); + + b.Property("PlaybackOrder") + .HasColumnType("INTEGER"); + + b.Property("ScheduleAsGroup") + .HasColumnType("INTEGER"); + + b.HasKey("MultiCollectionId", "SmartCollectionId"); + + b.HasIndex("SmartCollectionId"); + + b.ToTable("MultiCollectionSmartItem"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoArtist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MusicVideoMetadataId"); + + b.ToTable("MusicVideoArtist"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Album") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("MetadataKind") + .HasColumnType("INTEGER"); + + b.Property("MusicVideoId") + .HasColumnType("INTEGER"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Plot") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("SortTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Track") + .HasColumnType("INTEGER"); + + b.Property("Year") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("MusicVideoId"); + + b.ToTable("MusicVideoMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.OtherVideoMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ContentRating") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("MetadataKind") + .HasColumnType("INTEGER"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("OtherVideoId") + .HasColumnType("INTEGER"); + + b.Property("Outline") + .HasColumnType("TEXT"); + + b.Property("Plot") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("SortTitle") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Year") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("OtherVideoId"); + + b.ToTable("OtherVideoMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Playout", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DailyRebuildTime") + .HasColumnType("TEXT"); + + b.Property("ExternalJsonFile") + .HasColumnType("TEXT"); + + b.Property("ProgramScheduleId") + .HasColumnType("INTEGER"); + + b.Property("ProgramSchedulePlayoutType") + .HasColumnType("INTEGER"); + + b.Property("Seed") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChannelId"); + + b.HasIndex("ProgramScheduleId"); + + b.ToTable("Playout", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlayoutItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BlockKey") + .HasColumnType("TEXT"); + + b.Property("ChapterTitle") + .HasColumnType("TEXT"); + + b.Property("CollectionEtag") + .HasColumnType("TEXT"); + + b.Property("CollectionKey") + .HasColumnType("TEXT"); + + b.Property("CustomTitle") + .HasColumnType("TEXT"); + + b.Property("DisableWatermarks") + .HasColumnType("INTEGER"); + + b.Property("FillerKind") + .HasColumnType("INTEGER"); + + b.Property("Finish") + .HasColumnType("TEXT"); + + b.Property("GuideFinish") + .HasColumnType("TEXT"); + + b.Property("GuideGroup") + .HasColumnType("INTEGER"); + + b.Property("GuideStart") + .HasColumnType("TEXT"); + + b.Property("InPoint") + .HasColumnType("TEXT"); + + b.Property("MediaItemId") + .HasColumnType("INTEGER"); + + b.Property("OutPoint") + .HasColumnType("TEXT"); + + b.Property("PlayoutId") + .HasColumnType("INTEGER"); + + b.Property("PreferredAudioLanguageCode") + .HasColumnType("TEXT"); + + b.Property("PreferredAudioTitle") + .HasColumnType("TEXT"); + + b.Property("PreferredSubtitleLanguageCode") + .HasColumnType("TEXT"); + + b.Property("Start") + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("WatermarkId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("MediaItemId"); + + b.HasIndex("PlayoutId"); + + b.HasIndex("WatermarkId"); + + b.ToTable("PlayoutItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlayoutProgramScheduleAnchor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AnchorDate") + .HasColumnType("TEXT"); + + b.Property("CollectionId") + .HasColumnType("INTEGER"); + + b.Property("CollectionType") + .HasColumnType("INTEGER"); + + b.Property("FakeCollectionKey") + .HasColumnType("TEXT"); + + b.Property("MediaItemId") + .HasColumnType("INTEGER"); + + b.Property("MultiCollectionId") + .HasColumnType("INTEGER"); + + b.Property("PlayoutId") + .HasColumnType("INTEGER"); + + b.Property("SmartCollectionId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("CollectionId"); + + b.HasIndex("MediaItemId"); + + b.HasIndex("MultiCollectionId"); + + b.HasIndex("PlayoutId"); + + b.HasIndex("SmartCollectionId"); + + b.ToTable("PlayoutProgramScheduleAnchor", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlayoutScheduleItemFillGroupIndex", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("PlayoutId") + .HasColumnType("INTEGER"); + + b.Property("ProgramScheduleItemId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("PlayoutId"); + + b.HasIndex("ProgramScheduleItemId"); + + b.ToTable("PlayoutScheduleItemFillGroupIndex", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("PlexCollection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("PlexMediaSourceId") + .HasColumnType("INTEGER"); + + b.Property("Uri") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("PlexMediaSourceId"); + + b.ToTable("PlexConnection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexPathReplacement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LocalPath") + .HasColumnType("TEXT"); + + b.Property("PlexMediaSourceId") + .HasColumnType("INTEGER"); + + b.Property("PlexPath") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("PlexMediaSourceId"); + + b.ToTable("PlexPathReplacement", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("KeepMultiPartEpisodesTogether") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("RandomStartPoint") + .HasColumnType("INTEGER"); + + b.Property("ShuffleScheduleItems") + .HasColumnType("INTEGER"); + + b.Property("TreatCollectionsAsShows") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("ProgramSchedule", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleAlternate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DaysOfMonth") + .HasColumnType("TEXT"); + + b.Property("DaysOfWeek") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("MonthsOfYear") + .HasColumnType("TEXT"); + + b.Property("PlayoutId") + .HasColumnType("INTEGER"); + + b.Property("ProgramScheduleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("PlayoutId"); + + b.HasIndex("ProgramScheduleId"); + + b.ToTable("ProgramScheduleAlternate", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CollectionId") + .HasColumnType("INTEGER"); + + b.Property("CollectionType") + .HasColumnType("INTEGER"); + + b.Property("CustomTitle") + .HasColumnType("TEXT"); + + b.Property("FakeCollectionKey") + .HasColumnType("TEXT"); + + b.Property("FallbackFillerId") + .HasColumnType("INTEGER"); + + b.Property("FillWithGroupMode") + .HasColumnType("INTEGER"); + + b.Property("GuideMode") + .HasColumnType("INTEGER"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("MediaItemId") + .HasColumnType("INTEGER"); + + b.Property("MidRollFillerId") + .HasColumnType("INTEGER"); + + b.Property("MultiCollectionId") + .HasColumnType("INTEGER"); + + b.Property("PlaybackOrder") + .HasColumnType("INTEGER"); + + b.Property("PostRollFillerId") + .HasColumnType("INTEGER"); + + b.Property("PreRollFillerId") + .HasColumnType("INTEGER"); + + b.Property("PreferredAudioLanguageCode") + .HasColumnType("TEXT"); + + b.Property("PreferredAudioTitle") + .HasColumnType("TEXT"); + + b.Property("PreferredSubtitleLanguageCode") + .HasColumnType("TEXT"); + + b.Property("ProgramScheduleId") + .HasColumnType("INTEGER"); + + b.Property("SmartCollectionId") + .HasColumnType("INTEGER"); + + b.Property("StartTime") + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("TailFillerId") + .HasColumnType("INTEGER"); + + b.Property("WatermarkId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("CollectionId"); + + b.HasIndex("FallbackFillerId"); + + b.HasIndex("MediaItemId"); + + b.HasIndex("MidRollFillerId"); + + b.HasIndex("MultiCollectionId"); + + b.HasIndex("PostRollFillerId"); + + b.HasIndex("PreRollFillerId"); + + b.HasIndex("ProgramScheduleId"); + + b.HasIndex("SmartCollectionId"); + + b.HasIndex("TailFillerId"); + + b.HasIndex("WatermarkId"); + + b.ToTable("ProgramScheduleItem", (string)null); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Resolution", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IsCustom") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(false); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Resolution", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Block", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BlockGroupId") + .HasColumnType("INTEGER"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("Minutes") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("StopScheduling") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("BlockGroupId", "Name") + .IsUnique(); + + b.ToTable("Block", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.BlockGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("BlockGroup", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.BlockItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BlockId") + .HasColumnType("INTEGER"); + + b.Property("CollectionId") + .HasColumnType("INTEGER"); + + b.Property("CollectionType") + .HasColumnType("INTEGER"); + + b.Property("IncludeInProgramGuide") + .HasColumnType("INTEGER"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("MediaItemId") + .HasColumnType("INTEGER"); + + b.Property("MultiCollectionId") + .HasColumnType("INTEGER"); + + b.Property("PlaybackOrder") + .HasColumnType("INTEGER"); + + b.Property("SmartCollectionId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("BlockId"); + + b.HasIndex("CollectionId"); + + b.HasIndex("MediaItemId"); + + b.HasIndex("MultiCollectionId"); + + b.HasIndex("SmartCollectionId"); + + b.ToTable("BlockItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.PlayoutHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BlockId") + .HasColumnType("INTEGER"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("PlaybackOrder") + .HasColumnType("INTEGER"); + + b.Property("PlayoutId") + .HasColumnType("INTEGER"); + + b.Property("When") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("BlockId"); + + b.HasIndex("PlayoutId"); + + b.ToTable("PlayoutHistory", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.PlayoutTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("DaysOfMonth") + .HasColumnType("TEXT"); + + b.Property("DaysOfWeek") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("MonthsOfYear") + .HasColumnType("TEXT"); + + b.Property("PlayoutId") + .HasColumnType("INTEGER"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("TemplateId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("PlayoutId"); + + b.HasIndex("TemplateId"); + + b.ToTable("PlayoutTemplate", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Template", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("TemplateGroupId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("TemplateGroupId"); + + b.ToTable("Template", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.TemplateGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("TemplateGroup", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.TemplateItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BlockId") + .HasColumnType("INTEGER"); + + b.Property("StartTime") + .HasColumnType("TEXT"); + + b.Property("TemplateId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("BlockId"); + + b.HasIndex("TemplateId"); + + b.ToTable("TemplateItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SeasonMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("MetadataKind") + .HasColumnType("INTEGER"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Outline") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("SeasonId") + .HasColumnType("INTEGER"); + + b.Property("SortTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Year") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeasonId"); + + b.ToTable("SeasonMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ShowMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ContentRating") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("MetadataKind") + .HasColumnType("INTEGER"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Outline") + .HasColumnType("TEXT"); + + b.Property("Plot") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("ShowId") + .HasColumnType("INTEGER"); + + b.Property("SortTitle") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Year") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ShowId"); + + b.ToTable("ShowMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SmartCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Query") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SmartCollection", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SongMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Album") + .HasColumnType("TEXT"); + + b.Property("AlbumArtists") + .HasColumnType("TEXT"); + + b.Property("Artists") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("MetadataKind") + .HasColumnType("INTEGER"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("SortTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Track") + .HasColumnType("TEXT"); + + b.Property("Year") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SongId"); + + b.ToTable("SongMetadata", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Studio", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArtistMetadataId") + .HasColumnType("INTEGER"); + + b.Property("EpisodeMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ImageMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MovieMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("SeasonMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ShowMetadataId") + .HasColumnType("INTEGER"); + + b.Property("SongMetadataId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("Studio", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Style", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArtistMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.ToTable("Style"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Subtitle", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArtistMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DateUpdated") + .HasColumnType("TEXT"); + + b.Property("Default") + .HasColumnType("INTEGER"); + + b.Property("EpisodeMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Forced") + .HasColumnType("INTEGER"); + + b.Property("ImageMetadataId") + .HasColumnType("INTEGER"); + + b.Property("IsExtracted") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(false); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("MovieMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("SDH") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(false); + + b.Property("SeasonMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ShowMetadataId") + .HasColumnType("INTEGER"); + + b.Property("SongMetadataId") + .HasColumnType("INTEGER"); + + b.Property("StreamIndex") + .HasColumnType("INTEGER"); + + b.Property("SubtitleKind") + .HasColumnType("INTEGER"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("Subtitle", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArtistMetadataId") + .HasColumnType("INTEGER"); + + b.Property("EpisodeMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ExternalCollectionId") + .HasColumnType("TEXT"); + + b.Property("ImageMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MovieMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MusicVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("INTEGER"); + + b.Property("SeasonMetadataId") + .HasColumnType("INTEGER"); + + b.Property("ShowMetadataId") + .HasColumnType("INTEGER"); + + b.Property("SongMetadataId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ArtistMetadataId"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("ImageMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("MusicVideoMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.HasIndex("SeasonMetadataId"); + + b.HasIndex("ShowMetadataId"); + + b.HasIndex("SongMetadataId"); + + b.ToTable("Tag"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("ItemCount") + .HasColumnType("INTEGER"); + + b.Property("List") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("TraktId") + .HasColumnType("INTEGER"); + + b.Property("User") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("TraktList", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Episode") + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("MediaItemId") + .HasColumnType("INTEGER"); + + b.Property("Rank") + .HasColumnType("INTEGER"); + + b.Property("Season") + .HasColumnType("INTEGER"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TraktId") + .HasColumnType("INTEGER"); + + b.Property("TraktListId") + .HasColumnType("INTEGER"); + + b.Property("Year") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("MediaItemId"); + + b.HasIndex("TraktListId"); + + b.ToTable("TraktListItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktListItemGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Guid") + .HasColumnType("TEXT"); + + b.Property("TraktListItemId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("TraktListItemId"); + + b.ToTable("TraktListItemGuid", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Writer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EpisodeMetadataId") + .HasColumnType("INTEGER"); + + b.Property("MovieMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OtherVideoMetadataId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("EpisodeMetadataId"); + + b.HasIndex("MovieMetadataId"); + + b.HasIndex("OtherVideoMetadataId"); + + b.ToTable("Writer", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Emby.EmbyPathInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EmbyLibraryId") + .HasColumnType("INTEGER"); + + b.Property("NetworkPath") + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("EmbyLibraryId"); + + b.ToTable("EmbyPathInfo"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Jellyfin.JellyfinPathInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("JellyfinLibraryId") + .HasColumnType("INTEGER"); + + b.Property("NetworkPath") + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("JellyfinLibraryId"); + + b.ToTable("JellyfinPathInfo"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyLibrary", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Library"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ShouldSyncItems") + .HasColumnType("INTEGER"); + + b.ToTable("EmbyLibrary", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinLibrary", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Library"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ShouldSyncItems") + .HasColumnType("INTEGER"); + + b.ToTable("JellyfinLibrary", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LocalLibrary", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Library"); + + b.ToTable("LocalLibrary", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexLibrary", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Library"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("ShouldSyncItems") + .HasColumnType("INTEGER"); + + b.ToTable("PlexLibrary", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMediaFile", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaFile"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("PlexId") + .HasColumnType("INTEGER"); + + b.ToTable("PlexMediaFile", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Artist", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.ToTable("Artist", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Episode", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.Property("SeasonId") + .HasColumnType("INTEGER"); + + b.HasIndex("SeasonId"); + + b.ToTable("Episode", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Image", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.ToTable("Image", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Movie", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.ToTable("Movie", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideo", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.Property("ArtistId") + .HasColumnType("INTEGER"); + + b.HasIndex("ArtistId"); + + b.ToTable("MusicVideo", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.OtherVideo", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.ToTable("OtherVideo", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Season", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.Property("SeasonNumber") + .HasColumnType("INTEGER"); + + b.Property("ShowId") + .HasColumnType("INTEGER"); + + b.HasIndex("ShowId"); + + b.ToTable("Season", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Show", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.ToTable("Show", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Song", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaItem"); + + b.ToTable("Song", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyMediaSource", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaSource"); + + b.Property("LastCollectionsScan") + .HasColumnType("TEXT"); + + b.Property("OperatingSystem") + .HasColumnType("TEXT"); + + b.Property("ServerName") + .HasColumnType("TEXT"); + + b.ToTable("EmbyMediaSource", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinMediaSource", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaSource"); + + b.Property("LastCollectionsScan") + .HasColumnType("TEXT"); + + b.Property("OperatingSystem") + .HasColumnType("TEXT"); + + b.Property("ServerName") + .HasColumnType("TEXT"); + + b.ToTable("JellyfinMediaSource", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LocalMediaSource", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaSource"); + + b.ToTable("LocalMediaSource", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMediaSource", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.MediaSource"); + + b.Property("ClientIdentifier") + .HasColumnType("TEXT"); + + b.Property("LastCollectionsScan") + .HasColumnType("TEXT"); + + b.Property("Platform") + .HasColumnType("TEXT"); + + b.Property("PlatformVersion") + .HasColumnType("TEXT"); + + b.Property("ProductVersion") + .HasColumnType("TEXT"); + + b.Property("ServerName") + .HasColumnType("TEXT"); + + b.ToTable("PlexMediaSource", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemDuration", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.ProgramScheduleItem"); + + b.Property("DiscardToFillAttempts") + .HasColumnType("INTEGER"); + + b.Property("PlayoutDuration") + .HasColumnType("TEXT"); + + b.Property("TailMode") + .HasColumnType("INTEGER"); + + b.ToTable("ProgramScheduleDurationItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemFlood", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.ProgramScheduleItem"); + + b.ToTable("ProgramScheduleFloodItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemMultiple", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.ProgramScheduleItem"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.ToTable("ProgramScheduleMultipleItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemOne", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.ProgramScheduleItem"); + + b.ToTable("ProgramScheduleOneItem", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyEpisode", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Episode"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.ToTable("EmbyEpisode", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinEpisode", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Episode"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.ToTable("JellyfinEpisode", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexEpisode", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Episode"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.ToTable("PlexEpisode", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyMovie", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Movie"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.ToTable("EmbyMovie", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinMovie", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Movie"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.ToTable("JellyfinMovie", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMovie", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Movie"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.ToTable("PlexMovie", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbySeason", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Season"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.ToTable("EmbySeason", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinSeason", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Season"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.ToTable("JellyfinSeason", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexSeason", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Season"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.ToTable("PlexSeason", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyShow", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Show"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.ToTable("EmbyShow", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinShow", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Show"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.ToTable("JellyfinShow", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexShow", b => + { + b.HasBaseType("ErsatzTV.Core.Domain.Show"); + + b.Property("Etag") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.ToTable("PlexShow", (string)null); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Actor", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Actors") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Artwork", "Artwork") + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Actor", "ArtworkId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Actors") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Actors") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Actors") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Actors") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Actors") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Actors") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Actors") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Actors") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Artwork"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ArtistMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Artist", "Artist") + .WithMany("ArtistMetadata") + .HasForeignKey("ArtistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Artist"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Artwork", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Artwork") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Channel", null) + .WithMany("Artwork") + .HasForeignKey("ChannelId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Artwork") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Artwork") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Artwork") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Artwork") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Artwork") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Artwork") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Artwork") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Artwork") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Channel", b => + { + b.HasOne("ErsatzTV.Core.Domain.FFmpegProfile", "FFmpegProfile") + .WithMany() + .HasForeignKey("FFmpegProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Filler.FillerPreset", "FallbackFiller") + .WithMany() + .HasForeignKey("FallbackFillerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.ChannelWatermark", "Watermark") + .WithMany() + .HasForeignKey("WatermarkId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("FFmpegProfile"); + + b.Navigation("FallbackFiller"); + + b.Navigation("Watermark"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.CollectionItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.Collection", "Collection") + .WithMany("CollectionItems") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany("CollectionItems") + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("MediaItem"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Director", b => + { + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Directors") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Directors") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Directors") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Directors") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyConnection", b => + { + b.HasOne("ErsatzTV.Core.Domain.EmbyMediaSource", "EmbyMediaSource") + .WithMany("Connections") + .HasForeignKey("EmbyMediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EmbyMediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyPathReplacement", b => + { + b.HasOne("ErsatzTV.Core.Domain.EmbyMediaSource", "EmbyMediaSource") + .WithMany("PathReplacements") + .HasForeignKey("EmbyMediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EmbyMediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EpisodeMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Episode", "Episode") + .WithMany("EpisodeMetadata") + .HasForeignKey("EpisodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Episode"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.FFmpegProfile", b => + { + b.HasOne("ErsatzTV.Core.Domain.Resolution", "Resolution") + .WithMany() + .HasForeignKey("ResolutionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Resolution"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Filler.FillerPreset", b => + { + b.HasOne("ErsatzTV.Core.Domain.Collection", "Collection") + .WithMany() + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany() + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection") + .WithMany() + .HasForeignKey("MultiCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SmartCollection", "SmartCollection") + .WithMany() + .HasForeignKey("SmartCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Collection"); + + b.Navigation("MediaItem"); + + b.Navigation("MultiCollection"); + + b.Navigation("SmartCollection"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Genre", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Genres") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Genres") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Genres") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Genres") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Genres") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Genres") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Genres") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Genres") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Genres") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ImageFolderDuration", b => + { + b.HasOne("ErsatzTV.Core.Domain.LibraryFolder", "LibraryFolder") + .WithOne("ImageFolderDuration") + .HasForeignKey("ErsatzTV.Core.Domain.ImageFolderDuration", "LibraryFolderId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("LibraryFolder"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ImageMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Image", "Image") + .WithMany("ImageMetadata") + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinConnection", b => + { + b.HasOne("ErsatzTV.Core.Domain.JellyfinMediaSource", "JellyfinMediaSource") + .WithMany("Connections") + .HasForeignKey("JellyfinMediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("JellyfinMediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinPathReplacement", b => + { + b.HasOne("ErsatzTV.Core.Domain.JellyfinMediaSource", "JellyfinMediaSource") + .WithMany("PathReplacements") + .HasForeignKey("JellyfinMediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("JellyfinMediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Library", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaSource", "MediaSource") + .WithMany("Libraries") + .HasForeignKey("MediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LibraryFolder", b => + { + b.HasOne("ErsatzTV.Core.Domain.LibraryPath", "LibraryPath") + .WithMany("LibraryFolders") + .HasForeignKey("LibraryPathId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.LibraryFolder", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("LibraryPath"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LibraryPath", b => + { + b.HasOne("ErsatzTV.Core.Domain.Library", "Library") + .WithMany("Paths") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaChapter", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaVersion", "MediaVersion") + .WithMany("Chapters") + .HasForeignKey("MediaVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaVersion"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaFile", b => + { + b.HasOne("ErsatzTV.Core.Domain.LibraryFolder", "LibraryFolder") + .WithMany("MediaFiles") + .HasForeignKey("LibraryFolderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("ErsatzTV.Core.Domain.MediaVersion", "MediaVersion") + .WithMany("MediaFiles") + .HasForeignKey("MediaVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LibraryFolder"); + + b.Navigation("MediaVersion"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.LibraryPath", "LibraryPath") + .WithMany("MediaItems") + .HasForeignKey("LibraryPathId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LibraryPath"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaStream", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaVersion", "MediaVersion") + .WithMany("Streams") + .HasForeignKey("MediaVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaVersion"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaVersion", b => + { + b.HasOne("ErsatzTV.Core.Domain.Episode", null) + .WithMany("MediaVersions") + .HasForeignKey("EpisodeId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Image", null) + .WithMany("MediaVersions") + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Movie", null) + .WithMany("MediaVersions") + .HasForeignKey("MovieId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideo", null) + .WithMany("MediaVersions") + .HasForeignKey("MusicVideoId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideo", null) + .WithMany("MediaVersions") + .HasForeignKey("OtherVideoId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Song", null) + .WithMany("MediaVersions") + .HasForeignKey("SongId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MetadataGuid", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Guids") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Guids") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Guids") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Guids") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Guids") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Guids") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Guids") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Guids") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Guids") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Mood", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Moods") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MovieMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Movie", "Movie") + .WithMany("MovieMetadata") + .HasForeignKey("MovieId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Movie"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollectionItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.Collection", "Collection") + .WithMany("MultiCollectionItems") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection") + .WithMany("MultiCollectionItems") + .HasForeignKey("MultiCollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("MultiCollection"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollectionSmartItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection") + .WithMany("MultiCollectionSmartItems") + .HasForeignKey("MultiCollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.SmartCollection", "SmartCollection") + .WithMany("MultiCollectionSmartItems") + .HasForeignKey("SmartCollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MultiCollection"); + + b.Navigation("SmartCollection"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoArtist", b => + { + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Artists") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.MusicVideo", "MusicVideo") + .WithMany("MusicVideoMetadata") + .HasForeignKey("MusicVideoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MusicVideo"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.OtherVideoMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.OtherVideo", "OtherVideo") + .WithMany("OtherVideoMetadata") + .HasForeignKey("OtherVideoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("OtherVideo"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Playout", b => + { + b.HasOne("ErsatzTV.Core.Domain.Channel", "Channel") + .WithMany("Playouts") + .HasForeignKey("ChannelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.ProgramSchedule", "ProgramSchedule") + .WithMany("Playouts") + .HasForeignKey("ProgramScheduleId") + .OnDelete(DeleteBehavior.Cascade); + + b.OwnsOne("ErsatzTV.Core.Domain.PlayoutAnchor", "Anchor", b1 => + { + b1.Property("PlayoutId") + .HasColumnType("INTEGER"); + + b1.Property("DurationFinish") + .HasColumnType("TEXT"); + + b1.Property("InDurationFiller") + .HasColumnType("INTEGER"); + + b1.Property("InFlood") + .HasColumnType("INTEGER"); + + b1.Property("MultipleRemaining") + .HasColumnType("INTEGER"); + + b1.Property("NextGuideGroup") + .HasColumnType("INTEGER"); + + b1.Property("NextStart") + .HasColumnType("TEXT"); + + b1.HasKey("PlayoutId"); + + b1.ToTable("PlayoutAnchor", (string)null); + + b1.WithOwner() + .HasForeignKey("PlayoutId"); + + b1.OwnsOne("ErsatzTV.Core.Domain.CollectionEnumeratorState", "ScheduleItemsEnumeratorState", b2 => + { + b2.Property("PlayoutAnchorPlayoutId") + .HasColumnType("INTEGER"); + + b2.Property("Index") + .HasColumnType("INTEGER"); + + b2.Property("Seed") + .HasColumnType("INTEGER"); + + b2.HasKey("PlayoutAnchorPlayoutId"); + + b2.ToTable("ScheduleItemsEnumeratorState", (string)null); + + b2.WithOwner() + .HasForeignKey("PlayoutAnchorPlayoutId"); + }); + + b1.Navigation("ScheduleItemsEnumeratorState"); + }); + + b.Navigation("Anchor"); + + b.Navigation("Channel"); + + b.Navigation("ProgramSchedule"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlayoutItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany() + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Playout", "Playout") + .WithMany("Items") + .HasForeignKey("PlayoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.ChannelWatermark", "Watermark") + .WithMany() + .HasForeignKey("WatermarkId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("MediaItem"); + + b.Navigation("Playout"); + + b.Navigation("Watermark"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlayoutProgramScheduleAnchor", b => + { + b.HasOne("ErsatzTV.Core.Domain.Collection", "Collection") + .WithMany() + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany() + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection") + .WithMany() + .HasForeignKey("MultiCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Playout", "Playout") + .WithMany("ProgramScheduleAnchors") + .HasForeignKey("PlayoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.SmartCollection", "SmartCollection") + .WithMany() + .HasForeignKey("SmartCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.OwnsOne("ErsatzTV.Core.Domain.CollectionEnumeratorState", "EnumeratorState", b1 => + { + b1.Property("PlayoutProgramScheduleAnchorId") + .HasColumnType("INTEGER"); + + b1.Property("Index") + .HasColumnType("INTEGER"); + + b1.Property("Seed") + .HasColumnType("INTEGER"); + + b1.HasKey("PlayoutProgramScheduleAnchorId"); + + b1.ToTable("CollectionEnumeratorState", (string)null); + + b1.WithOwner() + .HasForeignKey("PlayoutProgramScheduleAnchorId"); + }); + + b.Navigation("Collection"); + + b.Navigation("EnumeratorState"); + + b.Navigation("MediaItem"); + + b.Navigation("MultiCollection"); + + b.Navigation("Playout"); + + b.Navigation("SmartCollection"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlayoutScheduleItemFillGroupIndex", b => + { + b.HasOne("ErsatzTV.Core.Domain.Playout", "Playout") + .WithMany("FillGroupIndices") + .HasForeignKey("PlayoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", "ProgramScheduleItem") + .WithMany() + .HasForeignKey("ProgramScheduleItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("ErsatzTV.Core.Domain.CollectionEnumeratorState", "EnumeratorState", b1 => + { + b1.Property("PlayoutScheduleItemFillGroupIndexId") + .HasColumnType("INTEGER"); + + b1.Property("Index") + .HasColumnType("INTEGER"); + + b1.Property("Seed") + .HasColumnType("INTEGER"); + + b1.HasKey("PlayoutScheduleItemFillGroupIndexId"); + + b1.ToTable("FillGroupEnumeratorState", (string)null); + + b1.WithOwner() + .HasForeignKey("PlayoutScheduleItemFillGroupIndexId"); + }); + + b.Navigation("EnumeratorState"); + + b.Navigation("Playout"); + + b.Navigation("ProgramScheduleItem"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexConnection", b => + { + b.HasOne("ErsatzTV.Core.Domain.PlexMediaSource", "PlexMediaSource") + .WithMany("Connections") + .HasForeignKey("PlexMediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PlexMediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexPathReplacement", b => + { + b.HasOne("ErsatzTV.Core.Domain.PlexMediaSource", "PlexMediaSource") + .WithMany("PathReplacements") + .HasForeignKey("PlexMediaSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PlexMediaSource"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleAlternate", b => + { + b.HasOne("ErsatzTV.Core.Domain.Playout", "Playout") + .WithMany("ProgramScheduleAlternates") + .HasForeignKey("PlayoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.ProgramSchedule", "ProgramSchedule") + .WithMany("ProgramScheduleAlternates") + .HasForeignKey("ProgramScheduleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Playout"); + + b.Navigation("ProgramSchedule"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.Collection", "Collection") + .WithMany() + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Filler.FillerPreset", "FallbackFiller") + .WithMany() + .HasForeignKey("FallbackFillerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany() + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Filler.FillerPreset", "MidRollFiller") + .WithMany() + .HasForeignKey("MidRollFillerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection") + .WithMany() + .HasForeignKey("MultiCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Filler.FillerPreset", "PostRollFiller") + .WithMany() + .HasForeignKey("PostRollFillerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.Filler.FillerPreset", "PreRollFiller") + .WithMany() + .HasForeignKey("PreRollFillerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.ProgramSchedule", "ProgramSchedule") + .WithMany("Items") + .HasForeignKey("ProgramScheduleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SmartCollection", "SmartCollection") + .WithMany() + .HasForeignKey("SmartCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.Filler.FillerPreset", "TailFiller") + .WithMany() + .HasForeignKey("TailFillerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.ChannelWatermark", "Watermark") + .WithMany() + .HasForeignKey("WatermarkId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Collection"); + + b.Navigation("FallbackFiller"); + + b.Navigation("MediaItem"); + + b.Navigation("MidRollFiller"); + + b.Navigation("MultiCollection"); + + b.Navigation("PostRollFiller"); + + b.Navigation("PreRollFiller"); + + b.Navigation("ProgramSchedule"); + + b.Navigation("SmartCollection"); + + b.Navigation("TailFiller"); + + b.Navigation("Watermark"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Block", b => + { + b.HasOne("ErsatzTV.Core.Domain.Scheduling.BlockGroup", "BlockGroup") + .WithMany("Blocks") + .HasForeignKey("BlockGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BlockGroup"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.BlockItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.Scheduling.Block", "Block") + .WithMany("Items") + .HasForeignKey("BlockId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Collection", "Collection") + .WithMany() + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany() + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection") + .WithMany() + .HasForeignKey("MultiCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SmartCollection", "SmartCollection") + .WithMany() + .HasForeignKey("SmartCollectionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Block"); + + b.Navigation("Collection"); + + b.Navigation("MediaItem"); + + b.Navigation("MultiCollection"); + + b.Navigation("SmartCollection"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.PlayoutHistory", b => + { + b.HasOne("ErsatzTV.Core.Domain.Scheduling.Block", "Block") + .WithMany("PlayoutHistory") + .HasForeignKey("BlockId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Playout", "Playout") + .WithMany("PlayoutHistory") + .HasForeignKey("PlayoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Block"); + + b.Navigation("Playout"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.PlayoutTemplate", b => + { + b.HasOne("ErsatzTV.Core.Domain.Playout", "Playout") + .WithMany("Templates") + .HasForeignKey("PlayoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Scheduling.Template", "Template") + .WithMany("PlayoutTemplates") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Playout"); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Template", b => + { + b.HasOne("ErsatzTV.Core.Domain.Scheduling.TemplateGroup", "TemplateGroup") + .WithMany("Templates") + .HasForeignKey("TemplateGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TemplateGroup"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.TemplateItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.Scheduling.Block", "Block") + .WithMany("TemplateItems") + .HasForeignKey("BlockId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Scheduling.Template", "Template") + .WithMany("Items") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Block"); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SeasonMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Season", "Season") + .WithMany("SeasonMetadata") + .HasForeignKey("SeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Season"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ShowMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Show", "Show") + .WithMany("ShowMetadata") + .HasForeignKey("ShowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Show"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SongMetadata", b => + { + b.HasOne("ErsatzTV.Core.Domain.Song", "Song") + .WithMany("SongMetadata") + .HasForeignKey("SongId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Song"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Studio", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Studios") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Studios") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Studios") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Studios") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Studios") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Studios") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Studios") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Studios") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Studios") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Style", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Styles") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Subtitle", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Subtitles") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Tag", b => + { + b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null) + .WithMany("Tags") + .HasForeignKey("ArtistMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Tags") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ImageMetadata", null) + .WithMany("Tags") + .HasForeignKey("ImageMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Tags") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null) + .WithMany("Tags") + .HasForeignKey("MusicVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Tags") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SeasonMetadata", null) + .WithMany("Tags") + .HasForeignKey("SeasonMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.ShowMetadata", null) + .WithMany("Tags") + .HasForeignKey("ShowMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null) + .WithMany("Tags") + .HasForeignKey("SongMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktListItem", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", "MediaItem") + .WithMany("TraktListItems") + .HasForeignKey("MediaItemId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("ErsatzTV.Core.Domain.TraktList", "TraktList") + .WithMany("Items") + .HasForeignKey("TraktListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaItem"); + + b.Navigation("TraktList"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktListItemGuid", b => + { + b.HasOne("ErsatzTV.Core.Domain.TraktListItem", "TraktListItem") + .WithMany("Guids") + .HasForeignKey("TraktListItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TraktListItem"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Writer", b => + { + b.HasOne("ErsatzTV.Core.Domain.EpisodeMetadata", null) + .WithMany("Writers") + .HasForeignKey("EpisodeMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.MovieMetadata", null) + .WithMany("Writers") + .HasForeignKey("MovieMetadataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null) + .WithMany("Writers") + .HasForeignKey("OtherVideoMetadataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Emby.EmbyPathInfo", b => + { + b.HasOne("ErsatzTV.Core.Domain.EmbyLibrary", null) + .WithMany("PathInfos") + .HasForeignKey("EmbyLibraryId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Jellyfin.JellyfinPathInfo", b => + { + b.HasOne("ErsatzTV.Core.Domain.JellyfinLibrary", null) + .WithMany("PathInfos") + .HasForeignKey("JellyfinLibraryId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyLibrary", b => + { + b.HasOne("ErsatzTV.Core.Domain.Library", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.EmbyLibrary", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinLibrary", b => + { + b.HasOne("ErsatzTV.Core.Domain.Library", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.JellyfinLibrary", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LocalLibrary", b => + { + b.HasOne("ErsatzTV.Core.Domain.Library", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.LocalLibrary", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexLibrary", b => + { + b.HasOne("ErsatzTV.Core.Domain.Library", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexLibrary", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMediaFile", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaFile", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexMediaFile", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Artist", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Artist", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Episode", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Episode", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Season", "Season") + .WithMany("Episodes") + .HasForeignKey("SeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Season"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Image", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Image", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Movie", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Movie", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideo", b => + { + b.HasOne("ErsatzTV.Core.Domain.Artist", "Artist") + .WithMany("MusicVideos") + .HasForeignKey("ArtistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.MusicVideo", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Artist"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.OtherVideo", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.OtherVideo", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Season", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Season", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ErsatzTV.Core.Domain.Show", "Show") + .WithMany("Seasons") + .HasForeignKey("ShowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Show"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Show", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Show", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Song", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.Song", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyMediaSource", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaSource", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.EmbyMediaSource", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinMediaSource", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaSource", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.JellyfinMediaSource", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LocalMediaSource", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaSource", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.LocalMediaSource", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMediaSource", b => + { + b.HasOne("ErsatzTV.Core.Domain.MediaSource", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexMediaSource", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemDuration", b => + { + b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.ProgramScheduleItemDuration", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemFlood", b => + { + b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.ProgramScheduleItemFlood", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemMultiple", b => + { + b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.ProgramScheduleItemMultiple", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemOne", b => + { + b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.ProgramScheduleItemOne", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyEpisode", b => + { + b.HasOne("ErsatzTV.Core.Domain.Episode", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.EmbyEpisode", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinEpisode", b => + { + b.HasOne("ErsatzTV.Core.Domain.Episode", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.JellyfinEpisode", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexEpisode", b => + { + b.HasOne("ErsatzTV.Core.Domain.Episode", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexEpisode", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyMovie", b => + { + b.HasOne("ErsatzTV.Core.Domain.Movie", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.EmbyMovie", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinMovie", b => + { + b.HasOne("ErsatzTV.Core.Domain.Movie", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.JellyfinMovie", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMovie", b => + { + b.HasOne("ErsatzTV.Core.Domain.Movie", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexMovie", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbySeason", b => + { + b.HasOne("ErsatzTV.Core.Domain.Season", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.EmbySeason", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinSeason", b => + { + b.HasOne("ErsatzTV.Core.Domain.Season", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.JellyfinSeason", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexSeason", b => + { + b.HasOne("ErsatzTV.Core.Domain.Season", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexSeason", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyShow", b => + { + b.HasOne("ErsatzTV.Core.Domain.Show", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.EmbyShow", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinShow", b => + { + b.HasOne("ErsatzTV.Core.Domain.Show", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.JellyfinShow", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexShow", b => + { + b.HasOne("ErsatzTV.Core.Domain.Show", null) + .WithOne() + .HasForeignKey("ErsatzTV.Core.Domain.PlexShow", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ArtistMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Moods"); + + b.Navigation("Studios"); + + b.Navigation("Styles"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Channel", b => + { + b.Navigation("Artwork"); + + b.Navigation("Playouts"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Collection", b => + { + b.Navigation("CollectionItems"); + + b.Navigation("MultiCollectionItems"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EpisodeMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Directors"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + + b.Navigation("Writers"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ImageMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Library", b => + { + b.Navigation("Paths"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LibraryFolder", b => + { + b.Navigation("Children"); + + b.Navigation("ImageFolderDuration"); + + b.Navigation("MediaFiles"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.LibraryPath", b => + { + b.Navigation("LibraryFolders"); + + b.Navigation("MediaItems"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaItem", b => + { + b.Navigation("CollectionItems"); + + b.Navigation("TraktListItems"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaSource", b => + { + b.Navigation("Libraries"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MediaVersion", b => + { + b.Navigation("Chapters"); + + b.Navigation("MediaFiles"); + + b.Navigation("Streams"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MovieMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Directors"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + + b.Navigation("Writers"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollection", b => + { + b.Navigation("MultiCollectionItems"); + + b.Navigation("MultiCollectionSmartItems"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artists"); + + b.Navigation("Artwork"); + + b.Navigation("Directors"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.OtherVideoMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Directors"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + + b.Navigation("Writers"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Playout", b => + { + b.Navigation("FillGroupIndices"); + + b.Navigation("Items"); + + b.Navigation("PlayoutHistory"); + + b.Navigation("ProgramScheduleAlternates"); + + b.Navigation("ProgramScheduleAnchors"); + + b.Navigation("Templates"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramSchedule", b => + { + b.Navigation("Items"); + + b.Navigation("Playouts"); + + b.Navigation("ProgramScheduleAlternates"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Block", b => + { + b.Navigation("Items"); + + b.Navigation("PlayoutHistory"); + + b.Navigation("TemplateItems"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.BlockGroup", b => + { + b.Navigation("Blocks"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Template", b => + { + b.Navigation("Items"); + + b.Navigation("PlayoutTemplates"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.TemplateGroup", b => + { + b.Navigation("Templates"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SeasonMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.ShowMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SmartCollection", b => + { + b.Navigation("MultiCollectionSmartItems"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.SongMetadata", b => + { + b.Navigation("Actors"); + + b.Navigation("Artwork"); + + b.Navigation("Genres"); + + b.Navigation("Guids"); + + b.Navigation("Studios"); + + b.Navigation("Subtitles"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.TraktListItem", b => + { + b.Navigation("Guids"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyLibrary", b => + { + b.Navigation("PathInfos"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinLibrary", b => + { + b.Navigation("PathInfos"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Artist", b => + { + b.Navigation("ArtistMetadata"); + + b.Navigation("MusicVideos"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Episode", b => + { + b.Navigation("EpisodeMetadata"); + + b.Navigation("MediaVersions"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Image", b => + { + b.Navigation("ImageMetadata"); + + b.Navigation("MediaVersions"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Movie", b => + { + b.Navigation("MediaVersions"); + + b.Navigation("MovieMetadata"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideo", b => + { + b.Navigation("MediaVersions"); + + b.Navigation("MusicVideoMetadata"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.OtherVideo", b => + { + b.Navigation("MediaVersions"); + + b.Navigation("OtherVideoMetadata"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Season", b => + { + b.Navigation("Episodes"); + + b.Navigation("SeasonMetadata"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Show", b => + { + b.Navigation("Seasons"); + + b.Navigation("ShowMetadata"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.Song", b => + { + b.Navigation("MediaVersions"); + + b.Navigation("SongMetadata"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyMediaSource", b => + { + b.Navigation("Connections"); + + b.Navigation("PathReplacements"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinMediaSource", b => + { + b.Navigation("Connections"); + + b.Navigation("PathReplacements"); + }); + + modelBuilder.Entity("ErsatzTV.Core.Domain.PlexMediaSource", b => + { + b.Navigation("Connections"); + + b.Navigation("PathReplacements"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ErsatzTV.Infrastructure.Sqlite/Migrations/20240305094323_Update_BlockUniqueIndex.cs b/ErsatzTV.Infrastructure.Sqlite/Migrations/20240305094323_Update_BlockUniqueIndex.cs new file mode 100644 index 00000000..201b83b2 --- /dev/null +++ b/ErsatzTV.Infrastructure.Sqlite/Migrations/20240305094323_Update_BlockUniqueIndex.cs @@ -0,0 +1,47 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ErsatzTV.Infrastructure.Sqlite.Migrations +{ + /// + public partial class Update_BlockUniqueIndex : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Block_BlockGroupId", + table: "Block"); + + migrationBuilder.DropIndex( + name: "IX_Block_Name", + table: "Block"); + + migrationBuilder.CreateIndex( + name: "IX_Block_BlockGroupId_Name", + table: "Block", + columns: new[] { "BlockGroupId", "Name" }, + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Block_BlockGroupId_Name", + table: "Block"); + + migrationBuilder.CreateIndex( + name: "IX_Block_BlockGroupId", + table: "Block", + column: "BlockGroupId"); + + migrationBuilder.CreateIndex( + name: "IX_Block_Name", + table: "Block", + column: "Name", + unique: true); + } + } +} diff --git a/ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs b/ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs index c4fa6e03..832bb0d6 100644 --- a/ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs +++ b/ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs @@ -15,7 +15,7 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.1"); + modelBuilder.HasAnnotation("ProductVersion", "8.0.2"); modelBuilder.Entity("ErsatzTV.Core.Domain.Actor", b => { @@ -1954,9 +1954,7 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations b.HasKey("Id"); - b.HasIndex("BlockGroupId"); - - b.HasIndex("Name") + b.HasIndex("BlockGroupId", "Name") .IsUnique(); b.ToTable("Block", (string)null); diff --git a/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj b/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj index 8311982d..d3d8d4fe 100644 --- a/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj +++ b/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj @@ -10,15 +10,15 @@ - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockConfiguration.cs index 192905b6..04301a0e 100644 --- a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockConfiguration.cs +++ b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockConfiguration.cs @@ -10,7 +10,7 @@ public class BlockConfiguration : IEntityTypeConfiguration { builder.ToTable("Block"); - builder.HasIndex(b => b.Name) + builder.HasIndex(b => new { b.BlockGroupId, b.Name }) .IsUnique(); builder.HasMany(b => b.Items) diff --git a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockGroupConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockGroupConfiguration.cs index 2e4853e2..d46811e5 100644 --- a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockGroupConfiguration.cs +++ b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockGroupConfiguration.cs @@ -9,7 +9,7 @@ public class BlockGroupConfiguration : IEntityTypeConfiguration public void Configure(EntityTypeBuilder builder) { builder.ToTable("BlockGroup"); - + builder.HasIndex(b => b.Name) .IsUnique(); diff --git a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockItemConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockItemConfiguration.cs index 09c2fb35..32f876a6 100644 --- a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockItemConfiguration.cs +++ b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/BlockItemConfiguration.cs @@ -9,7 +9,7 @@ public class BlockItemConfiguration : IEntityTypeConfiguration public void Configure(EntityTypeBuilder builder) { builder.ToTable("BlockItem"); - + builder.HasOne(i => i.Collection) .WithMany() .HasForeignKey(i => i.CollectionId) diff --git a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/PlayoutHistoryConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/PlayoutHistoryConfiguration.cs index da083909..90aecca2 100644 --- a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/PlayoutHistoryConfiguration.cs +++ b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/PlayoutHistoryConfiguration.cs @@ -6,8 +6,5 @@ namespace ErsatzTV.Infrastructure.Data.Configurations.Scheduling; public class PlayoutHistoryConfiguration : IEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("PlayoutHistory"); - } + public void Configure(EntityTypeBuilder builder) => builder.ToTable("PlayoutHistory"); } diff --git a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/PlayoutTemplateConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/PlayoutTemplateConfiguration.cs index 48b6ec6f..85b9ebc8 100644 --- a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/PlayoutTemplateConfiguration.cs +++ b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/PlayoutTemplateConfiguration.cs @@ -9,7 +9,7 @@ public class PlayoutTemplateConfiguration : IEntityTypeConfiguration builder) { builder.ToTable("PlayoutTemplate"); - + builder.Property(t => t.DaysOfMonth) .HasConversion>(); diff --git a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/TemplateGroupConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/TemplateGroupConfiguration.cs index cb3ea720..bd724682 100644 --- a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/TemplateGroupConfiguration.cs +++ b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/TemplateGroupConfiguration.cs @@ -9,7 +9,7 @@ public class TemplateGroupConfiguration : IEntityTypeConfiguration builder) { builder.ToTable("TemplateGroup"); - + builder.HasIndex(b => b.Name) .IsUnique(); diff --git a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/TemplateItemConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/TemplateItemConfiguration.cs index 630f9b0d..5d2f5c69 100644 --- a/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/TemplateItemConfiguration.cs +++ b/ErsatzTV.Infrastructure/Data/Configurations/Scheduling/TemplateItemConfiguration.cs @@ -6,8 +6,5 @@ namespace ErsatzTV.Infrastructure.Data.Configurations.Scheduling; public class TemplateItemConfiguration : IEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("TemplateItem"); - } + public void Configure(EntityTypeBuilder builder) => builder.ToTable("TemplateItem"); } diff --git a/ErsatzTV.Infrastructure/Data/Repositories/JellyfinTelevisionRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/JellyfinTelevisionRepository.cs index 7e77b850..9b2cbb9f 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/JellyfinTelevisionRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/JellyfinTelevisionRepository.cs @@ -402,7 +402,7 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository { return Option.None; } - + await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); episode.State = MediaItemState.RemoteOnly; diff --git a/ErsatzTV.Infrastructure/Data/Repositories/LibraryRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/LibraryRepository.cs index 4c43b1a0..0f7364ae 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/LibraryRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/LibraryRepository.cs @@ -128,7 +128,7 @@ public class LibraryRepository : ILibraryRepository IOrderedEnumerable orderedFolders = libraryPath.LibraryFolders .Where(f => !_localFileSystem.FolderExists(f.Path)) .OrderByDescending(lp => lp.Path.Length); - + foreach (LibraryFolder folder in orderedFolders) { await dbContext.Connection.ExecuteAsync( @@ -157,7 +157,10 @@ public class LibraryRepository : ILibraryRepository .MapT(lf => lf.Id); } - public async Task GetOrAddFolder(LibraryPath libraryPath, Option maybeParentFolder, string folder) + public async Task GetOrAddFolder( + LibraryPath libraryPath, + Option maybeParentFolder, + string folder) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); @@ -186,7 +189,7 @@ public class LibraryRepository : ILibraryRepository await dbContext.LibraryFolders.AddAsync(knownFolder); await dbContext.SaveChangesAsync(); } - + return knownFolder; } @@ -215,7 +218,7 @@ public class LibraryRepository : ILibraryRepository { parentId = parentFolder; } - + return new LibraryFolder { Path = folder, diff --git a/ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs index ff0f85cf..6fa4ee33 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs @@ -152,7 +152,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository .Map(i => i.Id) .ToList(); result.AddRange(await GetSongItems(dbContext, songIds)); - + var imageIds = searchResults.Items .Filter(i => i.Type == LuceneSearchIndex.ImageType) .Map(i => i.Id) diff --git a/ErsatzTV.Infrastructure/Data/Repositories/MediaItemRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/MediaItemRepository.cs index 28712d6a..b8b6c58b 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/MediaItemRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/MediaItemRepository.cs @@ -182,7 +182,7 @@ public class MediaItemRepository : IMediaItemRepository }; string libraryName = mediaItem.LibraryPath.Library.Name; - logger.LogWarning( + logger.LogDebug( "Unable to add media item to {IncomingLibraryType} '{IncomingLibraryName}'; {LibraryType} '{LibraryName}' already contains path {Path}", incomingLibraryType, incomingLibrary.Name, diff --git a/ErsatzTV.Infrastructure/Data/Repositories/MetadataRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/MetadataRepository.cs index 759dd393..00522768 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/MetadataRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/MetadataRepository.cs @@ -536,7 +536,10 @@ public class MetadataRepository : IMetadataRepository .Map(result => result > 0); } - private static async Task UpdateSubtitles(TvContext dbContext, Core.Domain.Metadata metadata, List subtitles) + private static async Task UpdateSubtitles( + TvContext dbContext, + Core.Domain.Metadata metadata, + List subtitles) { // _logger.LogDebug( // "Updating {Count} subtitles; metadata is {Metadata}", diff --git a/ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs index 6d9969a4..56bb88a8 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs @@ -167,7 +167,7 @@ public class SearchRepository : ISearchRepository WHERE MediaStreamKind = 2 AND S.ShowId = @ShowId", new { ShowId = show.Id }).Map(result => result.ToList()); } - + public async Task> GetSubLanguagesForShow(Show show) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); @@ -192,7 +192,7 @@ public class SearchRepository : ISearchRepository WHERE MediaStreamKind = 2 AND E.SeasonId = @SeasonId", new { SeasonId = season.Id }).Map(result => result.ToList()); } - + public async Task> GetSubLanguagesForSeason(Season season) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); @@ -217,7 +217,7 @@ public class SearchRepository : ISearchRepository WHERE MediaStreamKind = 2 AND A.Id = @ArtistId", new { ArtistId = artist.Id }).Map(result => result.ToList()); } - + public async Task> GetSubLanguagesForArtist(Artist artist) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); diff --git a/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj b/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj index f4f97c26..80070290 100644 --- a/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj +++ b/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj @@ -14,17 +14,17 @@ - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/ErsatzTV.Infrastructure/Images/ImageCache.cs b/ErsatzTV.Infrastructure/Images/ImageCache.cs index 52be5579..d07f14fa 100644 --- a/ErsatzTV.Infrastructure/Images/ImageCache.cs +++ b/ErsatzTV.Infrastructure/Images/ImageCache.cs @@ -12,7 +12,7 @@ using ErsatzTV.Core.Interfaces.Metadata; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; -using Image=SixLabors.ImageSharp.Image; +using Image = SixLabors.ImageSharp.Image; namespace ErsatzTV.Infrastructure.Images; diff --git a/ErsatzTV.Infrastructure/Metadata/LocalStatisticsProvider.cs b/ErsatzTV.Infrastructure/Metadata/LocalStatisticsProvider.cs index b70f796b..ddfc01a9 100644 --- a/ErsatzTV.Infrastructure/Metadata/LocalStatisticsProvider.cs +++ b/ErsatzTV.Infrastructure/Metadata/LocalStatisticsProvider.cs @@ -66,7 +66,6 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider { try { - string mediaItemPath = mediaItem.GetHeadVersion().MediaFiles.Head().Path; var song = File.Create(mediaItemPath); @@ -77,11 +76,11 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider { result.Add(new SongTag(MetadataSongTag.Album, song.Tag.Album)); } - + // album artist(s) IEnumerable albumArtists = song.Tag.AlbumArtists.Filter(a => !string.IsNullOrWhiteSpace(a)); result.AddRange(albumArtists.Map(albumArtist => new SongTag(MetadataSongTag.AlbumArtist, albumArtist))); - + // artist(s) IEnumerable artists = song.Tag.Performers.Filter(p => !string.IsNullOrWhiteSpace(p)); result.AddRange(artists.Map(artist => new SongTag(MetadataSongTag.Artist, artist))); @@ -100,7 +99,7 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider { result.Add(new SongTag(MetadataSongTag.Comment, song.Tag.Comment)); } - + // track result.Add(new SongTag(MetadataSongTag.Track, song.Tag.Track.ToString(CultureInfo.InvariantCulture))); diff --git a/ErsatzTV.Infrastructure/Search/ElasticSearchIndex.cs b/ErsatzTV.Infrastructure/Search/ElasticSearchIndex.cs index e511cd08..0431bd91 100644 --- a/ErsatzTV.Infrastructure/Search/ElasticSearchIndex.cs +++ b/ErsatzTV.Infrastructure/Search/ElasticSearchIndex.cs @@ -353,7 +353,9 @@ public class ElasticSearchIndex : ISearchIndex MetadataKind = metadata.MetadataKind.ToString(), Language = await GetLanguages(searchRepository, await searchRepository.GetLanguagesForShow(show)), LanguageTag = await searchRepository.GetLanguagesForShow(show), - SubLanguage = await GetLanguages(searchRepository, await searchRepository.GetSubLanguagesForShow(show)), + SubLanguage = await GetLanguages( + searchRepository, + await searchRepository.GetSubLanguagesForShow(show)), SubLanguageTag = await searchRepository.GetSubLanguagesForShow(show), ContentRating = GetContentRatings(metadata.ContentRating), ReleaseDate = GetReleaseDate(metadata.ReleaseDate), @@ -728,7 +730,7 @@ public class ElasticSearchIndex : ISearchIndex } } } - + private async Task UpdateImage(ISearchRepository searchRepository, Image image) { foreach (ImageMetadata metadata in image.ImageMetadata.HeadOrNone()) @@ -755,11 +757,11 @@ public class ElasticSearchIndex : ISearchIndex Genre = metadata.Genres.Map(g => g.Name).ToList(), Tag = metadata.Tags.Map(t => t.Name).ToList() }; - + IEnumerable libraryFolderIds = image.MediaVersions .SelectMany(mv => mv.MediaFiles) .SelectMany(mf => Optional(mf.LibraryFolderId)); - + foreach (int libraryFolderId in libraryFolderIds) { doc.LibraryFolderId = libraryFolderId; @@ -823,7 +825,7 @@ public class ElasticSearchIndex : ISearchIndex return result; } - + private async Task> GetSubLanguages( ISearchRepository searchRepository, IEnumerable mediaVersions) diff --git a/ErsatzTV.Infrastructure/Search/LuceneSearchIndex.cs b/ErsatzTV.Infrastructure/Search/LuceneSearchIndex.cs index 4901cbcb..290565ae 100644 --- a/ErsatzTV.Infrastructure/Search/LuceneSearchIndex.cs +++ b/ErsatzTV.Infrastructure/Search/LuceneSearchIndex.cs @@ -558,7 +558,7 @@ public sealed class LuceneSearchIndex : ISearchIndex doc.Add(new TextField(LanguageField, englishName, Field.Store.NO)); } } - + private async Task AddSubLanguages(ISearchRepository searchRepository, Document doc, List mediaCodes) { foreach (string code in mediaCodes.Where(c => !string.IsNullOrWhiteSpace(c)).Distinct()) @@ -1012,7 +1012,7 @@ public sealed class LuceneSearchIndex : ISearchIndex { doc.Add(new TextField(ShowTagField, tag.Name, Field.Store.NO)); } - + foreach (Studio studio in showMetadata.Studios) { doc.Add(new TextField(ShowStudioField, studio.Name, Field.Store.NO)); @@ -1250,7 +1250,7 @@ public sealed class LuceneSearchIndex : ISearchIndex { doc.Add(new TextField(ArtistField, artist, Field.Store.NO)); } - + foreach (string albumArtist in metadata.AlbumArtists) { doc.Add(new TextField(AlbumArtistField, albumArtist, Field.Store.NO)); @@ -1277,7 +1277,7 @@ public sealed class LuceneSearchIndex : ISearchIndex } } } - + private async Task UpdateImage(ISearchRepository searchRepository, Image image) { Option maybeMetadata = image.ImageMetadata.HeadOrNone(); @@ -1307,7 +1307,7 @@ public sealed class LuceneSearchIndex : ISearchIndex IEnumerable libraryFolderIds = image.MediaVersions .SelectMany(mv => mv.MediaFiles) .SelectMany(mf => Optional(mf.LibraryFolderId)); - + foreach (int libraryFolderId in libraryFolderIds) { doc.Add( diff --git a/ErsatzTV.Infrastructure/Search/Models/ElasticSearchItem.cs b/ErsatzTV.Infrastructure/Search/Models/ElasticSearchItem.cs index 1e5f1d94..068446b7 100644 --- a/ErsatzTV.Infrastructure/Search/Models/ElasticSearchItem.cs +++ b/ErsatzTV.Infrastructure/Search/Models/ElasticSearchItem.cs @@ -123,7 +123,7 @@ public class ElasticSearchItem : MinimalElasticSearchItem [JsonPropertyName(LuceneSearchIndex.MoodField)] public List Mood { get; set; } - + [JsonPropertyName(LuceneSearchIndex.LibraryFolderIdField)] public int LibraryFolderId { get; set; } } diff --git a/ErsatzTV.Infrastructure/Search/SearchTargets.cs b/ErsatzTV.Infrastructure/Search/SearchTargets.cs index 58bcab01..7f44d318 100644 --- a/ErsatzTV.Infrastructure/Search/SearchTargets.cs +++ b/ErsatzTV.Infrastructure/Search/SearchTargets.cs @@ -6,8 +6,5 @@ public class SearchTargets : ISearchTargets { public event EventHandler OnSearchTargetsChanged; - public void SearchTargetsChanged() - { - OnSearchTargetsChanged?.Invoke(this, EventArgs.Empty); - } + public void SearchTargetsChanged() => OnSearchTargetsChanged?.Invoke(this, EventArgs.Empty); } diff --git a/ErsatzTV.Infrastructure/Streaming/ExternalJsonPlayoutItemProvider.cs b/ErsatzTV.Infrastructure/Streaming/ExternalJsonPlayoutItemProvider.cs index cd357035..2aee0503 100644 --- a/ErsatzTV.Infrastructure/Streaming/ExternalJsonPlayoutItemProvider.cs +++ b/ErsatzTV.Infrastructure/Streaming/ExternalJsonPlayoutItemProvider.cs @@ -20,11 +20,11 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider { private readonly IDbContextFactory _dbContextFactory; private readonly ILocalFileSystem _localFileSystem; - private readonly IPlexPathReplacementService _plexPathReplacementService; - private readonly IPlexServerApiClient _plexServerApiClient; - private readonly IPlexSecretStore _plexSecretStore; private readonly ILocalStatisticsProvider _localStatisticsProvider; private readonly ILogger _logger; + private readonly IPlexPathReplacementService _plexPathReplacementService; + private readonly IPlexSecretStore _plexSecretStore; + private readonly IPlexServerApiClient _plexServerApiClient; public ExternalJsonPlayoutItemProvider( IDbContextFactory dbContextFactory, @@ -50,7 +50,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider string ffprobePath) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); - + Option maybePlayout = await dbContext.Playouts .AsNoTracking() .SelectOneAsync(p => p.ChannelId, p => p.ChannelId == channel.Id); @@ -76,7 +76,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider return new UnableToLocatePlayoutItem(); } - + private async Task> GetExternalJsonPlayoutItem( TvContext dbContext, Playout playout, @@ -90,7 +90,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider foreach (ExternalJsonChannel channel in maybeChannel) { // TODO: null start time should log and throw - + DateTimeOffset startTime = DateTimeOffset.Parse( channel.StartTime ?? string.Empty, CultureInfo.InvariantCulture, @@ -141,7 +141,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider return await StreamRemotely(dbContext, startTime, program); } - + return new UnableToLocatePlayoutItem(); } @@ -166,8 +166,8 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider new EpisodeMetadata { EpisodeNumber = program.Episode, - Title = program.Title, - }, + Title = program.Title + } ], Season = new Season { @@ -190,7 +190,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider return new UnableToLocatePlayoutItem(); } - + private async Task> StreamRemotely( TvContext dbContext, DateTimeOffset startTime, @@ -199,7 +199,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider Option maybeServer = await dbContext.PlexMediaSources .Include(pms => pms.Connections) .SelectOneAsync(pms => pms.ServerName, pms => pms.ServerName == program.ServerKey); - + foreach (PlexMediaSource server in maybeServer) { Option maybeConnection = server.Connections.SingleOrDefault(c => c.IsActive); diff --git a/ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs b/ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs index 8eccad38..30fd915d 100644 --- a/ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs +++ b/ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs @@ -131,7 +131,7 @@ public class TranscodingTests public static ScalingBehavior[] ScalingBehaviors = [ - ScalingBehavior.ScaleAndPad, + ScalingBehavior.ScaleAndPad //ScalingBehavior.Crop, //ScalingBehavior.Stretch ]; @@ -199,7 +199,7 @@ public class TranscodingTests [ HardwareAccelerationKind.None, //HardwareAccelerationKind.Nvenc, - HardwareAccelerationKind.Vaapi, + HardwareAccelerationKind.Vaapi //HardwareAccelerationKind.Qsv, // HardwareAccelerationKind.VideoToolbox, // HardwareAccelerationKind.Amf @@ -211,7 +211,7 @@ public class TranscodingTests //StreamingMode.HttpLiveStreamingSegmenter, StreamingMode.HttpLiveStreamingSegmenterV2 ]; - + public static string[] FilesToTest => [string.Empty]; } @@ -1011,7 +1011,7 @@ public class TranscodingTests (FFmpegProfileBitDepth.TenBit, _) => PixelFormat.YUV420P10LE, _ => PixelFormat.YUV420P }; - + videoStream.PixelFormat.Should().Be(expectedPixelFormat); // verify colors diff --git a/ErsatzTV.Scanner.Tests/Core/Metadata/MovieFolderScannerTests.cs b/ErsatzTV.Scanner.Tests/Core/Metadata/MovieFolderScannerTests.cs index fe7a3ed5..e7d715e9 100644 --- a/ErsatzTV.Scanner.Tests/Core/Metadata/MovieFolderScannerTests.cs +++ b/ErsatzTV.Scanner.Tests/Core/Metadata/MovieFolderScannerTests.cs @@ -111,7 +111,10 @@ public class MovieFolderScannerTests result.IsRight.Should().BeTrue(); - await _movieRepository.Received(1).GetOrAdd(Arg.Any(), Arg.Any(), Arg.Any()); + await _movieRepository.Received(1).GetOrAdd( + Arg.Any(), + Arg.Any(), + Arg.Any()); await _movieRepository.Received(1).GetOrAdd(libraryPath, Arg.Any(), moviePath); await _localStatisticsProvider.Received(1).RefreshStatistics( @@ -152,7 +155,10 @@ public class MovieFolderScannerTests result.IsRight.Should().BeTrue(); - await _movieRepository.Received(1).GetOrAdd(Arg.Any(), Arg.Any(), Arg.Any()); + await _movieRepository.Received(1).GetOrAdd( + Arg.Any(), + Arg.Any(), + Arg.Any()); await _movieRepository.Received(1).GetOrAdd(libraryPath, Arg.Any(), moviePath); await _localStatisticsProvider.Received(1).RefreshStatistics( @@ -192,7 +198,10 @@ public class MovieFolderScannerTests result.IsRight.Should().BeTrue(); - await _movieRepository.Received(1).GetOrAdd(Arg.Any(), Arg.Any(), Arg.Any()); + await _movieRepository.Received(1).GetOrAdd( + Arg.Any(), + Arg.Any(), + Arg.Any()); await _movieRepository.Received(1).GetOrAdd(libraryPath, Arg.Any(), moviePath); await _localStatisticsProvider.Received(1).RefreshStatistics( @@ -233,7 +242,10 @@ public class MovieFolderScannerTests result.IsRight.Should().BeTrue(); - await _movieRepository.Received(1).GetOrAdd(Arg.Any(), Arg.Any(), Arg.Any()); + await _movieRepository.Received(1).GetOrAdd( + Arg.Any(), + Arg.Any(), + Arg.Any()); await _movieRepository.Received(1).GetOrAdd(libraryPath, Arg.Any(), moviePath); await _localStatisticsProvider.Received(1).RefreshStatistics( @@ -278,7 +290,10 @@ public class MovieFolderScannerTests result.IsRight.Should().BeTrue(); - await _movieRepository.Received(1).GetOrAdd(Arg.Any(), Arg.Any(), Arg.Any()); + await _movieRepository.Received(1).GetOrAdd( + Arg.Any(), + Arg.Any(), + Arg.Any()); await _movieRepository.Received(1).GetOrAdd(libraryPath, Arg.Any(), moviePath); await _localStatisticsProvider.Received(1).RefreshStatistics( @@ -324,7 +339,10 @@ public class MovieFolderScannerTests result.IsRight.Should().BeTrue(); - await _movieRepository.Received(1).GetOrAdd(Arg.Any(), Arg.Any(), Arg.Any()); + await _movieRepository.Received(1).GetOrAdd( + Arg.Any(), + Arg.Any(), + Arg.Any()); await _movieRepository.Received(1).GetOrAdd(libraryPath, Arg.Any(), moviePath); await _localStatisticsProvider.Received(1).RefreshStatistics( @@ -370,7 +388,10 @@ public class MovieFolderScannerTests result.IsRight.Should().BeTrue(); - await _movieRepository.Received(1).GetOrAdd(Arg.Any(), Arg.Any(), Arg.Any()); + await _movieRepository.Received(1).GetOrAdd( + Arg.Any(), + Arg.Any(), + Arg.Any()); await _movieRepository.Received(1).GetOrAdd(libraryPath, Arg.Any(), moviePath); await _localStatisticsProvider.Received(1).RefreshStatistics( @@ -415,7 +436,10 @@ public class MovieFolderScannerTests result.IsRight.Should().BeTrue(); - await _movieRepository.Received(1).GetOrAdd(Arg.Any(), Arg.Any(), Arg.Any()); + await _movieRepository.Received(1).GetOrAdd( + Arg.Any(), + Arg.Any(), + Arg.Any()); await _movieRepository.Received(1).GetOrAdd(libraryPath, Arg.Any(), moviePath); await _localStatisticsProvider.Received(1).RefreshStatistics( @@ -456,7 +480,10 @@ public class MovieFolderScannerTests result.IsRight.Should().BeTrue(); - await _movieRepository.Received(1).GetOrAdd(Arg.Any(), Arg.Any(), Arg.Any()); + await _movieRepository.Received(1).GetOrAdd( + Arg.Any(), + Arg.Any(), + Arg.Any()); await _movieRepository.Received(1).GetOrAdd(libraryPath, Arg.Any(), moviePath); await _localStatisticsProvider.Received(1).RefreshStatistics( @@ -499,7 +526,10 @@ public class MovieFolderScannerTests result.IsRight.Should().BeTrue(); - await _movieRepository.Received(1).GetOrAdd(Arg.Any(), Arg.Any(), Arg.Any()); + await _movieRepository.Received(1).GetOrAdd( + Arg.Any(), + Arg.Any(), + Arg.Any()); await _movieRepository.Received(1).GetOrAdd(libraryPath, Arg.Any(), moviePath); await _localStatisticsProvider.Received(1).RefreshStatistics( @@ -536,7 +566,10 @@ public class MovieFolderScannerTests result.IsRight.Should().BeTrue(); - await _movieRepository.Received(1).GetOrAdd(Arg.Any(), Arg.Any(), Arg.Any()); + await _movieRepository.Received(1).GetOrAdd( + Arg.Any(), + Arg.Any(), + Arg.Any()); await _movieRepository.Received(1).GetOrAdd(libraryPath, Arg.Any(), moviePath); await _localStatisticsProvider.Received(1).RefreshStatistics( diff --git a/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj b/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj index de874752..ccbca280 100644 --- a/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj +++ b/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj @@ -10,16 +10,16 @@ - - + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/ErsatzTV.Scanner/Application/Emby/Commands/SynchronizeEmbyLibraryById.cs b/ErsatzTV.Scanner/Application/Emby/Commands/SynchronizeEmbyLibraryById.cs index 6f15915b..23c6d75b 100644 --- a/ErsatzTV.Scanner/Application/Emby/Commands/SynchronizeEmbyLibraryById.cs +++ b/ErsatzTV.Scanner/Application/Emby/Commands/SynchronizeEmbyLibraryById.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Scanner.Application.Emby; -public record SynchronizeEmbyLibraryById - (int EmbyLibraryId, bool ForceScan, bool DeepScan) : IRequest>; +public record SynchronizeEmbyLibraryById(int EmbyLibraryId, bool ForceScan, bool DeepScan) + : IRequest>; diff --git a/ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserIdHandler.cs b/ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserIdHandler.cs index 66b9044d..3c04a06f 100644 --- a/ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserIdHandler.cs +++ b/ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserIdHandler.cs @@ -9,7 +9,7 @@ namespace ErsatzTV.Scanner.Application.Jellyfin; public class SynchronizeJellyfinAdminUserIdHandler : IRequestHandler> + Either> { private readonly IJellyfinApiClient _jellyfinApiClient; private readonly IJellyfinSecretStore _jellyfinSecretStore; diff --git a/ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinCollections.cs b/ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinCollections.cs index 4c1cbb5a..bb54ff18 100644 --- a/ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinCollections.cs +++ b/ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinCollections.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Scanner.Application.Jellyfin; -public record SynchronizeJellyfinCollections - (int JellyfinMediaSourceId, bool ForceScan) : IRequest>; +public record SynchronizeJellyfinCollections(int JellyfinMediaSourceId, bool ForceScan) + : IRequest>; diff --git a/ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinLibraryById.cs b/ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinLibraryById.cs index 5a3140f1..e3eb5bb0 100644 --- a/ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinLibraryById.cs +++ b/ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinLibraryById.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Scanner.Application.Jellyfin; -public record SynchronizeJellyfinLibraryById - (int JellyfinLibraryId, bool ForceScan, bool DeepScan) : IRequest>; +public record SynchronizeJellyfinLibraryById(int JellyfinLibraryId, bool ForceScan, bool DeepScan) + : IRequest>; diff --git a/ErsatzTV.Scanner/Application/MediaSources/Commands/ScanLocalLibraryHandler.cs b/ErsatzTV.Scanner/Application/MediaSources/Commands/ScanLocalLibraryHandler.cs index d03f639a..82ac77dd 100644 --- a/ErsatzTV.Scanner/Application/MediaSources/Commands/ScanLocalLibraryHandler.cs +++ b/ErsatzTV.Scanner/Application/MediaSources/Commands/ScanLocalLibraryHandler.cs @@ -12,6 +12,7 @@ namespace ErsatzTV.Scanner.Application.MediaSources; public class ScanLocalLibraryHandler : IRequestHandler> { private readonly IConfigElementRepository _configElementRepository; + private readonly IImageFolderScanner _imageFolderScanner; private readonly ILibraryRepository _libraryRepository; private readonly ILogger _logger; private readonly IMediator _mediator; @@ -19,7 +20,6 @@ public class ScanLocalLibraryHandler : IRequestHandler>; +public record SynchronizePlexLibraryById(int PlexLibraryId, bool ForceScan, bool DeepScan) + : IRequest>; diff --git a/ErsatzTV.Scanner/Core/Metadata/ImageFolderScanner.cs b/ErsatzTV.Scanner/Core/Metadata/ImageFolderScanner.cs index 52636aad..633d6f9e 100644 --- a/ErsatzTV.Scanner/Core/Metadata/ImageFolderScanner.cs +++ b/ErsatzTV.Scanner/Core/Metadata/ImageFolderScanner.cs @@ -18,12 +18,12 @@ namespace ErsatzTV.Scanner.Core.Metadata; public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner { private readonly IClient _client; + private readonly IImageRepository _imageRepository; private readonly ILibraryRepository _libraryRepository; private readonly ILocalFileSystem _localFileSystem; private readonly ILocalMetadataProvider _localMetadataProvider; private readonly ILogger _logger; private readonly IMediator _mediator; - private readonly IImageRepository _imageRepository; public ImageFolderScanner( ILocalFileSystem localFileSystem, @@ -82,7 +82,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner { await _libraryRepository.UpdatePath(libraryPath, normalizedLibraryPath); } - + if (ShouldIncludeFolder(libraryPath.Path) && allFolders.Add(libraryPath.Path)) { folderQueue.Enqueue(libraryPath.Path); @@ -115,7 +115,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner string imageFolder = folderQueue.Dequeue(); Option maybeParentFolder = await _libraryRepository.GetParentFolderId(imageFolder); - + foldersCompleted++; var filesForEtag = _localFileSystem.ListFiles(imageFolder).ToList(); @@ -144,7 +144,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner { continue; } - + // walk up to get duration, if needed LibraryFolder? currentFolder = knownFolder; double? durationSeconds = currentFolder.ImageFolderDuration?.DurationSeconds; @@ -157,14 +157,14 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner { currentFolder = null; } - + foreach (LibraryFolder parent in maybeParent) { currentFolder = parent; durationSeconds = currentFolder.ImageFolderDuration?.DurationSeconds; } } - + _logger.LogDebug("UPDATE: Etag has changed for folder {Folder}", imageFolder); var hasErrors = false; @@ -271,7 +271,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner { Image image = result.Item; string path = image.GetHeadVersion().MediaFiles.Head().Path; - bool shouldUpdate = true; + var shouldUpdate = true; foreach (ImageMetadata imageMetadata in Optional(image.ImageMetadata).Flatten().HeadOrNone()) { @@ -283,7 +283,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner imageMetadata.DateUpdated != _localFileSystem.GetLastWriteTime(path) || durationsAreDifferent; } - + if (shouldUpdate) { image.ImageMetadata ??= []; diff --git a/ErsatzTV.Scanner/Core/Metadata/LocalFolderScanner.cs b/ErsatzTV.Scanner/Core/Metadata/LocalFolderScanner.cs index 37bb7b50..2647ca19 100644 --- a/ErsatzTV.Scanner/Core/Metadata/LocalFolderScanner.cs +++ b/ErsatzTV.Scanner/Core/Metadata/LocalFolderScanner.cs @@ -11,7 +11,6 @@ using ErsatzTV.Core.Interfaces.Metadata; using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Core.Metadata; using ErsatzTV.Scanner.Core.Interfaces.FFmpeg; -using ErsatzTV.Scanner.Core.Interfaces.Metadata; using Microsoft.Extensions.Logging; namespace ErsatzTV.Scanner.Core.Metadata; @@ -128,7 +127,7 @@ public abstract class LocalFolderScanner return BaseError.New(ex.Message); } } - + protected async Task RefreshArtwork( string artworkFile, ErsatzTV.Core.Domain.Metadata metadata, diff --git a/ErsatzTV.Scanner/Core/Metadata/LocalMetadataProvider.cs b/ErsatzTV.Scanner/Core/Metadata/LocalMetadataProvider.cs index d1251601..78fdc6f5 100644 --- a/ErsatzTV.Scanner/Core/Metadata/LocalMetadataProvider.cs +++ b/ErsatzTV.Scanner/Core/Metadata/LocalMetadataProvider.cs @@ -22,6 +22,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider private readonly IClient _client; private readonly IEpisodeNfoReader _episodeNfoReader; private readonly IFallbackMetadataProvider _fallbackMetadataProvider; + private readonly IImageRepository _imageRepository; private readonly ILocalFileSystem _localFileSystem; private readonly ILocalStatisticsProvider _localStatisticsProvider; private readonly ILogger _logger; @@ -34,7 +35,6 @@ public class LocalMetadataProvider : ILocalMetadataProvider private readonly IOtherVideoRepository _otherVideoRepository; private readonly IShowNfoReader _showNfoReader; private readonly ISongRepository _songRepository; - private readonly IImageRepository _imageRepository; private readonly ITelevisionRepository _televisionRepository; public LocalMetadataProvider( @@ -405,7 +405,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider return None; } } - + private Option LoadImageMetadata(Image image, double? durationSeconds) { string path = image.GetHeadVersion().MediaFiles.Head().Path; @@ -1105,7 +1105,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider return await _metadataRepository.Add(metadata); } - + private async Task ApplyMetadataUpdate(Image image, ImageMetadata metadata) { Option maybeMetadata = Optional(image.ImageMetadata).Flatten().HeadOrNone(); diff --git a/ErsatzTV.Scanner/Core/Metadata/MovieFolderScanner.cs b/ErsatzTV.Scanner/Core/Metadata/MovieFolderScanner.cs index 391c45d5..f1ace95c 100644 --- a/ErsatzTV.Scanner/Core/Metadata/MovieFolderScanner.cs +++ b/ErsatzTV.Scanner/Core/Metadata/MovieFolderScanner.cs @@ -83,7 +83,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner var foldersCompleted = 0; var folderQueue = new Queue(); - + string normalizedLibraryPath = libraryPath.Path.TrimEnd( Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); @@ -91,7 +91,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner { await _libraryRepository.UpdatePath(libraryPath, normalizedLibraryPath); } - + foreach (string folder in _localFileSystem.ListSubdirectories(libraryPath.Path) .Filter(ShouldIncludeFolder) .OrderBy(identity)) @@ -235,7 +235,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner return new ScanCanceled(); } } - + private async Task>> UpdateLibraryFolderId( MediaItemScanResult video, LibraryFolder libraryFolder) diff --git a/ErsatzTV.Scanner/Core/Metadata/MusicVideoFolderScanner.cs b/ErsatzTV.Scanner/Core/Metadata/MusicVideoFolderScanner.cs index 8a2812b7..e2afe630 100644 --- a/ErsatzTV.Scanner/Core/Metadata/MusicVideoFolderScanner.cs +++ b/ErsatzTV.Scanner/Core/Metadata/MusicVideoFolderScanner.cs @@ -396,7 +396,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan return Unit.Default; } - + private async Task>> UpdateLibraryFolderId( MediaItemScanResult video, LibraryFolder libraryFolder) diff --git a/ErsatzTV.Scanner/Core/Metadata/OtherVideoFolderScanner.cs b/ErsatzTV.Scanner/Core/Metadata/OtherVideoFolderScanner.cs index 0963fd71..77a01422 100644 --- a/ErsatzTV.Scanner/Core/Metadata/OtherVideoFolderScanner.cs +++ b/ErsatzTV.Scanner/Core/Metadata/OtherVideoFolderScanner.cs @@ -77,7 +77,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan var allFolders = new System.Collections.Generic.HashSet(); var folderQueue = new Queue(); - + string normalizedLibraryPath = libraryPath.Path.TrimEnd( Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); @@ -233,7 +233,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan return new ScanCanceled(); } } - + private async Task>> UpdateLibraryFolderId( MediaItemScanResult video, LibraryFolder libraryFolder) @@ -312,7 +312,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan return BaseError.New(ex.ToString()); } } - + private async Task>> UpdateThumbnail( MediaItemScanResult result, CancellationToken cancellationToken) @@ -336,7 +336,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan return BaseError.New(ex.ToString()); } } - + private Option LocateThumbnail(OtherVideo otherVideo) { string path = otherVideo.MediaVersions.Head().MediaFiles.Head().Path; diff --git a/ErsatzTV.Scanner/Core/Metadata/SongFolderScanner.cs b/ErsatzTV.Scanner/Core/Metadata/SongFolderScanner.cs index 64750474..7b87ad14 100644 --- a/ErsatzTV.Scanner/Core/Metadata/SongFolderScanner.cs +++ b/ErsatzTV.Scanner/Core/Metadata/SongFolderScanner.cs @@ -73,7 +73,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner var foldersCompleted = 0; var folderQueue = new Queue(); - + string normalizedLibraryPath = libraryPath.Path.TrimEnd( Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); @@ -226,7 +226,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner return new ScanCanceled(); } } - + private async Task>> UpdateLibraryFolderId( MediaItemScanResult result, LibraryFolder libraryFolder) diff --git a/ErsatzTV.Scanner/Core/Metadata/TelevisionFolderScanner.cs b/ErsatzTV.Scanner/Core/Metadata/TelevisionFolderScanner.cs index 8789039f..42fd978b 100644 --- a/ErsatzTV.Scanner/Core/Metadata/TelevisionFolderScanner.cs +++ b/ErsatzTV.Scanner/Core/Metadata/TelevisionFolderScanner.cs @@ -77,7 +77,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan try { decimal progressSpread = progressMax - progressMin; - + string normalizedLibraryPath = libraryPath.Path.TrimEnd( Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); @@ -107,9 +107,9 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan Array.Empty(), Array.Empty()), cancellationToken); - + Option maybeParentFolder = await _libraryRepository.GetParentFolderId(showFolder); - + // this folder is unused by the show, but will be used as parents of season folders LibraryFolder _ = await _libraryRepository.GetOrAddFolder( libraryPath, @@ -236,7 +236,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan { return new ScanCanceled(); } - + Option maybeParentFolder = await _libraryRepository.GetParentFolderId(seasonFolder); string etag = FolderEtag.CalculateWithSubfolders(seasonFolder, _localFileSystem); @@ -426,7 +426,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan return season; } - + private async Task> UpdateLibraryFolderId(Episode episode, LibraryFolder libraryFolder) { MediaFile mediaFile = episode.GetHeadVersion().MediaFiles.Head(); diff --git a/ErsatzTV.Scanner/Core/Plex/PlexConnectionParameters.cs b/ErsatzTV.Scanner/Core/Plex/PlexConnectionParameters.cs index b42fa2d9..f688cb20 100644 --- a/ErsatzTV.Scanner/Core/Plex/PlexConnectionParameters.cs +++ b/ErsatzTV.Scanner/Core/Plex/PlexConnectionParameters.cs @@ -4,5 +4,5 @@ using ErsatzTV.Core.Plex; namespace ErsatzTV.Scanner.Core.Plex; -public record PlexConnectionParameters - (PlexConnection Connection, PlexServerAuthToken Token) : MediaServerConnectionParameters; +public record PlexConnectionParameters(PlexConnection Connection, PlexServerAuthToken Token) + : MediaServerConnectionParameters; diff --git a/ErsatzTV.Scanner/ErsatzTV.Scanner.csproj b/ErsatzTV.Scanner/ErsatzTV.Scanner.csproj index 5248cafd..3496dbb8 100644 --- a/ErsatzTV.Scanner/ErsatzTV.Scanner.csproj +++ b/ErsatzTV.Scanner/ErsatzTV.Scanner.csproj @@ -22,7 +22,7 @@ - + diff --git a/ErsatzTV/Controllers/Api/SessionController.cs b/ErsatzTV/Controllers/Api/SessionController.cs index e75b9b62..dd5b3fc6 100644 --- a/ErsatzTV/Controllers/Api/SessionController.cs +++ b/ErsatzTV/Controllers/Api/SessionController.cs @@ -8,10 +8,7 @@ namespace ErsatzTV.Controllers.Api; public class SessionController(IFFmpegSegmenterService ffmpegSegmenterService) { [HttpGet("api/sessions")] - public List GetSessions() - { - return ffmpegSegmenterService.Workers.Map(w => w.GetModel()).ToList(); - } + public List GetSessions() => ffmpegSegmenterService.Workers.Map(w => w.GetModel()).ToList(); [HttpDelete("api/session/{channelNumber}")] public async Task StopSession(string channelNumber, CancellationToken cancellationToken) diff --git a/ErsatzTV/Controllers/InternalController.cs b/ErsatzTV/Controllers/InternalController.cs index 8f231a3b..e542b111 100644 --- a/ErsatzTV/Controllers/InternalController.cs +++ b/ErsatzTV/Controllers/InternalController.cs @@ -19,8 +19,8 @@ namespace ErsatzTV.Controllers; [ApiExplorerSettings(IgnoreApi = true)] public class InternalController : ControllerBase { - private readonly ILogger _logger; private readonly IFFmpegSegmenterService _ffmpegSegmenterService; + private readonly ILogger _logger; private readonly IMediator _mediator; public InternalController( diff --git a/ErsatzTV/Controllers/IptvController.cs b/ErsatzTV/Controllers/IptvController.cs index 0e0cefe6..cb337d5b 100644 --- a/ErsatzTV/Controllers/IptvController.cs +++ b/ErsatzTV/Controllers/IptvController.cs @@ -136,7 +136,7 @@ public class IptvController : ControllerBase }, error => BadRequest(error.Value))); } - + [HttpGet("iptv/session/{channelNumber}/hls.m3u8")] public async Task GetLivePlaylist(string channelNumber, CancellationToken cancellationToken) { @@ -196,7 +196,10 @@ public class IptvController : ControllerBase case "segmenter": case "segmenter-v2": string multiVariantPlaylist = await GetMultiVariantPlaylist(channelNumber, mode); - _logger.LogDebug("Maybe starting ffmpeg session for channel {Channel}, mode {Mode}", channelNumber, mode); + _logger.LogDebug( + "Maybe starting ffmpeg session for channel {Channel}, mode {Mode}", + channelNumber, + mode); var request = new StartFFmpegSession(channelNumber, mode, Request.Scheme, Request.Host.ToString()); Either result = await _mediator.Send(request); return result.Match( @@ -261,14 +264,14 @@ public class IptvController : ControllerBase _ => "hls.m3u8" }; - + Option maybeResolution = await _mediator.Send(new GetChannelResolution(channelNumber)); string resolution = string.Empty; foreach (ResolutionViewModel res in maybeResolution) { resolution = $",RESOLUTION={res.Width}x{res.Height}"; } - + return $@"#EXTM3U #EXT-X-VERSION:3 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=10000000{resolution} diff --git a/ErsatzTV/ErsatzTV.csproj b/ErsatzTV/ErsatzTV.csproj index 3f8cc561..277a0b0f 100644 --- a/ErsatzTV/ErsatzTV.csproj +++ b/ErsatzTV/ErsatzTV.csproj @@ -20,24 +20,24 @@ - - - - + + + + - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/ErsatzTV/JwtHelper.cs b/ErsatzTV/JwtHelper.cs index 8baeb47e..dae31a98 100644 --- a/ErsatzTV/JwtHelper.cs +++ b/ErsatzTV/JwtHelper.cs @@ -18,7 +18,7 @@ public static class JwtHelper IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(issuerSigningKey!)); } } - + public static string GenerateToken() { var tokenHandler = new JwtSecurityTokenHandler(); diff --git a/ErsatzTV/Pages/Artist.razor b/ErsatzTV/Pages/Artist.razor index b9381425..dcae4171 100644 --- a/ErsatzTV/Pages/Artist.razor +++ b/ErsatzTV/Pages/Artist.razor @@ -223,14 +223,15 @@ private async Task RefreshData() { - await _mediator.Send(new GetArtistById(ArtistId), _cts.Token).IfSomeAsync(vm => - { - _artist = vm; - _sortedLanguages = _artist.Languages.OrderBy(ci => ci.EnglishName).ToList(); - _sortedGenres = _artist.Genres.OrderBy(g => g).ToList(); - _sortedStyles = _artist.Styles.OrderBy(s => s).ToList(); - _sortedMoods = _artist.Moods.OrderBy(m => m).ToList(); - }); + await _mediator.Send(new GetArtistById(ArtistId), _cts.Token).IfSomeAsync( + vm => + { + _artist = vm; + _sortedLanguages = _artist.Languages.OrderBy(ci => ci.EnglishName).ToList(); + _sortedGenres = _artist.Genres.OrderBy(g => g).ToList(); + _sortedStyles = _artist.Styles.OrderBy(s => s).ToList(); + _sortedMoods = _artist.Moods.OrderBy(m => m).ToList(); + }); _musicVideos = await _mediator.Send(new GetMusicVideoCards(ArtistId, 1, 100), _cts.Token); } diff --git a/ErsatzTV/Pages/ArtistList.razor b/ErsatzTV/Pages/ArtistList.razor index edc40601..fcf42f2e 100644 --- a/ErsatzTV/Pages/ArtistList.razor +++ b/ErsatzTV/Pages/ArtistList.razor @@ -105,6 +105,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + _navigationManager.NavigateTo(uri); } @@ -116,6 +117,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + _navigationManager.NavigateTo(uri); } diff --git a/ErsatzTV/Pages/BlockEditor.razor b/ErsatzTV/Pages/BlockEditor.razor index a1e1e905..f42470a0 100644 --- a/ErsatzTV/Pages/BlockEditor.razor +++ b/ErsatzTV/Pages/BlockEditor.razor @@ -1,8 +1,8 @@ @page "/blocks/{Id:int}" -@using ErsatzTV.Application.MediaCollections -@using ErsatzTV.Application.MediaItems @using ErsatzTV.Application.Scheduling @using ErsatzTV.Application.Search +@using ErsatzTV.Application.MediaCollections +@using ErsatzTV.Application.MediaItems @using ErsatzTV.Core.Domain.Scheduling @implements IDisposable @inject NavigationManager NavigationManager @@ -11,264 +11,264 @@ @inject IMediator Mediator - Edit Block -
- - - - - - - - - - - - - - - - - - Before Duration End - After Duration End - - - -
- - Add Block Item - - - Save Changes - - - Preview Block Playout - - - - - - - - - - - - - - - Collection - Playback Order - Show In EPG - - - - - - - - - @context.CollectionName - - - - - @context.PlaybackOrder - - - - - - - - - - - - - - - - - - - - - - - - - -
- @if (_selectedItem is not null) - { - - -
- - - - Collection - Television Show - Television Season - @* Artist *@ - @* Multi Collection *@ - Smart Collection - - @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.Collection) - { - - - - Only the first 10 items are shown - - - - } - - @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.MultiCollection) - { - - - - Only the first 10 items are shown - - - - } - - @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.SmartCollection) - { - - - - Only the first 10 items are shown - - - - } - - @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.TelevisionShow) - { - - - - Only the first 10 items are shown - - - - } - - @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.TelevisionSeason) - { - - - - Only the first 20 items are shown - - - - } - - @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.Artist) - { - - - - Only the first 10 items are shown - - - - } - - - @switch (_selectedItem.CollectionType) - { - case ProgramScheduleItemCollectionType.MultiCollection: - Shuffle - @* Shuffle In Order *@ - break; - case ProgramScheduleItemCollectionType.Collection: - case ProgramScheduleItemCollectionType.SmartCollection: - Chronological - Shuffle - Random - @* Shuffle In Order *@ - break; - case ProgramScheduleItemCollectionType.TelevisionShow: - Season, Episode - Chronological - Shuffle - Random - @* Multi-Episode Shuffle *@ - break; - case ProgramScheduleItemCollectionType.TelevisionSeason: - case ProgramScheduleItemCollectionType.Artist: - case ProgramScheduleItemCollectionType.FakeCollection: - default: - Chronological - Shuffle - Random - break; - } - - - -
-
- } -
- @if (_previewItems != null) - { - - - Block Playout Preview - +Edit Block +
+ + + + + + + + + + + + + + + + + + Before Duration End + After Duration End + + + +
+ + Add Block Item + + + Save Changes + + + Preview Block Playout + + + + + + + + + + + + + - Start - Finish - Media Item - Duration + Collection + Playback Order + Show In EPG + + + + - @context.Start.ToString(@"hh\:mm\:ss") - @context.Finish.ToString(@"hh\:mm\:ss") - @context.Title - @context.Duration + + + @context.CollectionName + + + + + @context.PlaybackOrder + + + + + + + + + + + + + + + + + + + + + + + +
+ @if (_selectedItem is not null) + { + + +
+ + + + Collection + Television Show + Television Season + @* Artist *@ + @* Multi Collection *@ + Smart Collection + + @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.Collection) + { + + + + Only the first 10 items are shown + + + + } + + @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.MultiCollection) + { + + + + Only the first 10 items are shown + + + + } + + @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.SmartCollection) + { + + + + Only the first 10 items are shown + + + + } + + @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.TelevisionShow) + { + + + + Only the first 10 items are shown + + + + } + + @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.TelevisionSeason) + { + + + + Only the first 20 items are shown + + + + } + + @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.Artist) + { + + + + Only the first 10 items are shown + + + + } + + + @switch (_selectedItem.CollectionType) + { + case ProgramScheduleItemCollectionType.MultiCollection: + Shuffle + @* Shuffle In Order *@ + break; + case ProgramScheduleItemCollectionType.Collection: + case ProgramScheduleItemCollectionType.SmartCollection: + Chronological + Shuffle + Random + @* Shuffle In Order *@ + break; + case ProgramScheduleItemCollectionType.TelevisionShow: + Season, Episode + Chronological + Shuffle + Random + @* Multi-Episode Shuffle *@ + break; + case ProgramScheduleItemCollectionType.TelevisionSeason: + case ProgramScheduleItemCollectionType.Artist: + case ProgramScheduleItemCollectionType.FakeCollection: + default: + Chronological + Shuffle + Random + break; + } + + + +
+
} +
+@if (_previewItems != null) +{ + + + Block Playout Preview + + + Start + Finish + Media Item + Duration + + + @context.Start.ToString(@"hh\:mm\:ss") + @context.Finish.ToString(@"hh\:mm\:ss") + @context.Title + @context.Duration + + +}
@code { @@ -280,7 +280,7 @@ private BlockItemsEditViewModel _block = new() { Items = [] }; private BlockItemEditViewModel _selectedItem; private List _previewItems; - private int _durationHours = 0; + private int _durationHours; private int _durationMinutes = 15; public void Dispose() @@ -299,7 +299,7 @@ NavigationManager.NavigateTo("blocks"); return; } - + foreach (BlockViewModel block in maybeBlock) { _block = new BlockItemsEditViewModel @@ -494,8 +494,6 @@ _previewItems = await Mediator.Send(new PreviewBlockPlayout(GenerateReplaceRequest()), _cts.Token); } - private static void UpdateEPG(BlockItemEditViewModel context, bool includeInProgramGuide) - { - context.IncludeInProgramGuide = includeInProgramGuide; - } -} + private static void UpdateEPG(BlockItemEditViewModel context, bool includeInProgramGuide) => context.IncludeInProgramGuide = includeInProgramGuide; + +} \ No newline at end of file diff --git a/ErsatzTV/Pages/Blocks.razor b/ErsatzTV/Pages/Blocks.razor index 8de2a512..bb325621 100644 --- a/ErsatzTV/Pages/Blocks.razor +++ b/ErsatzTV/Pages/Blocks.razor @@ -1,5 +1,5 @@ @page "/blocks" -@using S=System.Collections.Generic +@using S = System.Collections.Generic @using ErsatzTV.Application.Scheduling @implements IDisposable @inject ILogger Logger @@ -88,7 +88,7 @@ private BlockGroupViewModel _selectedBlockGroup; private string _blockGroupName; private string _blockName; - + public void Dispose() { _cts.Cancel(); @@ -123,25 +123,25 @@ { TreeItems.Add(new BlockTreeItemViewModel(blockGroup)); _blockGroupName = null; - + _blockGroups = await Mediator.Send(new GetAllBlockGroups(), _cts.Token); await InvokeAsync(StateHasChanged); } } } - + private async Task AddBlock() { if (_selectedBlockGroup is not null && !string.IsNullOrWhiteSpace(_blockName)) { Either result = await Mediator.Send(new CreateBlock(_selectedBlockGroup.Id, _blockName), _cts.Token); - + foreach (BaseError error in result.LeftToSeq()) { Snackbar.Add(error.Value, Severity.Error); Logger.LogError("Unexpected error adding block: {Error}", error.Value); } - + foreach (BlockViewModel block in result.RightToSeq()) { foreach (BlockTreeItemViewModel item in TreeItems.Where(item => item.BlockGroupId == _selectedBlockGroup.Id)) @@ -154,7 +154,7 @@ } } } - + private async Task> LoadServerData(BlockTreeItemViewModel parentNode) { foreach (int blockGroupId in Optional(parentNode.BlockGroupId)) @@ -182,7 +182,7 @@ { await Mediator.Send(new DeleteBlockGroup(blockGroupId), _cts.Token); TreeItems.RemoveWhere(i => i.BlockGroupId == blockGroupId); - + _blockGroups = await Mediator.Send(new GetAllBlockGroups(), _cts.Token); await InvokeAsync(StateHasChanged); } @@ -207,4 +207,5 @@ } } } + } \ No newline at end of file diff --git a/ErsatzTV/Pages/ChannelEditor.razor b/ErsatzTV/Pages/ChannelEditor.razor index 5305c912..a7ddb7c2 100644 --- a/ErsatzTV/Pages/ChannelEditor.razor +++ b/ErsatzTV/Pages/ChannelEditor.razor @@ -7,8 +7,8 @@ @using ErsatzTV.Application.MediaItems @using ErsatzTV.Application.Templates @using ErsatzTV.Application.Watermarks -@using ErsatzTV.Core.Domain.Filler @using ErsatzTV.Application.Channels +@using ErsatzTV.Core.Domain.Filler @implements IDisposable @inject NavigationManager NavigationManager @inject ILogger Logger @@ -196,7 +196,7 @@ { FFmpegSettingsViewModel ffmpegSettings = await Mediator.Send(new GetFFmpegSettings(), _cts.Token); - // TODO: command for new channel + // TODO: command for new channel IEnumerable channelNumbers = await Mediator.Send(new GetAllChannels(), _cts.Token) .Map(list => list.Map(c => int.TryParse(c.Number.Split(".").Head(), out int result) ? result : 0)); int maxNumber = Optional(channelNumbers).Flatten().DefaultIfEmpty(0).Max(); @@ -234,9 +234,7 @@ _messageStore.Clear(); if (_editContext.Validate()) { - Seq errorMessage = IsEdit ? - (await Mediator.Send(_model.ToUpdate(), _cts.Token)).LeftToSeq() : - (await Mediator.Send(_model.ToCreate(), _cts.Token)).LeftToSeq(); + Seq errorMessage = IsEdit ? (await Mediator.Send(_model.ToUpdate(), _cts.Token)).LeftToSeq() : (await Mediator.Send(_model.ToCreate(), _cts.Token)).LeftToSeq(); errorMessage.HeadOrNone().Match( error => diff --git a/ErsatzTV/Pages/Channels.razor b/ErsatzTV/Pages/Channels.razor index 33e8ed86..fca7a6d7 100644 --- a/ErsatzTV/Pages/Channels.razor +++ b/ErsatzTV/Pages/Channels.razor @@ -2,10 +2,8 @@ @using ErsatzTV.Application.Channels @using ErsatzTV.Application.Configuration @using ErsatzTV.Application.FFmpegProfiles -@using System.Globalization @using ErsatzTV.Core.Interfaces.FFmpeg -@using Microsoft.AspNetCore.WebUtilities -@using Microsoft.Extensions.Primitives +@using System.Globalization @implements IDisposable @inject IDialogService Dialog @inject IMediator Mediator @@ -118,11 +116,8 @@ private int _rowsPerPage = 10; - protected override void OnInitialized() - { - SegmenterService.OnWorkersChanged += WorkersChanged; - } - + protected override void OnInitialized() => SegmenterService.OnWorkersChanged += WorkersChanged; + private void WorkersChanged(object sender, EventArgs e) => InvokeAsync(StateHasChanged); @@ -141,10 +136,7 @@ .Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10)); } - private async Task StopChannel(ChannelViewModel channel) - { - await SegmenterService.StopChannel(channel.Number, _cts.Token); - } + private async Task StopChannel(ChannelViewModel channel) => await SegmenterService.StopChannel(channel.Number, _cts.Token); private bool CanPreviewChannel(ChannelViewModel channel) { @@ -235,7 +227,7 @@ () => processedChannels.Add(channel)); } - // TODO: properly page this data + // TODO: properly page this data return new TableData { TotalItems = channels.Count, diff --git a/ErsatzTV/Pages/CollectionEditor.razor b/ErsatzTV/Pages/CollectionEditor.razor index ad32db4d..0beab332 100644 --- a/ErsatzTV/Pages/CollectionEditor.razor +++ b/ErsatzTV/Pages/CollectionEditor.razor @@ -48,11 +48,12 @@ if (IsEdit) { Option maybeCollection = await _mediator.Send(new GetCollectionById(Id), _cts.Token); - maybeCollection.IfSome(collection => - { - _model.Id = collection.Id; - _model.Name = collection.Name; - }); + maybeCollection.IfSome( + collection => + { + _model.Id = collection.Id; + _model.Name = collection.Name; + }); } else { @@ -73,9 +74,7 @@ _messageStore.Clear(); if (_editContext.Validate()) { - Seq errorMessage = IsEdit ? - (await _mediator.Send(new UpdateCollection(Id, _model.Name), _cts.Token)).LeftToSeq() : - (await _mediator.Send(new CreateCollection(_model.Name), _cts.Token)).LeftToSeq(); + Seq errorMessage = IsEdit ? (await _mediator.Send(new UpdateCollection(Id, _model.Name), _cts.Token)).LeftToSeq() : (await _mediator.Send(new CreateCollection(_model.Name), _cts.Token)).LeftToSeq(); errorMessage.HeadOrNone().Match( error => diff --git a/ErsatzTV/Pages/CollectionItems.razor b/ErsatzTV/Pages/CollectionItems.razor index bc42cb31..2c705527 100644 --- a/ErsatzTV/Pages/CollectionItems.razor +++ b/ErsatzTV/Pages/CollectionItems.razor @@ -37,26 +37,32 @@ { @_data.MovieCards.Count Movies } + @if (_data?.ShowCards.Count > 0) { @_data.ShowCards.Count Shows } + @if (_data?.SeasonCards.Count > 0) { @_data.SeasonCards.Count Seasons } + @if (_data?.EpisodeCards.Count > 0) { @_data.EpisodeCards.Count Episodes } + @if (_data?.ArtistCards.Count > 0) { @_data.ArtistCards.Count Artists } + @if (_data?.MusicVideoCards.Count > 0) { @_data.MusicVideoCards.Count Music Videos } + @if (_data?.OtherVideoCards.Count > 0) { @_data.OtherVideoCards.Count Other Videos @@ -71,7 +77,7 @@ { @_data.ImageCards.Count Images } - + @if (SupportsCustomOrdering()) {
@@ -281,7 +287,7 @@ } } - + @if (_data?.ImageCards.Count > 0) { _scannerWorkerChannel diff --git a/ErsatzTV/Pages/EmbyMediaSources.razor b/ErsatzTV/Pages/EmbyMediaSources.razor index d9b5cc08..50dddfcb 100644 --- a/ErsatzTV/Pages/EmbyMediaSources.razor +++ b/ErsatzTV/Pages/EmbyMediaSources.razor @@ -1,6 +1,6 @@ @page "/media/sources/emby" -@using ErsatzTV.Application.Emby @using ErsatzTV.Core.Interfaces.Emby +@using ErsatzTV.Application.Emby @using ErsatzTV.Core.Emby @implements IDisposable @inject IEmbySecretStore _embySecretStore diff --git a/ErsatzTV/Pages/EpisodeList.razor b/ErsatzTV/Pages/EpisodeList.razor index 931f12f1..969e3d28 100644 --- a/ErsatzTV/Pages/EpisodeList.razor +++ b/ErsatzTV/Pages/EpisodeList.razor @@ -105,6 +105,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + _navigationManager.NavigateTo(uri); } @@ -116,6 +117,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + _navigationManager.NavigateTo(uri); } diff --git a/ErsatzTV/Pages/FFmpegEditor.razor b/ErsatzTV/Pages/FFmpegEditor.razor index da296f61..bda5f4b8 100644 --- a/ErsatzTV/Pages/FFmpegEditor.razor +++ b/ErsatzTV/Pages/FFmpegEditor.razor @@ -88,6 +88,7 @@ } + @if (_model.HardwareAcceleration is HardwareAccelerationKind.Vaapi or HardwareAccelerationKind.Qsv) { @@ -262,9 +263,7 @@ _messageStore.Clear(); if (_editContext.Validate()) { - Seq errorMessage = IsEdit ? - (await _mediator.Send(_model.ToUpdate(), _cts.Token)).LeftToSeq() : - (await _mediator.Send(_model.ToCreate(), _cts.Token)).LeftToSeq(); + Seq errorMessage = IsEdit ? (await _mediator.Send(_model.ToUpdate(), _cts.Token)).LeftToSeq() : (await _mediator.Send(_model.ToCreate(), _cts.Token)).LeftToSeq(); errorMessage.HeadOrNone().Match( error => diff --git a/ErsatzTV/Pages/FillerPresetEditor.razor b/ErsatzTV/Pages/FillerPresetEditor.razor index b421d6f2..a9fbcd8e 100644 --- a/ErsatzTV/Pages/FillerPresetEditor.razor +++ b/ErsatzTV/Pages/FillerPresetEditor.razor @@ -176,30 +176,31 @@ if (IsEdit) { Option maybeFillerPreset = await _mediator.Send(new GetFillerPresetById(Id), _cts.Token); - maybeFillerPreset.IfSome(fillerPreset => - { - _model.Id = fillerPreset.Id; - _model.Name = fillerPreset.Name; - _model.FillerKind = fillerPreset.FillerKind; - _model.FillerMode = fillerPreset.FillerMode; - _model.Duration = fillerPreset.Duration; - _model.Count = fillerPreset.Count; - _model.PadToNearestMinute = fillerPreset.PadToNearestMinute; - _model.AllowWatermarks = fillerPreset.AllowWatermarks; - _model.CollectionType = fillerPreset.CollectionType; - _model.Collection = fillerPreset.CollectionId.HasValue - ? _mediaCollections.Find(c => c.Id == fillerPreset.CollectionId.Value) - : null; - _model.MultiCollection = fillerPreset.MultiCollectionId.HasValue - ? _multiCollections.Find(c => c.Id == fillerPreset.MultiCollectionId.Value) - : null; - _model.SmartCollection = fillerPreset.SmartCollectionId.HasValue - ? _smartCollections.Find(c => c.Id == fillerPreset.SmartCollectionId.Value) - : null; - _model.MediaItem = fillerPreset.MediaItemId.HasValue - ? _televisionShows.Append(_televisionSeasons).Append(_artists).ToList().Find(vm => vm.MediaItemId == fillerPreset.MediaItemId.Value) - : null; - }); + maybeFillerPreset.IfSome( + fillerPreset => + { + _model.Id = fillerPreset.Id; + _model.Name = fillerPreset.Name; + _model.FillerKind = fillerPreset.FillerKind; + _model.FillerMode = fillerPreset.FillerMode; + _model.Duration = fillerPreset.Duration; + _model.Count = fillerPreset.Count; + _model.PadToNearestMinute = fillerPreset.PadToNearestMinute; + _model.AllowWatermarks = fillerPreset.AllowWatermarks; + _model.CollectionType = fillerPreset.CollectionType; + _model.Collection = fillerPreset.CollectionId.HasValue + ? _mediaCollections.Find(c => c.Id == fillerPreset.CollectionId.Value) + : null; + _model.MultiCollection = fillerPreset.MultiCollectionId.HasValue + ? _multiCollections.Find(c => c.Id == fillerPreset.MultiCollectionId.Value) + : null; + _model.SmartCollection = fillerPreset.SmartCollectionId.HasValue + ? _smartCollections.Find(c => c.Id == fillerPreset.SmartCollectionId.Value) + : null; + _model.MediaItem = fillerPreset.MediaItemId.HasValue + ? _televisionShows.Append(_televisionSeasons).Append(_artists).ToList().Find(vm => vm.MediaItemId == fillerPreset.MediaItemId.Value) + : null; + }); } else { diff --git a/ErsatzTV/Pages/FillerPresets.razor b/ErsatzTV/Pages/FillerPresets.razor index 3d36d429..b1dcf695 100644 --- a/ErsatzTV/Pages/FillerPresets.razor +++ b/ErsatzTV/Pages/FillerPresets.razor @@ -35,15 +35,16 @@ @context.Name @( - context.FillerKind switch { - FillerKind.PreRoll => "Pre-Roll", - FillerKind.MidRoll => "Mid-Roll", - FillerKind.PostRoll => "Post-Roll", - FillerKind.Fallback => "Fallback", - FillerKind.Tail => "Tail", - _ => "None" - } - ) + context.FillerKind switch + { + FillerKind.PreRoll => "Pre-Roll", + FillerKind.MidRoll => "Mid-Roll", + FillerKind.PostRoll => "Post-Roll", + FillerKind.Fallback => "Fallback", + FillerKind.Tail => "Tail", + _ => "None" + } + )
diff --git a/ErsatzTV/Pages/ImageBrowser.razor b/ErsatzTV/Pages/ImageBrowser.razor index 1fcdc81b..6dc20947 100644 --- a/ErsatzTV/Pages/ImageBrowser.razor +++ b/ErsatzTV/Pages/ImageBrowser.razor @@ -1,5 +1,5 @@ @page "/media/browser/images" -@using S=System.Collections.Generic +@using S = System.Collections.Generic @using ErsatzTV.Application.Images @using System.Net @implements IDisposable @@ -83,7 +83,7 @@ var query = $"library_folder_id:{item.LibraryFolderId}"; return WebUtility.UrlEncode(query); } - + private async Task EditImageFolderDuration(ImageTreeItemViewModel item) { var parameters = new DialogParameters { { "ImageFolderDuration", item.ImageFolderDuration } }; @@ -98,4 +98,5 @@ await InvokeAsync(StateHasChanged); } } + } \ No newline at end of file diff --git a/ErsatzTV/Pages/ImageList.razor b/ErsatzTV/Pages/ImageList.razor index 070158dd..3e544d0c 100644 --- a/ErsatzTV/Pages/ImageList.razor +++ b/ErsatzTV/Pages/ImageList.razor @@ -104,6 +104,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + NavigationManager.NavigateTo(uri); } @@ -115,6 +116,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + NavigationManager.NavigateTo(uri); } diff --git a/ErsatzTV/Pages/Index.razor b/ErsatzTV/Pages/Index.razor index 9cb679a3..8a5e9646 100644 --- a/ErsatzTV/Pages/Index.razor +++ b/ErsatzTV/Pages/Index.razor @@ -193,7 +193,7 @@ } catch (Exception) { - // ignore + // ignore } } diff --git a/ErsatzTV/Pages/JellyfinLibrariesEditor.razor b/ErsatzTV/Pages/JellyfinLibrariesEditor.razor index 6da9f657..25843667 100644 --- a/ErsatzTV/Pages/JellyfinLibrariesEditor.razor +++ b/ErsatzTV/Pages/JellyfinLibrariesEditor.razor @@ -1,6 +1,6 @@ @page "/media/sources/jellyfin/{Id:int}/libraries" -@using ErsatzTV.Application.Jellyfin @using ErsatzTV.Application.MediaSources +@using ErsatzTV.Application.Jellyfin @implements IDisposable @inject IMediator _mediator @inject ChannelWriter _scannerWorkerChannel diff --git a/ErsatzTV/Pages/JellyfinMediaSources.razor b/ErsatzTV/Pages/JellyfinMediaSources.razor index b9fc1a24..11b63c86 100644 --- a/ErsatzTV/Pages/JellyfinMediaSources.razor +++ b/ErsatzTV/Pages/JellyfinMediaSources.razor @@ -1,6 +1,6 @@ @page "/media/sources/jellyfin" -@using ErsatzTV.Application.Jellyfin @using ErsatzTV.Core.Interfaces.Jellyfin +@using ErsatzTV.Application.Jellyfin @using ErsatzTV.Core.Jellyfin @implements IDisposable @inject IJellyfinSecretStore _jellyfinSecretStore diff --git a/ErsatzTV/Pages/Libraries.razor b/ErsatzTV/Pages/Libraries.razor index 80cd8126..43cd412a 100644 --- a/ErsatzTV/Pages/Libraries.razor +++ b/ErsatzTV/Pages/Libraries.razor @@ -1,10 +1,10 @@ @page "/media/libraries" +@using PlexLibraryViewModel = ErsatzTV.Application.Libraries.PlexLibraryViewModel @using ErsatzTV.Application.Libraries @using ErsatzTV.Application.MediaSources @using ErsatzTV.Application.Plex @using ErsatzTV.Core.Metadata @using MediatR.Courier -@using PlexLibraryViewModel = ErsatzTV.Application.Libraries.PlexLibraryViewModel @using ErsatzTV.Application.Jellyfin @using ErsatzTV.Application.Emby @implements IDisposable @@ -77,6 +77,7 @@ {
} + list.Map(vm => new LocalLibraryPathEditViewModel - { - Id = vm.Id, - Path = vm.Path - }).ToList()); + .Map( + list => list.Map( + vm => new LocalLibraryPathEditViewModel + { + Id = vm.Id, + Path = vm.Path + }).ToList()); } private async Task MoveLibraryPath(LocalLibraryPathEditViewModel libraryPath) @@ -189,10 +191,11 @@ if (!string.IsNullOrWhiteSpace(_newPath.Path) && _model.Paths.All(p => NormalizePath(p.Path) != NormalizePath(_newPath.Path))) { _model.HasChanges = true; - _model.Paths.Add(new LocalLibraryPathEditViewModel - { - Path = _newPath.Path - }); + _model.Paths.Add( + new LocalLibraryPathEditViewModel + { + Path = _newPath.Path + }); } _newPath.Path = null; @@ -204,14 +207,18 @@ if (_editContext.Validate()) { Either result = IsEdit - ? await _mediator.Send(new UpdateLocalLibrary( - _model.Id, - _model.Name, - _model.Paths.Map(p => new UpdateLocalLibraryPath(p.Id, p.Path)).ToList()), _cts.Token) - : await _mediator.Send(new CreateLocalLibrary( - _model.Name, - _model.MediaKind, - _model.Paths.Map(p => p.Path).ToList()), _cts.Token); + ? await _mediator.Send( + new UpdateLocalLibrary( + _model.Id, + _model.Name, + _model.Paths.Map(p => new UpdateLocalLibraryPath(p.Id, p.Path)).ToList()), + _cts.Token) + : await _mediator.Send( + new CreateLocalLibrary( + _model.Name, + _model.MediaKind, + _model.Paths.Map(p => p.Path).ToList()), + _cts.Token); result.Match( _ => _navigationManager.NavigateTo("media/sources/local"), diff --git a/ErsatzTV/Pages/LocalLibraryPathEditor.razor b/ErsatzTV/Pages/LocalLibraryPathEditor.razor index 1e19cb88..f74c819d 100644 --- a/ErsatzTV/Pages/LocalLibraryPathEditor.razor +++ b/ErsatzTV/Pages/LocalLibraryPathEditor.razor @@ -88,5 +88,4 @@ } - } \ No newline at end of file diff --git a/ErsatzTV/Pages/Logs.razor b/ErsatzTV/Pages/Logs.razor index efb76108..3d2ef11c 100644 --- a/ErsatzTV/Pages/Logs.razor +++ b/ErsatzTV/Pages/Logs.razor @@ -73,28 +73,34 @@ switch (state.SortLabel?.ToLowerInvariant()) { case "timestamp": - data = await Mediator.Send(new GetRecentLogEntries(state.Page, state.PageSize, _searchString) - { - SortExpression = le => le.Timestamp, - SortDescending = state.SortDirection == SortDirection.None - ? Option.None - : state.SortDirection == SortDirection.Descending - }, _cts.Token); + data = await Mediator.Send( + new GetRecentLogEntries(state.Page, state.PageSize, _searchString) + { + SortExpression = le => le.Timestamp, + SortDescending = state.SortDirection == SortDirection.None + ? Option.None + : state.SortDirection == SortDirection.Descending + }, + _cts.Token); break; case "level": - data = await Mediator.Send(new GetRecentLogEntries(state.Page, state.PageSize, _searchString) - { - SortExpression = le => le.Level, - SortDescending = state.SortDirection == SortDirection.None - ? Option.None - : state.SortDirection == SortDirection.Descending - }, _cts.Token); + data = await Mediator.Send( + new GetRecentLogEntries(state.Page, state.PageSize, _searchString) + { + SortExpression = le => le.Level, + SortDescending = state.SortDirection == SortDirection.None + ? Option.None + : state.SortDirection == SortDirection.Descending + }, + _cts.Token); break; default: - data = await Mediator.Send(new GetRecentLogEntries(state.Page, state.PageSize, _searchString) - { - SortDescending = Option.None - }, _cts.Token); + data = await Mediator.Send( + new GetRecentLogEntries(state.Page, state.PageSize, _searchString) + { + SortDescending = Option.None + }, + _cts.Token); break; } diff --git a/ErsatzTV/Pages/MovieList.razor b/ErsatzTV/Pages/MovieList.razor index ed83045d..60fab027 100644 --- a/ErsatzTV/Pages/MovieList.razor +++ b/ErsatzTV/Pages/MovieList.razor @@ -132,6 +132,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + NavigationManager.NavigateTo(uri); } @@ -143,6 +144,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + NavigationManager.NavigateTo(uri); } diff --git a/ErsatzTV/Pages/MultiCollectionEditor.razor b/ErsatzTV/Pages/MultiCollectionEditor.razor index 5bb45f8a..6337cc73 100644 --- a/ErsatzTV/Pages/MultiCollectionEditor.razor +++ b/ErsatzTV/Pages/MultiCollectionEditor.razor @@ -140,26 +140,30 @@ if (IsEdit) { Option maybeCollection = await _mediator.Send(new GetMultiCollectionById(Id), _cts.Token); - maybeCollection.IfSome(collection => - { - _model.Id = collection.Id; - _model.Name = collection.Name; - _model.Items = collection.Items - .Map(item => - new MultiCollectionItemEditViewModel - { - Collection = item.Collection, - ScheduleAsGroup = item.ScheduleAsGroup, - PlaybackOrder = item.PlaybackOrder - }) - .Append(collection.SmartItems.Map(item => - new MultiCollectionSmartItemEditViewModel - { - SmartCollection = item.SmartCollection, - ScheduleAsGroup = item.ScheduleAsGroup, - PlaybackOrder = item.PlaybackOrder - })).ToList(); - }); + maybeCollection.IfSome( + collection => + { + _model.Id = collection.Id; + _model.Name = collection.Name; + _model.Items = collection.Items + .Map( + item => + new MultiCollectionItemEditViewModel + { + Collection = item.Collection, + ScheduleAsGroup = item.ScheduleAsGroup, + PlaybackOrder = item.PlaybackOrder + }) + .Append( + collection.SmartItems.Map( + item => + new MultiCollectionSmartItemEditViewModel + { + SmartCollection = item.SmartCollection, + ScheduleAsGroup = item.ScheduleAsGroup, + PlaybackOrder = item.PlaybackOrder + })).ToList(); + }); } else { @@ -181,9 +185,7 @@ _messageStore.Clear(); if (_editContext.Validate()) { - Seq errorMessage = IsEdit ? - (await _mediator.Send(new UpdateMultiCollection(Id, _model.Name, GetUpdateItems()), _cts.Token)).LeftToSeq() : - (await _mediator.Send(new CreateMultiCollection(_model.Name, GetCreateItems()), _cts.Token)).LeftToSeq(); + Seq errorMessage = IsEdit ? (await _mediator.Send(new UpdateMultiCollection(Id, _model.Name, GetUpdateItems()), _cts.Token)).LeftToSeq() : (await _mediator.Send(new CreateMultiCollection(_model.Name, GetCreateItems()), _cts.Token)).LeftToSeq(); errorMessage.HeadOrNone().Match( error => @@ -196,29 +198,31 @@ } private List GetUpdateItems() => - _model.Items.Map(i => - i switch - { - MultiCollectionSmartItemEditViewModel smartVm => - new UpdateMultiCollectionItem( - null, - smartVm.SmartCollection.Id, - smartVm.ScheduleAsGroup, - smartVm.PlaybackOrder), - _ => new UpdateMultiCollectionItem(i.Collection.Id, null, i.ScheduleAsGroup, i.PlaybackOrder) + _model.Items.Map( + i => + i switch + { + MultiCollectionSmartItemEditViewModel smartVm => + new UpdateMultiCollectionItem( + null, + smartVm.SmartCollection.Id, + smartVm.ScheduleAsGroup, + smartVm.PlaybackOrder), + _ => new UpdateMultiCollectionItem(i.Collection.Id, null, i.ScheduleAsGroup, i.PlaybackOrder) }).ToList(); private List GetCreateItems() => - _model.Items.Map(i => - i switch - { - MultiCollectionSmartItemEditViewModel smartVm => - new CreateMultiCollectionItem( - null, - smartVm.SmartCollection.Id, - smartVm.ScheduleAsGroup, - smartVm.PlaybackOrder), - _ => new CreateMultiCollectionItem(i.Collection.Id, null, i.ScheduleAsGroup, i.PlaybackOrder) + _model.Items.Map( + i => + i switch + { + MultiCollectionSmartItemEditViewModel smartVm => + new CreateMultiCollectionItem( + null, + smartVm.SmartCollection.Id, + smartVm.ScheduleAsGroup, + smartVm.PlaybackOrder), + _ => new CreateMultiCollectionItem(i.Collection.Id, null, i.ScheduleAsGroup, i.PlaybackOrder) }).ToList(); private void RemoveCollection(MultiCollectionItemEditViewModel item) => _model.Items.Remove(item); @@ -227,11 +231,12 @@ { if (_selectedCollection != null && _model.Items.All(i => i.Collection != _selectedCollection)) { - _model.Items.Add(new MultiCollectionItemEditViewModel - { - Collection = _selectedCollection, - PlaybackOrder = PlaybackOrder.Chronological - }); + _model.Items.Add( + new MultiCollectionItemEditViewModel + { + Collection = _selectedCollection, + PlaybackOrder = PlaybackOrder.Chronological + }); _selectedCollection = null; await _collectionSelect.ResetAsync(); @@ -242,11 +247,12 @@ { if (_selectedSmartCollection != null && _model.Items.OfType().All(i => i.SmartCollection != _selectedSmartCollection)) { - _model.Items.Add(new MultiCollectionSmartItemEditViewModel - { - SmartCollection = _selectedSmartCollection, - PlaybackOrder = PlaybackOrder.Chronological - }); + _model.Items.Add( + new MultiCollectionSmartItemEditViewModel + { + SmartCollection = _selectedSmartCollection, + PlaybackOrder = PlaybackOrder.Chronological + }); _selectedSmartCollection = null; await _smartCollectionSelect.ResetAsync(); diff --git a/ErsatzTV/Pages/MusicVideoList.razor b/ErsatzTV/Pages/MusicVideoList.razor index 8a63381f..303cbc76 100644 --- a/ErsatzTV/Pages/MusicVideoList.razor +++ b/ErsatzTV/Pages/MusicVideoList.razor @@ -105,6 +105,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + _navigationManager.NavigateTo(uri); } @@ -116,6 +117,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + _navigationManager.NavigateTo(uri); } diff --git a/ErsatzTV/Pages/OtherVideoList.razor b/ErsatzTV/Pages/OtherVideoList.razor index a2f695cf..f338cf71 100644 --- a/ErsatzTV/Pages/OtherVideoList.razor +++ b/ErsatzTV/Pages/OtherVideoList.razor @@ -104,6 +104,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + NavigationManager.NavigateTo(uri); } @@ -115,6 +116,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + NavigationManager.NavigateTo(uri); } diff --git a/ErsatzTV/Pages/PlayoutAlternateSchedulesEditor.razor b/ErsatzTV/Pages/PlayoutAlternateSchedulesEditor.razor index bbf3ef00..3587d8e1 100644 --- a/ErsatzTV/Pages/PlayoutAlternateSchedulesEditor.razor +++ b/ErsatzTV/Pages/PlayoutAlternateSchedulesEditor.razor @@ -274,24 +274,26 @@ private void SelectWeekdays() { _selectedItem.DaysOfWeek.Clear(); - _selectedItem.DaysOfWeek.AddRange(new[] - { - DayOfWeek.Monday, - DayOfWeek.Tuesday, - DayOfWeek.Wednesday, - DayOfWeek.Thursday, - DayOfWeek.Friday - }); + _selectedItem.DaysOfWeek.AddRange( + new[] + { + DayOfWeek.Monday, + DayOfWeek.Tuesday, + DayOfWeek.Wednesday, + DayOfWeek.Thursday, + DayOfWeek.Friday + }); } private void SelectWeekends() { _selectedItem.DaysOfWeek.Clear(); - _selectedItem.DaysOfWeek.AddRange(new[] - { - DayOfWeek.Saturday, - DayOfWeek.Sunday - }); + _selectedItem.DaysOfWeek.AddRange( + new[] + { + DayOfWeek.Saturday, + DayOfWeek.Sunday + }); } private void SelectAllDaysOfWeek() @@ -369,27 +371,28 @@ private void MoveItemUp(PlayoutAlternateScheduleEditViewModel item) { - // swap with lower index + // swap with lower index PlayoutAlternateScheduleEditViewModel toSwap = _items.OrderByDescending(x => x.Index).First(x => x.Index < item.Index); (toSwap.Index, item.Index) = (item.Index, toSwap.Index); } private void MoveItemDown(PlayoutAlternateScheduleEditViewModel item) { - // swap with higher index + // swap with higher index PlayoutAlternateScheduleEditViewModel toSwap = _items.OrderBy(x => x.Index).First(x => x.Index > item.Index); (toSwap.Index, item.Index) = (item.Index, toSwap.Index); } private async Task SaveChanges() { - var items = _items.Map(item => new ReplacePlayoutAlternateSchedule( - item.Id, - item.Index, - item.ProgramSchedule.Id, - item.DaysOfWeek, - item.DaysOfMonth, - item.MonthsOfYear)).ToList(); + var items = _items.Map( + item => new ReplacePlayoutAlternateSchedule( + item.Id, + item.Index, + item.ProgramSchedule.Id, + item.DaysOfWeek, + item.DaysOfMonth, + item.MonthsOfYear)).ToList(); Seq errorMessages = await Mediator.Send(new ReplacePlayoutAlternateScheduleItems(Id, items), _cts.Token) .Map(e => e.LeftToSeq()); @@ -447,22 +450,22 @@ { int temp = list[i]; - //add a number + //add a number result.Append(list[i]); - //skip number(s) between a range + //skip number(s) between a range while (i < list.Count - 1 && list[i + 1] == list[i] + 1) { i++; } - //add the range + //add the range if (temp != list[i]) { result.Append("-").Append(list[i]); } - //add comma + //add comma if (i != list.Count - 1) { result.Append(", "); diff --git a/ErsatzTV/Pages/PlayoutEditor.razor b/ErsatzTV/Pages/PlayoutEditor.razor index 64ee47de..f7ed83d4 100644 --- a/ErsatzTV/Pages/PlayoutEditor.razor +++ b/ErsatzTV/Pages/PlayoutEditor.razor @@ -41,7 +41,7 @@ @if (Kind == PlayoutKind.ExternalJson) { - + } else if (string.IsNullOrWhiteSpace(Kind)) { @@ -75,7 +75,7 @@ private EditContext _editContext; private ValidationMessageStore _messageStore; - + [Parameter] public string Kind { get; set; } @@ -88,7 +88,7 @@ protected override async Task OnParametersSetAsync() { _model.Kind = Kind; - + _channels = await Mediator.Send(new GetAllChannels(), _cts.Token) .Map(list => list.OrderBy(vm => decimal.Parse(vm.Number)).ToList()); @@ -121,4 +121,5 @@ () => NavigationManager.NavigateTo("/playouts")); } } + } \ No newline at end of file diff --git a/ErsatzTV/Pages/PlayoutTemplatesEditor.razor b/ErsatzTV/Pages/PlayoutTemplatesEditor.razor index 047a0157..9cee2e23 100644 --- a/ErsatzTV/Pages/PlayoutTemplatesEditor.razor +++ b/ErsatzTV/Pages/PlayoutTemplatesEditor.razor @@ -1,9 +1,9 @@ @page "/playouts/{Id:int}/templates" @using System.Globalization -@using ErsatzTV.Application.Channels -@using System.Text @using ErsatzTV.Application.Scheduling +@using ErsatzTV.Application.Channels @using ErsatzTV.Core.Domain.Scheduling +@using System.Text @implements IDisposable @inject NavigationManager NavigationManager @inject ILogger Logger @@ -99,7 +99,7 @@ @templateGroup.Name - } + } @foreach (TemplateViewModel template in _templates) @@ -224,7 +224,7 @@ ShowDay="false" DateRangeChanged="@(range => DateRangeChanged(range))" MonthCellMinHeight="115" - Items="_previewItems" /> + Items="_previewItems"/> } @@ -244,7 +244,7 @@ private List _items = []; private TemplateGroupViewModel _selectedGroup; private PlayoutTemplateEditViewModel _selectedItem; - private List _previewItems = []; + private readonly List _previewItems = []; public void Dispose() { @@ -276,10 +276,10 @@ Template = item.Template, Index = item.Index, DaysOfWeek = item.DaysOfWeek.ToList(), - DaysOfMonth = item.DaysOfMonth.ToList(), - MonthsOfYear = item.MonthsOfYear.ToList() + DaysOfMonth = item.DaysOfMonth.ToList(), + MonthsOfYear = item.MonthsOfYear.ToList() }; - + private async Task UpdateTemplateGroupItems(TemplateGroupViewModel templateGroup) { _selectedGroup = templateGroup; @@ -315,24 +315,26 @@ private void SelectWeekdays() { _selectedItem.DaysOfWeek.Clear(); - _selectedItem.DaysOfWeek.AddRange(new[] - { - DayOfWeek.Monday, - DayOfWeek.Tuesday, - DayOfWeek.Wednesday, - DayOfWeek.Thursday, - DayOfWeek.Friday - }); + _selectedItem.DaysOfWeek.AddRange( + new[] + { + DayOfWeek.Monday, + DayOfWeek.Tuesday, + DayOfWeek.Wednesday, + DayOfWeek.Thursday, + DayOfWeek.Friday + }); } private void SelectWeekends() { _selectedItem.DaysOfWeek.Clear(); - _selectedItem.DaysOfWeek.AddRange(new[] - { - DayOfWeek.Saturday, - DayOfWeek.Sunday - }); + _selectedItem.DaysOfWeek.AddRange( + new[] + { + DayOfWeek.Saturday, + DayOfWeek.Sunday + }); } private void SelectAllDaysOfWeek() @@ -350,13 +352,13 @@ _selectedItem.DaysOfMonth.Add(dayOfMonth); _selectedItem.DaysOfMonth.Sort(); } - + if (!isChecked) { _selectedItem.DaysOfMonth.Remove(dayOfMonth); } } - + private void SelectAllDaysOfMonth() { _selectedItem.DaysOfMonth.Clear(); @@ -409,14 +411,14 @@ private void MoveItemUp(PlayoutTemplateEditViewModel item) { - // swap with lower index + // swap with lower index PlayoutTemplateEditViewModel toSwap = _items.OrderByDescending(x => x.Index).First(x => x.Index < item.Index); (toSwap.Index, item.Index) = (item.Index, toSwap.Index); } private void MoveItemDown(PlayoutTemplateEditViewModel item) { - // swap with higher index + // swap with higher index PlayoutTemplateEditViewModel toSwap = _items.OrderBy(x => x.Index).First(x => x.Index > item.Index); (toSwap.Index, item.Index) = (item.Index, toSwap.Index); } @@ -428,14 +430,15 @@ Snackbar.Add("Unable to save; item has no template selected", Severity.Error); return; } - - var items = _items.Map(item => new ReplacePlayoutTemplate( - item.Id, - item.Index, - item.Template.Id, - item.DaysOfWeek, - item.DaysOfMonth, - item.MonthsOfYear)).ToList(); + + var items = _items.Map( + item => new ReplacePlayoutTemplate( + item.Id, + item.Index, + item.Template.Id, + item.DaysOfWeek, + item.DaysOfMonth, + item.MonthsOfYear)).ToList(); Option maybeError = await Mediator.Send(new ReplacePlayoutTemplateItems(Id, items), _cts.Token); @@ -461,7 +464,7 @@ _previewItems.Clear(); var prioritized = _items.Filter(i => i.Template is not null).OrderBy(t => t.Index).ToList(); - + if (dateRange.Start.HasValue && dateRange.End.HasValue) { DateTime current = dateRange.Start.Value.Date; @@ -532,22 +535,22 @@ { int temp = list[i]; - //add a number + //add a number result.Append(list[i]); - //skip number(s) between a range + //skip number(s) between a range while (i < list.Count - 1 && list[i + 1] == list[i] + 1) { i++; } - //add the range + //add the range if (temp != list[i]) { result.Append("-").Append(list[i]); } - //add comma + //add comma if (i != list.Count - 1) { result.Append(", "); diff --git a/ErsatzTV/Pages/Playouts.razor b/ErsatzTV/Pages/Playouts.razor index 654b1206..11440325 100644 --- a/ErsatzTV/Pages/Playouts.razor +++ b/ErsatzTV/Pages/Playouts.razor @@ -1,7 +1,7 @@ @page "/playouts" @using ErsatzTV.Application.Playouts -@using ErsatzTV.Application.Configuration @using ErsatzTV.Application.Scheduling +@using ErsatzTV.Application.Configuration @using ErsatzTV.Core.Scheduling @implements IDisposable @inject IDialogService Dialog @@ -70,7 +70,7 @@ default: break; - } + }
@@ -281,6 +281,7 @@ { await _table.ReloadServerData(); } + if (_selectedPlayoutId == playout.PlayoutId) { _selectedPlayoutId = null; @@ -321,7 +322,7 @@ { await Mediator.Send(new EraseBlockPlayoutHistory(playout.PlayoutId), _cts.Token); } - + if (_selectedPlayoutId == playout.PlayoutId) { await PlayoutSelected(playout); @@ -355,7 +356,7 @@ List playouts = await Mediator.Send(new GetAllPlayouts(), _cts.Token); IOrderedEnumerable sorted = playouts.OrderBy(p => decimal.Parse(p.ChannelNumber)); - // TODO: properly page this data + // TODO: properly page this data return new TableData { TotalItems = playouts.Count, diff --git a/ErsatzTV/Pages/PlexLibrariesEditor.razor b/ErsatzTV/Pages/PlexLibrariesEditor.razor index d44bba2b..decd5e01 100644 --- a/ErsatzTV/Pages/PlexLibrariesEditor.razor +++ b/ErsatzTV/Pages/PlexLibrariesEditor.razor @@ -1,6 +1,6 @@ @page "/media/sources/plex/{Id:int}/libraries" -@using ErsatzTV.Application.Plex @using ErsatzTV.Application.MediaSources +@using ErsatzTV.Application.Plex @implements IDisposable @inject IMediator _mediator @inject ChannelWriter _scannerWorkerChannel diff --git a/ErsatzTV/Pages/PlexMediaSources.razor b/ErsatzTV/Pages/PlexMediaSources.razor index 73b3d859..27e19047 100644 --- a/ErsatzTV/Pages/PlexMediaSources.razor +++ b/ErsatzTV/Pages/PlexMediaSources.razor @@ -130,7 +130,7 @@ } catch (Exception) { - // ignored + // ignored } }, error => diff --git a/ErsatzTV/Pages/ScheduleItemsEditor.razor b/ErsatzTV/Pages/ScheduleItemsEditor.razor index b8951d8a..17893ae5 100644 --- a/ErsatzTV/Pages/ScheduleItemsEditor.razor +++ b/ErsatzTV/Pages/ScheduleItemsEditor.razor @@ -379,7 +379,7 @@ private async Task LoadScheduleItems() { - // TODO: fix performance + // TODO: fix performance _fillerPresets = await Mediator.Send(new GetAllFillerPresets(), _cts.Token) .Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList()); _watermarks = await Mediator.Send(new GetAllWatermarks(), _cts.Token) @@ -541,48 +541,49 @@ private void MoveItemUp(ProgramScheduleItemEditViewModel item) { - // swap with lower index + // swap with lower index ProgramScheduleItemEditViewModel toSwap = _schedule.Items.OrderByDescending(x => x.Index).First(x => x.Index < item.Index); (toSwap.Index, item.Index) = (item.Index, toSwap.Index); } private void MoveItemDown(ProgramScheduleItemEditViewModel item) { - // swap with higher index + // swap with higher index ProgramScheduleItemEditViewModel toSwap = _schedule.Items.OrderBy(x => x.Index).First(x => x.Index > item.Index); (toSwap.Index, item.Index) = (item.Index, toSwap.Index); } private async Task SaveChanges() { - var items = _schedule.Items.Map(item => new ReplaceProgramScheduleItem( - item.Index, - item.StartType, - item.StartTime, - item.PlayoutMode, - item.CollectionType, - item.Collection?.Id, - item.MultiCollection?.Id, - item.SmartCollection?.Id, - item.MediaItem?.MediaItemId, - item.PlaybackOrder, - item.FillWithGroupMode, - item.MultipleCount, - item.PlayoutDuration, - item.TailMode, - item.DiscardToFillAttempts, - item.CustomTitle, - item.GuideMode, - item.PreRollFiller?.Id, - item.MidRollFiller?.Id, - item.PostRollFiller?.Id, - item.TailFiller?.Id, - item.FallbackFiller?.Id, - item.Watermark?.Id, - item.PreferredAudioLanguageCode, - item.PreferredAudioTitle, - item.PreferredSubtitleLanguageCode, - item.SubtitleMode)).ToList(); + var items = _schedule.Items.Map( + item => new ReplaceProgramScheduleItem( + item.Index, + item.StartType, + item.StartTime, + item.PlayoutMode, + item.CollectionType, + item.Collection?.Id, + item.MultiCollection?.Id, + item.SmartCollection?.Id, + item.MediaItem?.MediaItemId, + item.PlaybackOrder, + item.FillWithGroupMode, + item.MultipleCount, + item.PlayoutDuration, + item.TailMode, + item.DiscardToFillAttempts, + item.CustomTitle, + item.GuideMode, + item.PreRollFiller?.Id, + item.MidRollFiller?.Id, + item.PostRollFiller?.Id, + item.TailFiller?.Id, + item.FallbackFiller?.Id, + item.Watermark?.Id, + item.PreferredAudioLanguageCode, + item.PreferredAudioTitle, + item.PreferredSubtitleLanguageCode, + item.SubtitleMode)).ToList(); Seq errorMessages = await Mediator.Send(new ReplaceProgramScheduleItems(Id, items), _cts.Token).Map(e => e.LeftToSeq()); diff --git a/ErsatzTV/Pages/Schedules.razor b/ErsatzTV/Pages/Schedules.razor index ada20a00..0b6d8770 100644 --- a/ErsatzTV/Pages/Schedules.razor +++ b/ErsatzTV/Pages/Schedules.razor @@ -139,6 +139,7 @@ { await _table.ReloadServerData(); } + if (_selectedSchedule == programSchedule) { _selectedSchedule = null; @@ -166,7 +167,7 @@ List schedules = await Mediator.Send(new GetAllProgramSchedules(), _cts.Token); IOrderedEnumerable sorted = schedules.OrderBy(s => s.Name, new NaturalSortComparer(StringComparison.CurrentCultureIgnoreCase)); - // TODO: properly page this data + // TODO: properly page this data return new TableData { TotalItems = schedules.Count, @@ -181,7 +182,7 @@ List scheduleItems = await Mediator.Send(new GetProgramScheduleItems(_selectedSchedule.Id), _cts.Token); IOrderedEnumerable sorted = scheduleItems.OrderBy(s => s.Index); - // TODO: properly page this data + // TODO: properly page this data return new TableData { TotalItems = scheduleItems.Count, diff --git a/ErsatzTV/Pages/Search.razor b/ErsatzTV/Pages/Search.razor index bc6bd305..b0705ced 100644 --- a/ErsatzTV/Pages/Search.razor +++ b/ErsatzTV/Pages/Search.razor @@ -77,6 +77,7 @@ { @_images.Count Images } +
} - + @if (_images?.Count > 0) {
@@ -648,6 +649,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -659,6 +661,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -670,6 +673,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -681,6 +685,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -692,6 +697,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -703,6 +709,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -714,6 +721,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -725,6 +733,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -736,6 +745,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } diff --git a/ErsatzTV/Pages/Settings.razor b/ErsatzTV/Pages/Settings.razor index 999aca8a..c4f73025 100644 --- a/ErsatzTV/Pages/Settings.razor +++ b/ErsatzTV/Pages/Settings.razor @@ -367,11 +367,12 @@ private static string ValidateTunerCount(int tunerCount) => tunerCount <= 0 ? "Tuner count must be greater than zero" : null; - private static string ValidateLibraryRefreshInterval(int libraryRefreshInterval) => libraryRefreshInterval switch { + private static string ValidateLibraryRefreshInterval(int libraryRefreshInterval) => libraryRefreshInterval switch + { <= -1 => "Library refresh interval must be 0 (do not refresh) or greater than zero", >= 1_000_000 => "Library refresh interval must be less than 1,000,000. Use 0 to disable automatic refresh", _ => null - }; + }; private static string ValidatePlayoutDaysToBuild(int daysToBuild) => daysToBuild <= 0 ? "Days to build must be greater than zero" : null; @@ -443,7 +444,7 @@ }, Right: _ => Snackbar.Add("Successfully saved general settings", Severity.Success)); } - + private async Task SaveXmltvSettings() { Either result = await Mediator.Send(new UpdateXmltvSettings(_xmltvSettings), _cts.Token); diff --git a/ErsatzTV/Pages/SongList.razor b/ErsatzTV/Pages/SongList.razor index 2f3e65ce..0911c8c7 100644 --- a/ErsatzTV/Pages/SongList.razor +++ b/ErsatzTV/Pages/SongList.razor @@ -105,6 +105,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + _navigationManager.NavigateTo(uri); } @@ -116,6 +117,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + _navigationManager.NavigateTo(uri); } diff --git a/ErsatzTV/Pages/TelevisionEpisodeList.razor b/ErsatzTV/Pages/TelevisionEpisodeList.razor index d4022492..98e4a159 100644 --- a/ErsatzTV/Pages/TelevisionEpisodeList.razor +++ b/ErsatzTV/Pages/TelevisionEpisodeList.razor @@ -202,7 +202,7 @@ } catch (Exception) { - // ignored + // ignored } } } diff --git a/ErsatzTV/Pages/TelevisionSeasonList.razor b/ErsatzTV/Pages/TelevisionSeasonList.razor index b9d87fc8..d226ba35 100644 --- a/ErsatzTV/Pages/TelevisionSeasonList.razor +++ b/ErsatzTV/Pages/TelevisionSeasonList.razor @@ -192,15 +192,16 @@ private async Task RefreshData() { await _mediator.Send(new GetTelevisionShowById(ShowId), _cts.Token) - .IfSomeAsync(vm => - { - _show = vm; - _sortedContentRatings = _show.ContentRatings.OrderBy(cr => cr).ToList(); - _sortedLanguages = _show.Languages.OrderBy(ci => ci.EnglishName).ToList(); - _sortedStudios = _show.Studios.OrderBy(s => s).ToList(); - _sortedGenres = _show.Genres.OrderBy(g => g).ToList(); - _sortedTags = _show.Tags.OrderBy(t => t).ToList(); - }); + .IfSomeAsync( + vm => + { + _show = vm; + _sortedContentRatings = _show.ContentRatings.OrderBy(cr => cr).ToList(); + _sortedLanguages = _show.Languages.OrderBy(ci => ci.EnglishName).ToList(); + _sortedStudios = _show.Studios.OrderBy(s => s).ToList(); + _sortedGenres = _show.Genres.OrderBy(g => g).ToList(); + _sortedTags = _show.Tags.OrderBy(t => t).ToList(); + }); _data = await _mediator.Send(new GetTelevisionSeasonCards(ShowId, _pageNumber, _pageSize), _cts.Token); } diff --git a/ErsatzTV/Pages/TelevisionSeasonSearchResults.razor b/ErsatzTV/Pages/TelevisionSeasonSearchResults.razor index 70391e5e..ec8f8340 100644 --- a/ErsatzTV/Pages/TelevisionSeasonSearchResults.razor +++ b/ErsatzTV/Pages/TelevisionSeasonSearchResults.razor @@ -104,6 +104,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + _navigationManager.NavigateTo(uri); } @@ -115,6 +116,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + _navigationManager.NavigateTo(uri); } diff --git a/ErsatzTV/Pages/TelevisionShowList.razor b/ErsatzTV/Pages/TelevisionShowList.razor index d9027054..d4d2259c 100644 --- a/ErsatzTV/Pages/TelevisionShowList.razor +++ b/ErsatzTV/Pages/TelevisionShowList.razor @@ -132,6 +132,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + NavigationManager.NavigateTo(uri); } @@ -143,6 +144,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + NavigationManager.NavigateTo(uri); } diff --git a/ErsatzTV/Pages/TemplateEditor.razor b/ErsatzTV/Pages/TemplateEditor.razor index d29b4112..b3e5b42b 100644 --- a/ErsatzTV/Pages/TemplateEditor.razor +++ b/ErsatzTV/Pages/TemplateEditor.razor @@ -70,7 +70,7 @@ - (none) + (none) @foreach (TemplateItemEditViewModel item in _template.Items.OrderBy(i => i.Start)) { @item.Start.ToShortTimeString() - @item.Text @@ -112,7 +112,7 @@ public int Id { get; set; } private TemplateItemsEditViewModel _template = new(); - private TemplateItemEditViewModel _blockToRemove = null; + private TemplateItemEditViewModel _blockToRemove; private BlockGroupViewModel _selectedBlockGroup; private BlockViewModel _selectedBlock; private DateTime _selectedBlockStart; @@ -128,7 +128,7 @@ await LoadTemplateItems(); DateTime start = DateTime.Today; - _selectedBlockStart = start; + _selectedBlockStart = start; while (start.Date == DateTime.Today.Date) { _startTimes.Add(start); @@ -144,7 +144,7 @@ NavigationManager.NavigateTo("templates"); return; } - + foreach (TemplateViewModel template in maybeTemplate) { _template = new TemplateItemsEditViewModel @@ -175,7 +175,7 @@ private async Task UpdateBlockGroupItems(BlockGroupViewModel blockGroup) { _selectedBlockGroup = blockGroup; - + _blocks.Clear(); _blocks.AddRange(await Mediator.Send(new GetBlocksByBlockGroupId(_selectedBlockGroup.Id), _cts.Token)); } @@ -207,7 +207,7 @@ maybeStart = maybeStart.AddMinutes(15); } } - + private async Task RemoveBlockFromTemplate() { if (_blockToRemove is not null) @@ -218,7 +218,7 @@ await InvokeAsync(StateHasChanged); } } - + private void CalendarItemChanged(CalendarItem calendarItem) { // don't allow any overlap @@ -242,14 +242,14 @@ private bool IntersectsOthers(TemplateItemEditViewModel item, DateTime start, DateTime end) { var willFit = true; - + foreach (TemplateItemEditViewModel existing in _template.Items) { if (existing == item) { continue; } - + if (start < existing.End && existing.Start < end) { willFit = false; @@ -271,10 +271,10 @@ await Task.Delay(10); var items = _template.Items.Map(item => new ReplaceTemplateItem(item.BlockId, item.Start.TimeOfDay)).ToList(); - + Seq errorMessages = await Mediator.Send(new ReplaceTemplateItems(Id, _template.Name, items), _cts.Token) .Map(e => e.LeftToSeq()); - + errorMessages.HeadOrNone().Match( error => { @@ -283,4 +283,5 @@ }, () => NavigationManager.NavigateTo("/templates")); } + } \ No newline at end of file diff --git a/ErsatzTV/Pages/Templates.razor b/ErsatzTV/Pages/Templates.razor index d6735cb7..16a4e8d8 100644 --- a/ErsatzTV/Pages/Templates.razor +++ b/ErsatzTV/Pages/Templates.razor @@ -1,5 +1,5 @@ @page "/templates" -@using S=System.Collections.Generic +@using S = System.Collections.Generic @using ErsatzTV.Application.Scheduling @implements IDisposable @inject ILogger Logger @@ -82,7 +82,7 @@ private TemplateGroupViewModel _selectedTemplateGroup; private string _templateGroupName; private string _templateName; - + public void Dispose() { _cts.Cancel(); @@ -117,25 +117,25 @@ { TreeItems.Add(new TemplateTreeItemViewModel(templateGroup)); _templateGroupName = null; - + _templateGroups = await Mediator.Send(new GetAllTemplateGroups(), _cts.Token); await InvokeAsync(StateHasChanged); } } } - + private async Task AddTemplate() { if (_selectedTemplateGroup is not null && !string.IsNullOrWhiteSpace(_templateName)) { Either result = await Mediator.Send(new CreateTemplate(_selectedTemplateGroup.Id, _templateName), _cts.Token); - + foreach (BaseError error in result.LeftToSeq()) { Snackbar.Add(error.Value, Severity.Error); Logger.LogError("Unexpected error adding template: {Error}", error.Value); } - + foreach (TemplateViewModel template in result.RightToSeq()) { foreach (TemplateTreeItemViewModel item in TreeItems.Where(item => item.TemplateGroupId == _selectedTemplateGroup.Id)) @@ -148,7 +148,7 @@ } } } - + private async Task> LoadServerData(TemplateTreeItemViewModel parentNode) { foreach (int templateGroupId in Optional(parentNode.TemplateGroupId)) @@ -201,4 +201,5 @@ } } } + } \ No newline at end of file diff --git a/ErsatzTV/Pages/TraktLists.razor b/ErsatzTV/Pages/TraktLists.razor index 1827fd24..d2f8b4b5 100644 --- a/ErsatzTV/Pages/TraktLists.razor +++ b/ErsatzTV/Pages/TraktLists.razor @@ -91,14 +91,15 @@ .Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10)); private void LockChanged(object sender, EventArgs e) => - InvokeAsync(async () => - { - StateHasChanged(); - if (_traktListsTable != null && !_locker.IsTraktLocked()) + InvokeAsync( + async () => { - await _traktListsTable.ReloadServerData(); - } - }); + StateHasChanged(); + if (_traktListsTable != null && !_locker.IsTraktLocked()) + { + await _traktListsTable.ReloadServerData(); + } + }); private async Task MatchListItems(TraktListViewModel traktList) { diff --git a/ErsatzTV/Pages/Trash.razor b/ErsatzTV/Pages/Trash.razor index 1c112334..446430f1 100644 --- a/ErsatzTV/Pages/Trash.razor +++ b/ErsatzTV/Pages/Trash.razor @@ -321,7 +321,7 @@ } } - + @if (_images?.Count > 0) {
@@ -413,6 +413,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -424,6 +425,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -435,6 +437,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -446,6 +449,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -457,6 +461,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -468,6 +473,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -479,6 +485,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -490,6 +497,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -501,6 +509,7 @@ (string key, string value) = _query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri; } @@ -531,7 +540,7 @@ musicVideoIds.Count + otherVideoIds.Count + songIds.Count + imageIds.Count; var parameters = new DialogParameters - { { "EntityType", count.ToString() }, { "EntityName", entityName } }; + { { "EntityType", count.ToString() }, { "EntityName", entityName } }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall }; IDialogReference dialog = await Dialog.ShowAsync("Delete From Database", parameters, options); diff --git a/ErsatzTV/Pages/WatermarkEditor.razor b/ErsatzTV/Pages/WatermarkEditor.razor index 0ba335ce..38fe8cf4 100644 --- a/ErsatzTV/Pages/WatermarkEditor.razor +++ b/ErsatzTV/Pages/WatermarkEditor.razor @@ -207,9 +207,7 @@ _messageStore.Clear(); if (_editContext.Validate()) { - Seq errorMessage = IsEdit ? - (await Mediator.Send(_model.ToUpdate(), _cts.Token)).LeftToSeq() : - (await Mediator.Send(_model.ToCreate(), _cts.Token)).LeftToSeq(); + Seq errorMessage = IsEdit ? (await Mediator.Send(_model.ToUpdate(), _cts.Token)).LeftToSeq() : (await Mediator.Send(_model.ToCreate(), _cts.Token)).LeftToSeq(); errorMessage.HeadOrNone().Match( error => diff --git a/ErsatzTV/Program.cs b/ErsatzTV/Program.cs index d79b918e..edc4a6c1 100644 --- a/ErsatzTV/Program.cs +++ b/ErsatzTV/Program.cs @@ -4,7 +4,6 @@ using System.Runtime.InteropServices; using Destructurama; using ErsatzTV.Core; using Serilog; -using Serilog.Core; using Serilog.Events; using Serilog.Sinks.SystemConsole.Themes; @@ -62,7 +61,6 @@ public class Program LoggerConfiguration loggerConfiguration = new LoggerConfiguration() .ReadFrom.Configuration(Configuration) - .MinimumLevel.ControlledBy(LoggingLevelSwitches.DefaultLevelSwitch) // scanning @@ -72,18 +70,21 @@ public class Program // scheduling .MinimumLevel.Override("ErsatzTV.Core.Scheduling", LoggingLevelSwitches.SchedulingLevelSwitch) - .MinimumLevel.Override("ErsatzTV.Application.Subtitles.ExtractEmbeddedSubtitlesHandler", LoggingLevelSwitches.SchedulingLevelSwitch) - + .MinimumLevel.Override( + "ErsatzTV.Application.Subtitles.ExtractEmbeddedSubtitlesHandler", + LoggingLevelSwitches.SchedulingLevelSwitch) + // streaming .MinimumLevel.Override("ErsatzTV.Application.Streaming", LoggingLevelSwitches.StreamingLevelSwitch) .MinimumLevel.Override("ErsatzTV.FFmpeg", LoggingLevelSwitches.StreamingLevelSwitch) - .MinimumLevel.Override("ErsatzTV.Core.FFmpeg.FFmpegLibraryProcessService", LoggingLevelSwitches.StreamingLevelSwitch) + .MinimumLevel.Override( + "ErsatzTV.Core.FFmpeg.FFmpegLibraryProcessService", + LoggingLevelSwitches.StreamingLevelSwitch) .MinimumLevel.Override("ErsatzTV.Controllers.IptvController", LoggingLevelSwitches.StreamingLevelSwitch) .MinimumLevel.Override("ErsatzTV.Controllers.InternalController", LoggingLevelSwitches.StreamingLevelSwitch) - + // http .MinimumLevel.Override("Serilog.AspNetCore.RequestLoggingMiddleware", LoggingLevelSwitches.HttpLevelSwitch) - .Destructure.UsingAttributes() .Enrich.FromLogContext() .WriteTo.File( diff --git a/ErsatzTV/Services/RunOnce/LoadLoggingLevelService.cs b/ErsatzTV/Services/RunOnce/LoadLoggingLevelService.cs index c83b2772..b7c52242 100644 --- a/ErsatzTV/Services/RunOnce/LoadLoggingLevelService.cs +++ b/ErsatzTV/Services/RunOnce/LoadLoggingLevelService.cs @@ -1,7 +1,6 @@ using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Repositories; -using Serilog.Core; using Serilog.Events; namespace ErsatzTV.Services.RunOnce; @@ -31,33 +30,43 @@ public class LoadLoggingLevelService : BackgroundService IConfigElementRepository configElementRepository = scope.ServiceProvider.GetRequiredService(); - foreach (LogEventLevel logLevel in await configElementRepository.GetValue(ConfigElementKey.MinimumLogLevel)) + foreach (LogEventLevel logLevel in await configElementRepository.GetValue( + ConfigElementKey.MinimumLogLevel)) { - LoggingLevelSwitches loggingLevelSwitches = scope.ServiceProvider.GetRequiredService(); + LoggingLevelSwitches loggingLevelSwitches = + scope.ServiceProvider.GetRequiredService(); loggingLevelSwitches.DefaultLevelSwitch.MinimumLevel = logLevel; } - - foreach (LogEventLevel logLevel in await configElementRepository.GetValue(ConfigElementKey.MinimumLogLevelScanning)) + + foreach (LogEventLevel logLevel in await configElementRepository.GetValue( + ConfigElementKey.MinimumLogLevelScanning)) { - LoggingLevelSwitches loggingLevelSwitches = scope.ServiceProvider.GetRequiredService(); + LoggingLevelSwitches loggingLevelSwitches = + scope.ServiceProvider.GetRequiredService(); loggingLevelSwitches.ScanningLevelSwitch.MinimumLevel = logLevel; } - foreach (LogEventLevel logLevel in await configElementRepository.GetValue(ConfigElementKey.MinimumLogLevelScheduling)) + foreach (LogEventLevel logLevel in await configElementRepository.GetValue( + ConfigElementKey.MinimumLogLevelScheduling)) { - LoggingLevelSwitches loggingLevelSwitches = scope.ServiceProvider.GetRequiredService(); + LoggingLevelSwitches loggingLevelSwitches = + scope.ServiceProvider.GetRequiredService(); loggingLevelSwitches.SchedulingLevelSwitch.MinimumLevel = logLevel; } - foreach (LogEventLevel logLevel in await configElementRepository.GetValue(ConfigElementKey.MinimumLogLevelStreaming)) + foreach (LogEventLevel logLevel in await configElementRepository.GetValue( + ConfigElementKey.MinimumLogLevelStreaming)) { - LoggingLevelSwitches loggingLevelSwitches = scope.ServiceProvider.GetRequiredService(); + LoggingLevelSwitches loggingLevelSwitches = + scope.ServiceProvider.GetRequiredService(); loggingLevelSwitches.StreamingLevelSwitch.MinimumLevel = logLevel; } - foreach (LogEventLevel logLevel in await configElementRepository.GetValue(ConfigElementKey.MinimumLogLevelHttp)) + foreach (LogEventLevel logLevel in await configElementRepository.GetValue( + ConfigElementKey.MinimumLogLevelHttp)) { - LoggingLevelSwitches loggingLevelSwitches = scope.ServiceProvider.GetRequiredService(); + LoggingLevelSwitches loggingLevelSwitches = + scope.ServiceProvider.GetRequiredService(); loggingLevelSwitches.HttpLevelSwitch.MinimumLevel = logLevel; } } diff --git a/ErsatzTV/Services/RunOnce/ResourceExtractorService.cs b/ErsatzTV/Services/RunOnce/ResourceExtractorService.cs index 029dfacd..e493405b 100644 --- a/ErsatzTV/Services/RunOnce/ResourceExtractorService.cs +++ b/ErsatzTV/Services/RunOnce/ResourceExtractorService.cs @@ -42,7 +42,7 @@ public class ResourceExtractorService : BackgroundService "_ArtistTitleAlbum_CenterTop.sbntxt", FileSystemLayout.MusicVideoCreditsTemplatesFolder, stoppingToken); - + await ExtractTemplateResource( assembly, "_channel.sbntxt", diff --git a/ErsatzTV/Services/SchedulerService.cs b/ErsatzTV/Services/SchedulerService.cs index 92f9b069..a75accad 100644 --- a/ErsatzTV/Services/SchedulerService.cs +++ b/ErsatzTV/Services/SchedulerService.cs @@ -102,7 +102,7 @@ public class SchedulerService : BackgroundService } } } - + stoppingToken.ThrowIfCancellationRequested(); } catch (Exception ex) when (ex is TaskCanceledException or OperationCanceledException) diff --git a/ErsatzTV/Shared/AddCustomResolutionDialog.razor b/ErsatzTV/Shared/AddCustomResolutionDialog.razor index c044f616..fb6ff0c4 100644 --- a/ErsatzTV/Shared/AddCustomResolutionDialog.razor +++ b/ErsatzTV/Shared/AddCustomResolutionDialog.razor @@ -30,7 +30,7 @@ private void Cancel(MouseEventArgs e) { - // this is gross, but [enter] seems to sometimes trigger cancel instead of submit + // this is gross, but [enter] seems to sometimes trigger cancel instead of submit if (e.Detail == 0) { Submit(); diff --git a/ErsatzTV/Shared/AddToCollectionDialog.razor b/ErsatzTV/Shared/AddToCollectionDialog.razor index bae5da64..456d1ed8 100644 --- a/ErsatzTV/Shared/AddToCollectionDialog.razor +++ b/ErsatzTV/Shared/AddToCollectionDialog.razor @@ -126,7 +126,7 @@ private async Task Cancel(MouseEventArgs e) { - // this is gross, but [enter] seems to sometimes trigger cancel instead of submit + // this is gross, but [enter] seems to sometimes trigger cancel instead of submit if (e.Detail == 0) { await Submit(); diff --git a/ErsatzTV/Shared/AddTraktListDialog.razor b/ErsatzTV/Shared/AddTraktListDialog.razor index 82bd75a6..10a27728 100644 --- a/ErsatzTV/Shared/AddTraktListDialog.razor +++ b/ErsatzTV/Shared/AddTraktListDialog.razor @@ -54,7 +54,7 @@ private void Cancel(MouseEventArgs e) { - // this is gross, but [enter] seems to sometimes trigger cancel instead of submit + // this is gross, but [enter] seems to sometimes trigger cancel instead of submit if (e.Detail == 0) { Submit(); diff --git a/ErsatzTV/Shared/ChannelPreviewDialog.razor b/ErsatzTV/Shared/ChannelPreviewDialog.razor index 092ee60b..1131d4dc 100644 --- a/ErsatzTV/Shared/ChannelPreviewDialog.razor +++ b/ErsatzTV/Shared/ChannelPreviewDialog.razor @@ -26,11 +26,8 @@ [Parameter] public string StreamUri { get; set; } - protected override Task OnParametersSetAsync() - { - return Task.CompletedTask; - } - + protected override Task OnParametersSetAsync() => Task.CompletedTask; + protected override async Task OnAfterRenderAsync(bool firstRender) { try @@ -55,7 +52,7 @@ { // ignored } - + MudDialog.Close(DialogResult.Ok(true)); } diff --git a/ErsatzTV/Shared/EditExternalJsonFileDialog.razor b/ErsatzTV/Shared/EditExternalJsonFileDialog.razor index f8fd1a52..63aef85f 100644 --- a/ErsatzTV/Shared/EditExternalJsonFileDialog.razor +++ b/ErsatzTV/Shared/EditExternalJsonFileDialog.razor @@ -7,7 +7,7 @@ Edit the playout's external json file - + Cancel @@ -34,11 +34,8 @@ _cts.Dispose(); } - protected override void OnParametersSet() - { - _externalJsonFile = ExternalJsonFile; - } - + protected override void OnParametersSet() => _externalJsonFile = ExternalJsonFile; + private void Submit() => MudDialog.Close(DialogResult.Ok(_externalJsonFile)); private void Cancel() => MudDialog.Cancel(); diff --git a/ErsatzTV/Shared/EditImageFolderDurationDialog.razor b/ErsatzTV/Shared/EditImageFolderDurationDialog.razor index 7f0f5332..9d2d6080 100644 --- a/ErsatzTV/Shared/EditImageFolderDurationDialog.razor +++ b/ErsatzTV/Shared/EditImageFolderDurationDialog.razor @@ -8,11 +8,11 @@ + Adornment="Adornment.End" + AdornmentText="seconds" + Min="0.01" + Step="0.01" + Immediate="true"/> Cancel @@ -39,11 +39,8 @@ _cts.Dispose(); } - protected override void OnParametersSet() - { - _imageDurationSeconds = ImageFolderDuration; - } - + protected override void OnParametersSet() => _imageDurationSeconds = ImageFolderDuration; + private void Submit() => MudDialog.Close(DialogResult.Ok(_imageDurationSeconds)); private void Cancel() => MudDialog.Cancel(); diff --git a/ErsatzTV/Shared/FragmentLetterAnchor.razor b/ErsatzTV/Shared/FragmentLetterAnchor.razor index 6ce1f880..e27ed9e3 100644 --- a/ErsatzTV/Shared/FragmentLetterAnchor.razor +++ b/ErsatzTV/Shared/FragmentLetterAnchor.razor @@ -12,6 +12,7 @@ { letter = '#'; } + if (!letters.Contains(letter)) { letters.Add(letter); diff --git a/ErsatzTV/Shared/LetterBar.razor b/ErsatzTV/Shared/LetterBar.razor index e0460bb2..7637a4dc 100644 --- a/ErsatzTV/Shared/LetterBar.razor +++ b/ErsatzTV/Shared/LetterBar.razor @@ -51,6 +51,7 @@ (string key, string value) = Query.EncodeQuery(); uri = $"{uri}?{key}={value}"; } + return uri + $"#letter-{letter}"; } diff --git a/ErsatzTV/Shared/MainLayout.razor b/ErsatzTV/Shared/MainLayout.razor index ff329725..ac8485c3 100644 --- a/ErsatzTV/Shared/MainLayout.razor +++ b/ErsatzTV/Shared/MainLayout.razor @@ -46,7 +46,8 @@ @searchTarget.Name - @(searchTarget.Kind switch + @( + searchTarget.Kind switch { SearchTargetKind.Channel => "Channel", SearchTargetKind.FFmpegProfile => "FFmpeg Profile", @@ -57,7 +58,7 @@ SearchTargetKind.Schedule => "Schedule", SearchTargetKind.ScheduleItems => "Schedule Items", _ => string.Empty - }) + }) } @@ -161,7 +162,7 @@ { SystemStartup.OnDatabaseReady += OnStartupProgress; SystemStartup.OnSearchIndexReady += OnStartupProgress; - + SearchTargets.OnSearchTargetsChanged += OnSearchTargetsChanged; } @@ -169,7 +170,7 @@ { SystemStartup.OnDatabaseReady -= OnStartupProgress; SystemStartup.OnSearchIndexReady -= OnStartupProgress; - + SearchTargets.OnSearchTargetsChanged -= OnSearchTargetsChanged; _cts.Cancel(); @@ -238,10 +239,7 @@ } } - protected async void OnSearchTargetsChanged(object sender, EventArgs e) - { - _searchTargets = await Mediator.Send(new QuerySearchTargets(), _cts.Token); - } + protected async void OnSearchTargetsChanged(object sender, EventArgs e) => _searchTargets = await Mediator.Send(new QuerySearchTargets(), _cts.Token); private void PerformSearch() { @@ -264,7 +262,7 @@ } private void NavigateTo(SearchTargetViewModel searchTarget) => - // need to force smart collections to navigate since the query string is all that differs + // need to force smart collections to navigate since the query string is all that differs NavigationManager.NavigateTo(UrlFor(searchTarget), searchTarget.Kind is SearchTargetKind.SmartCollection); private string UrlFor(SearchTargetViewModel searchTarget) => @@ -280,6 +278,6 @@ SearchTargetKind.Schedule => $"schedules/{searchTarget.Id}", SearchTargetKind.ScheduleItems => $"schedules/{searchTarget.Id}/items", _ => null - }; + }; } \ No newline at end of file diff --git a/ErsatzTV/Shared/MediaCard.razor b/ErsatzTV/Shared/MediaCard.razor index 972a764b..173fc5ae 100644 --- a/ErsatzTV/Shared/MediaCard.razor +++ b/ErsatzTV/Shared/MediaCard.razor @@ -160,6 +160,6 @@ { ArtworkKind.Thumbnail => "thumbnails", _ => "posters" - }; + }; } \ No newline at end of file diff --git a/ErsatzTV/Shared/MoveLocalLibraryPathDialog.razor b/ErsatzTV/Shared/MoveLocalLibraryPathDialog.razor index 5af54ead..4bb9829e 100644 --- a/ErsatzTV/Shared/MoveLocalLibraryPathDialog.razor +++ b/ErsatzTV/Shared/MoveLocalLibraryPathDialog.razor @@ -120,7 +120,7 @@ private async Task Cancel(MouseEventArgs e) { - // this is gross, but [enter] seems to sometimes trigger cancel instead of submit + // this is gross, but [enter] seems to sometimes trigger cancel instead of submit if (e.Detail == 0) { await Submit(); diff --git a/ErsatzTV/Shared/SaveAsSmartCollectionDialog.razor b/ErsatzTV/Shared/SaveAsSmartCollectionDialog.razor index 5f6bb79d..f1bba73e 100644 --- a/ErsatzTV/Shared/SaveAsSmartCollectionDialog.razor +++ b/ErsatzTV/Shared/SaveAsSmartCollectionDialog.razor @@ -111,7 +111,7 @@ private async Task Cancel(MouseEventArgs e) { - // this is gross, but [enter] seems to sometimes trigger cancel instead of submit + // this is gross, but [enter] seems to sometimes trigger cancel instead of submit if (e.Detail == 0) { await Submit(); diff --git a/ErsatzTV/Startup.cs b/ErsatzTV/Startup.cs index a0090a6b..ff908da2 100644 --- a/ErsatzTV/Startup.cs +++ b/ErsatzTV/Startup.cs @@ -134,7 +134,7 @@ public class Startup configuration.ReleaseStage = bugsnagConfig.Enable ? "public" : "private"; #endif }); - + services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(FileSystemLayout.DataProtectionFolder)); OidcHelper.Init(Configuration); @@ -544,7 +544,7 @@ public class Startup blazor.UseAuthorization(); #pragma warning restore ASP0001 } - + blazor.UseEndpoints( endpoints => { @@ -562,7 +562,7 @@ public class Startup iptv.UseEndpoints(endpoints => endpoints.MapControllers()); }); } - + private static void CustomServices(IServiceCollection services) { services.AddSingleton(); diff --git a/ErsatzTV/Validators/RemoteMediaSourcePathReplacementEditViewModelValidator.cs b/ErsatzTV/Validators/RemoteMediaSourcePathReplacementEditViewModelValidator.cs index d5ccade5..19a6ed1f 100644 --- a/ErsatzTV/Validators/RemoteMediaSourcePathReplacementEditViewModelValidator.cs +++ b/ErsatzTV/Validators/RemoteMediaSourcePathReplacementEditViewModelValidator.cs @@ -5,7 +5,7 @@ namespace ErsatzTV.Validators; public class RemoteMediaSourcePathReplacementEditViewModelValidator : AbstractValidator< - RemoteMediaSourcePathReplacementEditViewModel> + RemoteMediaSourcePathReplacementEditViewModel> { public RemoteMediaSourcePathReplacementEditViewModelValidator() { diff --git a/ErsatzTV/ViewModels/BlockItemEditViewModel.cs b/ErsatzTV/ViewModels/BlockItemEditViewModel.cs index 27102589..7a8af307 100644 --- a/ErsatzTV/ViewModels/BlockItemEditViewModel.cs +++ b/ErsatzTV/ViewModels/BlockItemEditViewModel.cs @@ -10,11 +10,9 @@ public class BlockItemEditViewModel : INotifyPropertyChanged { private ProgramScheduleItemCollectionType _collectionType; - public event PropertyChangedEventHandler PropertyChanged; - public int Id { get; set; } public int Index { get; set; } - + public ProgramScheduleItemCollectionType CollectionType { get => _collectionType; @@ -46,7 +44,7 @@ public class BlockItemEditViewModel : INotifyPropertyChanged public MultiCollectionViewModel MultiCollection { get; set; } public SmartCollectionViewModel SmartCollection { get; set; } public NamedMediaItemViewModel MediaItem { get; set; } - + public string CollectionName => CollectionType switch { ProgramScheduleItemCollectionType.Collection => Collection?.Name, @@ -59,17 +57,21 @@ public class BlockItemEditViewModel : INotifyPropertyChanged }; public PlaybackOrder PlaybackOrder { get; set; } - + public bool IncludeInProgramGuide { get; set; } - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) - { + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } protected bool SetField(ref T field, T value, [CallerMemberName] string propertyName = null) { - if (EqualityComparer.Default.Equals(field, value)) return false; + if (EqualityComparer.Default.Equals(field, value)) + { + return false; + } + field = value; OnPropertyChanged(propertyName); return true; diff --git a/ErsatzTV/ViewModels/BlockTreeItemViewModel.cs b/ErsatzTV/ViewModels/BlockTreeItemViewModel.cs index 77fe69eb..9e7afc85 100644 --- a/ErsatzTV/ViewModels/BlockTreeItemViewModel.cs +++ b/ErsatzTV/ViewModels/BlockTreeItemViewModel.cs @@ -37,18 +37,18 @@ public class BlockTreeItemViewModel CanExpand = false; BlockId = block.Id; } - + public string Text { get; } - + public string EndText { get; } - + public string Icon { get; } - + public bool CanExpand { get; } - + public int? BlockId { get; } - + public int? BlockGroupId { get; } - + public S.HashSet TreeItems { get; } } diff --git a/ErsatzTV/ViewModels/ImageTreeItemViewModel.cs b/ErsatzTV/ViewModels/ImageTreeItemViewModel.cs index d96a396d..c84d71cc 100644 --- a/ErsatzTV/ViewModels/ImageTreeItemViewModel.cs +++ b/ErsatzTV/ViewModels/ImageTreeItemViewModel.cs @@ -7,7 +7,7 @@ namespace ErsatzTV.ViewModels; public class ImageTreeItemViewModel { private readonly string _imageCount; - + public ImageTreeItemViewModel(ImageFolderViewModel imageFolder) { LibraryFolderId = imageFolder.LibraryFolderId; @@ -34,18 +34,18 @@ public class ImageTreeItemViewModel } public string Text { get; } - + public string EndText { get; private set; } public string FullPath { get; } - + public string Icon { get; } - + public int LibraryFolderId { get; } public double? ImageFolderDuration { get; private set; } - + public bool CanExpand { get; } - + public S.HashSet TreeItems { get; } public void UpdateDuration(double? imageFolderDuration) @@ -53,7 +53,7 @@ public class ImageTreeItemViewModel ImageFolderDuration = imageFolderDuration; string duration = string.Empty; - + foreach (double durationSeconds in Optional(imageFolderDuration)) { duration = durationSeconds switch diff --git a/ErsatzTV/ViewModels/TemplateItemEditViewModel.cs b/ErsatzTV/ViewModels/TemplateItemEditViewModel.cs index 18b75b95..0f001826 100644 --- a/ErsatzTV/ViewModels/TemplateItemEditViewModel.cs +++ b/ErsatzTV/ViewModels/TemplateItemEditViewModel.cs @@ -16,7 +16,7 @@ public class TemplateItemEditViewModel : CalendarItem Text = value; } } - + public DateTime LastStart { get; set; } public DateTime? LastEnd { get; set; } } diff --git a/ErsatzTV/ViewModels/TemplateTreeItemViewModel.cs b/ErsatzTV/ViewModels/TemplateTreeItemViewModel.cs index 764266ec..70bdd02e 100644 --- a/ErsatzTV/ViewModels/TemplateTreeItemViewModel.cs +++ b/ErsatzTV/ViewModels/TemplateTreeItemViewModel.cs @@ -22,16 +22,16 @@ public class TemplateTreeItemViewModel CanExpand = false; TemplateId = template.Id; } - + public string Text { get; } - + public string Icon { get; } - + public bool CanExpand { get; } - + public int? TemplateId { get; } - + public int? TemplateGroupId { get; } - + public S.HashSet TreeItems { get; } }