From 6dc61a430ba3a8480399309f277e5debfd6403ba Mon Sep 17 00:00:00 2001 From: Marc Brooks Date: Mon, 15 May 2023 00:38:27 -0500 Subject: Sort embedded collections in Nfo files Because the Nfo files emit the collections as they are in-memory, the files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change. In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too. Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers) BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name) AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name) ArtistNfo: Albums (by Production Year>SortName>Name) MovieNfo: Artists Fix Debug build lint Fix CI debug build lint issue. Fix review issues Fixed debug-build lint issues. Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero. Removed the exception filtering I put in for testing. Don't emit actors for MusicAlbums or MusicArtists Swap from String.Trimmed() to ?.Trim() Addressing PR feedback Can't use ReadOnlySpan in an async method Removed now-unused namespace --- .../Probing/ProbeResultNormalizer.cs | 34 ++++++++++++---------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 334796f58..0dee77db8 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -10,7 +10,9 @@ using System.Text.RegularExpressions; using System.Xml; using Jellyfin.Data.Enums; using Jellyfin.Extensions; +using MediaBrowser.Controller.Extensions; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; @@ -531,42 +533,44 @@ namespace MediaBrowser.MediaEncoding.Probing private void ProcessPairs(string key, List pairs, MediaInfo info) { List peoples = new List(); + var distinctPairs = pairs.Select(p => p.Value) + .Where(i => !string.IsNullOrWhiteSpace(i)) + .Trimmed() + .Distinct(StringComparer.OrdinalIgnoreCase); + if (string.Equals(key, "studio", StringComparison.OrdinalIgnoreCase)) { - info.Studios = pairs.Select(p => p.Value) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToArray(); + info.Studios = distinctPairs.ToArray(); } else if (string.Equals(key, "screenwriters", StringComparison.OrdinalIgnoreCase)) { - foreach (var pair in pairs) + foreach (var pair in distinctPairs) { peoples.Add(new BaseItemPerson { - Name = pair.Value, + Name = pair, Type = PersonKind.Writer }); } } else if (string.Equals(key, "producers", StringComparison.OrdinalIgnoreCase)) { - foreach (var pair in pairs) + foreach (var pair in distinctPairs) { peoples.Add(new BaseItemPerson { - Name = pair.Value, + Name = pair, Type = PersonKind.Producer }); } } else if (string.Equals(key, "directors", StringComparison.OrdinalIgnoreCase)) { - foreach (var pair in pairs) + foreach (var pair in distinctPairs) { peoples.Add(new BaseItemPerson { - Name = pair.Value, + Name = pair, Type = PersonKind.Director }); } @@ -591,10 +595,10 @@ namespace MediaBrowser.MediaEncoding.Probing switch (reader.Name) { case "key": - name = reader.ReadElementContentAsString(); + name = reader.ReadNormalizedString(); break; case "string": - value = reader.ReadElementContentAsString(); + value = reader.ReadNormalizedString(); break; default: reader.Skip(); @@ -607,8 +611,8 @@ namespace MediaBrowser.MediaEncoding.Probing } } - if (string.IsNullOrWhiteSpace(name) - || string.IsNullOrWhiteSpace(value)) + if (string.IsNullOrEmpty(name) + || string.IsNullOrEmpty(value)) { return null; } @@ -1453,7 +1457,7 @@ namespace MediaBrowser.MediaEncoding.Probing var genres = new List(info.Genres); foreach (var genre in Split(genreVal, true)) { - if (string.IsNullOrWhiteSpace(genre)) + if (string.IsNullOrEmpty(genre)) { continue; } -- cgit v1.2.3 From 0fc288936d10afc146780d118361f2e722768ee6 Mon Sep 17 00:00:00 2001 From: gnattu Date: Mon, 9 Dec 2024 16:17:49 +0800 Subject: Enable VideoToolbox AV1 decode This decoder differs from others provided by VideoToolbox in that it lacks any software fallback. To achieve consistent behavior with other VideoToolbox decoders, this PR implemented additional checking on the server to simulate the software fallback provided by VideoToolbox. The current fallback checking mechanism is a temporary solution. In the long term, it should be replaced with a more capable hardware capability checking system. --- .../MediaEncoding/EncodingHelper.cs | 8 ++ .../MediaEncoding/IMediaEncoder.cs | 6 ++ .../Encoder/ApplePlatformHelper.cs | 85 ++++++++++++++++++++++ .../Encoder/EncoderValidator.cs | 5 ++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 10 +++ 5 files changed, 114 insertions(+) create mode 100644 MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 9399679a4..7dea5f8eb 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -6610,6 +6610,7 @@ namespace MediaBrowser.Controller.MediaEncoding || string.Equals("yuv420p12le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase) || string.Equals("yuv422p12le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase) || string.Equals("yuv444p12le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); + var isAv1SupportedSwFormatsVt = is8_10bitSwFormatsVt || string.Equals("yuv420p12le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); // The related patches make videotoolbox hardware surface working is only available in jellyfin-ffmpeg 7.0.1 at the moment. bool useHwSurface = (_mediaEncoder.EncoderVersion >= _minFFmpegWorkingVtHwSurface) && IsVideoToolboxFullSupported(); @@ -6643,6 +6644,13 @@ namespace MediaBrowser.Controller.MediaEncoding { return GetHwaccelType(state, options, "hevc", bitDepth, useHwSurface); } + + if (string.Equals("av1", videoStream.Codec, StringComparison.OrdinalIgnoreCase) + && isAv1SupportedSwFormatsVt + && _mediaEncoder.IsVideoToolboxAv1DecodeAvailable) + { + return GetHwaccelType(state, options, "av1", bitDepth, useHwSurface); + } } return null; diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index c767b4a51..a60f52340 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -75,6 +75,12 @@ namespace MediaBrowser.Controller.MediaEncoding /// true if the Vaapi device supports vulkan drm interop, false otherwise. bool IsVaapiDeviceSupportVulkanDrmInterop { get; } + /// + /// Gets a value indicating whether av1 decoding is available via VideoToolbox. + /// + /// true if the av1 is available via VideoToolbox, false otherwise. + bool IsVideoToolboxAv1DecodeAvailable { get; } + /// /// Whether given encoder codec is supported. /// diff --git a/MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs b/MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs new file mode 100644 index 000000000..ea2289bd7 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs @@ -0,0 +1,85 @@ +#pragma warning disable CA1031 + +using System; +using System.Linq; +using System.Runtime.InteropServices; +using Microsoft.Extensions.Logging; + +namespace MediaBrowser.MediaEncoding.Encoder; + +/// +/// Helper class for Apple platform specific operations. +/// +public static class ApplePlatformHelper +{ + private static readonly string[] _av1DecodeBlacklistedCpuClass = ["M1", "M2"]; + + private static string GetSysctlValue(string name) + { + IntPtr length = IntPtr.Zero; + // Get length of the value + int osStatus = SysctlByName(name, IntPtr.Zero, ref length, IntPtr.Zero, 0); + + if (osStatus != 0) + { + throw new NotSupportedException($"Failed to get sysctl value for {name} with error {osStatus}"); + } + + IntPtr buffer = Marshal.AllocHGlobal(length.ToInt32()); + try + { + osStatus = SysctlByName(name, buffer, ref length, IntPtr.Zero, 0); + if (osStatus != 0) + { + throw new NotSupportedException($"Failed to get sysctl value for {name} with error {osStatus}"); + } + + return Marshal.PtrToStringAnsi(buffer) ?? string.Empty; + } + finally + { + Marshal.FreeHGlobal(buffer); + } + } + + private static int SysctlByName(string name, IntPtr oldp, ref IntPtr oldlenp, IntPtr newp, uint newlen) + { + return NativeMethods.SysctlByName(System.Text.Encoding.ASCII.GetBytes(name), oldp, ref oldlenp, newp, newlen); + } + + /// + /// Check if the current system has hardware acceleration for AV1 decoding. + /// + /// The logger used for error logging. + /// Boolean indicates the hwaccel support. + public static bool HasAv1HardwareAccel(ILogger logger) + { + if (!RuntimeInformation.OSArchitecture.Equals(Architecture.Arm64)) + { + return false; + } + + try + { + string cpuBrandString = GetSysctlValue("machdep.cpu.brand_string"); + return !_av1DecodeBlacklistedCpuClass.Any(blacklistedCpuClass => cpuBrandString.Contains(blacklistedCpuClass, StringComparison.OrdinalIgnoreCase)); + } + catch (NotSupportedException e) + { + logger.LogError("Error getting CPU brand string: {Message}", e.Message); + } + catch (Exception e) + { + logger.LogError("Unknown error occured: {Exception}", e); + } + + return false; + } + + private static class NativeMethods + { + [DllImport("libc", EntryPoint = "sysctlbyname", SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] + internal static extern int SysctlByName(byte[] name, IntPtr oldp, ref IntPtr oldlenp, IntPtr newp, uint newlen); + } +} diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 23d9ca7ef..776b2ab42 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -437,6 +437,11 @@ namespace MediaBrowser.MediaEncoding.Encoder } } + public bool CheckIsVideoToolboxAv1DecodeAvailable() + { + return ApplePlatformHelper.HasAv1HardwareAccel(_logger); + } + private IEnumerable GetHwaccelTypes() { string? output = null; diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index a34238cd6..44b38f03b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -83,6 +83,8 @@ namespace MediaBrowser.MediaEncoding.Encoder private bool _isVaapiDeviceSupportVulkanDrmModifier = false; private bool _isVaapiDeviceSupportVulkanDrmInterop = false; + private bool _isVideoToolboxAv1DecodeAvailable = false; + private static string[] _vulkanImageDrmFmtModifierExts = { "VK_EXT_image_drm_format_modifier", @@ -153,6 +155,8 @@ namespace MediaBrowser.MediaEncoding.Encoder /// public bool IsVaapiDeviceSupportVulkanDrmInterop => _isVaapiDeviceSupportVulkanDrmInterop; + public bool IsVideoToolboxAv1DecodeAvailable => _isVideoToolboxAv1DecodeAvailable; + [GeneratedRegex(@"[^\/\\]+?(\.[^\/\\\n.]+)?$")] private static partial Regex FfprobePathRegex(); @@ -255,6 +259,12 @@ namespace MediaBrowser.MediaEncoding.Encoder _logger.LogInformation("VAAPI device {RenderNodePath} supports Vulkan DRM interop", options.VaapiDevice); } } + + // Check if VideoToolbox supports AV1 decode + if (OperatingSystem.IsMacOS() && SupportsHwaccel("videotoolbox")) + { + _isVideoToolboxAv1DecodeAvailable = validator.CheckIsVideoToolboxAv1DecodeAvailable(); + } } _logger.LogInformation("FFmpeg: {FfmpegPath}", _ffmpegPath ?? string.Empty); -- cgit v1.2.3 From aa811eb1e3c78bdf8f4a751311c1bb6d639e851e Mon Sep 17 00:00:00 2001 From: JPVenson Date: Sun, 26 Jan 2025 20:45:28 +0000 Subject: Prepared Seperation of Database components for future multi provider support --- .devcontainer/devcontainer.json | 14 + Directory.Packages.props | 1 + .../Emby.Server.Implementations.csproj | 1 + .../HttpServer/Security/AuthService.cs | 1 + .../Library/LibraryManager.cs | 1 + .../Library/MediaSourceManager.cs | 1 + .../Library/UserViewManager.cs | 1 + .../ScheduledTasks/Tasks/OptimizeDatabaseTask.cs | 21 +- .../Session/SessionManager.cs | 1 + Emby.Server.Implementations/TV/TVSeriesManager.cs | 1 + Jellyfin.Api/Auth/CustomAuthenticationHandler.cs | 1 + .../DefaultAuthorizationHandler.cs | 1 + .../UserPermissionPolicy/UserPermissionHandler.cs | 1 + Jellyfin.Api/Controllers/ItemsController.cs | 1 + Jellyfin.Api/Controllers/UserController.cs | 1 + Jellyfin.Api/Helpers/MediaInfoHelper.cs | 1 + .../ActivityLogWebSocketListener.cs | 1 + .../SessionInfoWebSocketListener.cs | 1 + Jellyfin.Data/Entities/AccessSchedule.cs | 62 - Jellyfin.Data/Entities/ActivityLog.cs | 123 -- Jellyfin.Data/Entities/AncestorId.cs | 29 - Jellyfin.Data/Entities/AttachmentStreamInfo.cs | 49 - Jellyfin.Data/Entities/BaseItemEntity.cs | 186 --- Jellyfin.Data/Entities/BaseItemExtraType.cs | 18 - Jellyfin.Data/Entities/BaseItemImageInfo.cs | 59 - Jellyfin.Data/Entities/BaseItemMetadataField.cs | 24 - Jellyfin.Data/Entities/BaseItemProvider.cs | 32 - Jellyfin.Data/Entities/BaseItemTrailerType.cs | 24 - Jellyfin.Data/Entities/Chapter.cs | 44 - .../Entities/CustomItemDisplayPreferences.cs | 80 - Jellyfin.Data/Entities/DisplayPreferences.cs | 150 -- Jellyfin.Data/Entities/Group.cs | 80 - Jellyfin.Data/Entities/HomeSection.cs | 44 - Jellyfin.Data/Entities/ImageInfo.cs | 54 - Jellyfin.Data/Entities/ImageInfoImageType.cs | 76 - Jellyfin.Data/Entities/ItemDisplayPreferences.cs | 113 -- Jellyfin.Data/Entities/ItemValue.cs | 37 - Jellyfin.Data/Entities/ItemValueMap.cs | 30 - Jellyfin.Data/Entities/ItemValueType.cs | 38 - Jellyfin.Data/Entities/Libraries/Artwork.cs | 64 - Jellyfin.Data/Entities/Libraries/Book.cs | 29 - Jellyfin.Data/Entities/Libraries/BookMetadata.cs | 34 - Jellyfin.Data/Entities/Libraries/Chapter.cs | 80 - Jellyfin.Data/Entities/Libraries/Collection.cs | 57 - Jellyfin.Data/Entities/Libraries/CollectionItem.cs | 64 - Jellyfin.Data/Entities/Libraries/Company.cs | 54 - .../Entities/Libraries/CompanyMetadata.cs | 59 - Jellyfin.Data/Entities/Libraries/CustomItem.cs | 29 - .../Entities/Libraries/CustomItemMetadata.cs | 17 - Jellyfin.Data/Entities/Libraries/Episode.cs | 34 - .../Entities/Libraries/EpisodeMetadata.cs | 49 - Jellyfin.Data/Entities/Libraries/Genre.cs | 50 - Jellyfin.Data/Entities/Libraries/ItemMetadata.cs | 141 -- Jellyfin.Data/Entities/Libraries/Library.cs | 60 - Jellyfin.Data/Entities/Libraries/LibraryItem.cs | 55 - Jellyfin.Data/Entities/Libraries/MediaFile.cs | 72 - .../Entities/Libraries/MediaFileStream.cs | 50 - .../Entities/Libraries/MetadataProvider.cs | 53 - .../Entities/Libraries/MetadataProviderId.cs | 63 - Jellyfin.Data/Entities/Libraries/Movie.cs | 29 - Jellyfin.Data/Entities/Libraries/MovieMetadata.cs | 70 - Jellyfin.Data/Entities/Libraries/MusicAlbum.cs | 30 - .../Entities/Libraries/MusicAlbumMetadata.cs | 56 - Jellyfin.Data/Entities/Libraries/Person.cs | 89 -- Jellyfin.Data/Entities/Libraries/PersonRole.cs | 80 - Jellyfin.Data/Entities/Libraries/Photo.cs | 29 - Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs | 17 - Jellyfin.Data/Entities/Libraries/Rating.cs | 59 - Jellyfin.Data/Entities/Libraries/RatingSource.cs | 73 - Jellyfin.Data/Entities/Libraries/Release.cs | 67 - Jellyfin.Data/Entities/Libraries/Season.cs | 35 - Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs | 29 - Jellyfin.Data/Entities/Libraries/Series.cs | 46 - Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs | 70 - Jellyfin.Data/Entities/Libraries/Track.cs | 34 - Jellyfin.Data/Entities/Libraries/TrackMetadata.cs | 17 - Jellyfin.Data/Entities/MediaSegment.cs | 42 - Jellyfin.Data/Entities/MediaStreamInfo.cs | 103 -- Jellyfin.Data/Entities/MediaStreamTypeEntity.cs | 37 - Jellyfin.Data/Entities/People.cs | 32 - Jellyfin.Data/Entities/PeopleBaseItemMap.cs | 44 - Jellyfin.Data/Entities/Permission.cs | 68 - Jellyfin.Data/Entities/Preference.cs | 68 - Jellyfin.Data/Entities/ProgramAudioEntity.cs | 37 - Jellyfin.Data/Entities/Security/ApiKey.cs | 56 - Jellyfin.Data/Entities/Security/Device.cs | 107 -- Jellyfin.Data/Entities/Security/DeviceOptions.cs | 35 - Jellyfin.Data/Entities/TrickplayInfo.cs | 75 - Jellyfin.Data/Entities/User.cs | 534 ------- Jellyfin.Data/Entities/UserData.cs | 92 -- Jellyfin.Data/Enums/ArtKind.cs | 33 - Jellyfin.Data/Enums/ChromecastVersion.cs | 18 - Jellyfin.Data/Enums/DynamicDayOfWeek.cs | 58 - Jellyfin.Data/Enums/HomeSectionType.cs | 58 - Jellyfin.Data/Enums/IndexingKind.cs | 23 - Jellyfin.Data/Enums/MediaFileKind.cs | 33 - Jellyfin.Data/Enums/MediaSegmentType.cs | 39 - Jellyfin.Data/Enums/PermissionKind.cs | 128 -- Jellyfin.Data/Enums/PersonRoleType.cs | 68 - Jellyfin.Data/Enums/PreferenceKind.cs | 73 - Jellyfin.Data/Enums/ScrollDirection.cs | 18 - Jellyfin.Data/Enums/SortOrder.cs | 18 - Jellyfin.Data/Enums/SubtitlePlaybackMode.cs | 33 - Jellyfin.Data/Enums/SyncPlayUserAccessType.cs | 23 - Jellyfin.Data/Enums/ViewType.cs | 113 -- Jellyfin.Data/Interfaces/IHasArtwork.cs | 16 - Jellyfin.Data/Interfaces/IHasCompanies.cs | 16 - Jellyfin.Data/Interfaces/IHasConcurrencyToken.cs | 18 - Jellyfin.Data/Interfaces/IHasPermissions.cs | 31 - Jellyfin.Data/Interfaces/IHasReleases.cs | 16 - Jellyfin.Data/Jellyfin.Data.csproj | 4 + Jellyfin.Data/UserEntityExtensions.cs | 220 +++ .../Entities/AccessSchedule.cs | 62 + .../Entities/ActivityLog.cs | 123 ++ .../Entities/AncestorId.cs | 29 + .../Entities/AttachmentStreamInfo.cs | 49 + .../Entities/BaseItemEntity.cs | 186 +++ .../Entities/BaseItemExtraType.cs | 18 + .../Entities/BaseItemImageInfo.cs | 59 + .../Entities/BaseItemMetadataField.cs | 24 + .../Entities/BaseItemProvider.cs | 32 + .../Entities/BaseItemTrailerType.cs | 24 + .../Entities/Chapter.cs | 44 + .../Entities/CustomItemDisplayPreferences.cs | 80 + .../Entities/DisplayPreferences.cs | 150 ++ .../Entities/Group.cs | 68 + .../Entities/HomeSection.cs | 44 + .../Entities/ImageInfo.cs | 54 + .../Entities/ImageInfoImageType.cs | 76 + .../Entities/ItemDisplayPreferences.cs | 113 ++ .../Entities/ItemValue.cs | 37 + .../Entities/ItemValueMap.cs | 30 + .../Entities/ItemValueType.cs | 38 + .../Entities/Libraries/Artwork.cs | 64 + .../Entities/Libraries/Book.cs | 29 + .../Entities/Libraries/BookMetadata.cs | 34 + .../Entities/Libraries/Chapter.cs | 80 + .../Entities/Libraries/Collection.cs | 57 + .../Entities/Libraries/CollectionItem.cs | 64 + .../Entities/Libraries/Company.cs | 54 + .../Entities/Libraries/CompanyMetadata.cs | 59 + .../Entities/Libraries/CustomItem.cs | 29 + .../Entities/Libraries/CustomItemMetadata.cs | 17 + .../Entities/Libraries/Episode.cs | 34 + .../Entities/Libraries/EpisodeMetadata.cs | 49 + .../Entities/Libraries/Genre.cs | 50 + .../Entities/Libraries/ItemMetadata.cs | 141 ++ .../Entities/Libraries/Library.cs | 60 + .../Entities/Libraries/LibraryItem.cs | 55 + .../Entities/Libraries/MediaFile.cs | 72 + .../Entities/Libraries/MediaFileStream.cs | 50 + .../Entities/Libraries/MetadataProvider.cs | 53 + .../Entities/Libraries/MetadataProviderId.cs | 63 + .../Entities/Libraries/Movie.cs | 29 + .../Entities/Libraries/MovieMetadata.cs | 70 + .../Entities/Libraries/MusicAlbum.cs | 30 + .../Entities/Libraries/MusicAlbumMetadata.cs | 56 + .../Entities/Libraries/Person.cs | 89 ++ .../Entities/Libraries/PersonRole.cs | 80 + .../Entities/Libraries/Photo.cs | 29 + .../Entities/Libraries/PhotoMetadata.cs | 17 + .../Entities/Libraries/Rating.cs | 59 + .../Entities/Libraries/RatingSource.cs | 73 + .../Entities/Libraries/Release.cs | 67 + .../Entities/Libraries/Season.cs | 35 + .../Entities/Libraries/SeasonMetadata.cs | 29 + .../Entities/Libraries/Series.cs | 46 + .../Entities/Libraries/SeriesMetadata.cs | 70 + .../Entities/Libraries/Track.cs | 34 + .../Entities/Libraries/TrackMetadata.cs | 17 + .../Entities/MediaSegment.cs | 42 + .../Entities/MediaStreamInfo.cs | 103 ++ .../Entities/MediaStreamTypeEntity.cs | 37 + .../Entities/People.cs | 32 + .../Entities/PeopleBaseItemMap.cs | 44 + .../Entities/Permission.cs | 68 + .../Entities/Preference.cs | 68 + .../Entities/ProgramAudioEntity.cs | 37 + .../Entities/Security/ApiKey.cs | 56 + .../Entities/Security/Device.cs | 107 ++ .../Entities/Security/DeviceOptions.cs | 35 + .../Entities/TrickplayInfo.cs | 75 + .../Entities/User.cs | 338 ++++ .../Entities/UserData.cs | 92 ++ .../Enums/ArtKind.cs | 33 + .../Enums/ChromecastVersion.cs | 18 + .../Enums/DynamicDayOfWeek.cs | 58 + .../Enums/HomeSectionType.cs | 58 + .../Enums/IndexingKind.cs | 23 + .../Enums/MediaFileKind.cs | 33 + .../Enums/MediaSegmentType.cs | 39 + .../Enums/PermissionKind.cs | 128 ++ .../Enums/PersonRoleType.cs | 68 + .../Enums/PreferenceKind.cs | 73 + .../Enums/ScrollDirection.cs | 18 + .../Enums/SortOrder.cs | 18 + .../Enums/SubtitlePlaybackMode.cs | 33 + .../Enums/SyncPlayUserAccessType.cs | 23 + .../Enums/ViewType.cs | 113 ++ .../IJellyfinDatabaseProvider.cs | 31 + .../Interfaces/IHasArtwork.cs | 16 + .../Interfaces/IHasCompanies.cs | 16 + .../Interfaces/IHasConcurrencyToken.cs | 18 + .../Interfaces/IHasPermissions.cs | 17 + .../Interfaces/IHasReleases.cs | 16 + .../Jellyfin.Database.Implementations.csproj | 43 + .../JellyfinDatabaseProviderKeyAttribute.cs | 29 + .../JellyfinDbContext.cs | 275 ++++ .../ModelConfiguration/ActivityLogConfiguration.cs | 17 + .../ModelConfiguration/AncestorIdConfiguration.cs | 21 + .../ModelConfiguration/ApiKeyConfiguration.cs | 20 + .../AttachmentStreamInfoConfiguration.cs | 17 + .../ModelConfiguration/BaseItemConfiguration.cs | 57 + .../BaseItemMetadataFieldConfiguration.cs | 18 + .../BaseItemProviderConfiguration.cs | 20 + .../BaseItemTrailerTypeConfiguration.cs | 18 + .../ModelConfiguration/ChapterConfiguration.cs | 19 + .../CustomItemDisplayPreferencesConfiguration.cs | 20 + .../ModelConfiguration/DeviceConfiguration.cs | 28 + .../DeviceOptionsConfiguration.cs | 20 + .../DisplayPreferencesConfiguration.cs | 25 + .../ModelConfiguration/ItemValuesConfiguration.cs | 19 + .../ItemValuesMapConfiguration.cs | 20 + .../MediaStreamInfoConfiguration.cs | 22 + .../PeopleBaseItemMapConfiguration.cs | 22 + .../ModelConfiguration/PeopleConfiguration.cs | 20 + .../ModelConfiguration/PermissionConfiguration.cs | 24 + .../ModelConfiguration/PreferenceConfiguration.cs | 21 + .../TrickplayInfoConfiguration.cs | 18 + .../ModelConfiguration/UserConfiguration.cs | 56 + .../ModelConfiguration/UserDataConfiguration.cs | 23 + .../Jellyfin.Database.Providers.PgSql.csproj | 51 + .../Jellyfin.Database.Providers.SqLite.csproj | 51 + .../20200514181226_AddActivityLog.Designer.cs | 72 + .../Migrations/20200514181226_AddActivityLog.cs | 46 + .../Migrations/20200613202153_AddUsers.Designer.cs | 312 ++++ .../Migrations/20200613202153_AddUsers.cs | 197 +++ ...0200728005145_AddDisplayPreferences.Designer.cs | 459 ++++++ .../20200728005145_AddDisplayPreferences.cs | 132 ++ ...05220533_FixDisplayPreferencesIndex.Designer.cs | 461 ++++++ .../20200905220533_FixDisplayPreferencesIndex.cs | 51 + ...20201004171403_AddMaxActiveSessions.Designer.cs | 464 ++++++ .../20201004171403_AddMaxActiveSessions.cs | 28 + ...4223655_AddCustomDisplayPreferences.Designer.cs | 522 +++++++ .../20201204223655_AddCustomDisplayPreferences.cs | 108 ++ ...10320181425_AddIndexesAndCollations.Designer.cs | 535 +++++++ .../20210320181425_AddIndexesAndCollations.cs | 240 +++ ...10407110544_NullableCustomPrefValue.Designer.cs | 520 +++++++ .../20210407110544_NullableCustomPrefValue.cs | 35 + .../20210814002109_AddDevices.Designer.cs | 653 ++++++++ .../Migrations/20210814002109_AddDevices.cs | 128 ++ ...052_AddIndexActivityLogsDateCreated.Designer.cs | 657 ++++++++ ...221022080052_AddIndexActivityLogsDateCreated.cs | 28 + .../20230526173516_RemoveEasyPassword.Designer.cs | 650 ++++++++ .../20230526173516_RemoveEasyPassword.cs | 164 ++ .../20230626233818_AddTrickplayInfos.Designer.cs | 681 +++++++++ .../Migrations/20230626233818_AddTrickplayInfos.cs | 40 + .../20230923170422_UserCastReceiver.Designer.cs | 654 ++++++++ .../Migrations/20230923170422_UserCastReceiver.cs | 29 + .../20240729140605_AddMediaSegments.Designer.cs | 708 +++++++++ .../Migrations/20240729140605_AddMediaSegments.cs | 38 + ...30_MarkSegmentProviderIdNonNullable.Designer.cs | 712 +++++++++ ...40928082930_MarkSegmentProviderIdNonNullable.cs | 36 + .../20241020103111_LibraryDbMigration.Designer.cs | 1607 +++++++++++++++++++ .../20241020103111_LibraryDbMigration.cs | 639 ++++++++ .../20241111131257_AddedCustomDataKey.Designer.cs | 1610 ++++++++++++++++++++ .../20241111131257_AddedCustomDataKey.cs | 28 + ...0241111135439_AddedCustomDataKeyKey.Designer.cs | 1610 ++++++++++++++++++++ .../20241111135439_AddedCustomDataKeyKey.cs | 54 + .../20241112152323_FixAncestorIdConfig.Designer.cs | 1603 +++++++++++++++++++ .../20241112152323_FixAncestorIdConfig.cs | 49 + .../20241112232041_fixMediaStreams.Designer.cs | 1600 +++++++++++++++++++ .../Migrations/20241112232041_fixMediaStreams.cs | 702 +++++++++ .../20241112234144_FixMediaStreams2.Designer.cs | 1594 +++++++++++++++++++ .../Migrations/20241112234144_FixMediaStreams2.cs | 144 ++ ...241113133548_EnforceUniqueItemValue.Designer.cs | 1595 +++++++++++++++++++ .../20241113133548_EnforceUniqueItemValue.cs | 37 + .../Migrations/DesignTimeJellyfinDbFactory.cs | 25 + .../Migrations/JellyfinDbModelSnapshot.cs | 1592 +++++++++++++++++++ .../SqliteDatabaseProvider.cs | 78 + .../DatabaseConfigurationFactory.cs | 17 + .../DatabaseConfigurationOptions.cs | 14 + .../DbConfiguration/DatabaseConfigurationStore.cs | 25 + .../Devices/DeviceManager.cs | 1 + .../Extensions/ServiceCollectionExtensions.cs | 54 +- .../Jellyfin.Server.Implementations.csproj | 10 +- .../JellyfinDbContext.cs | 274 ---- .../20200514181226_AddActivityLog.Designer.cs | 72 - .../Migrations/20200514181226_AddActivityLog.cs | 46 - .../Migrations/20200613202153_AddUsers.Designer.cs | 312 ---- .../Migrations/20200613202153_AddUsers.cs | 197 --- ...0200728005145_AddDisplayPreferences.Designer.cs | 459 ------ .../20200728005145_AddDisplayPreferences.cs | 132 -- ...05220533_FixDisplayPreferencesIndex.Designer.cs | 461 ------ .../20200905220533_FixDisplayPreferencesIndex.cs | 51 - ...20201004171403_AddMaxActiveSessions.Designer.cs | 464 ------ .../20201004171403_AddMaxActiveSessions.cs | 28 - ...4223655_AddCustomDisplayPreferences.Designer.cs | 522 ------- .../20201204223655_AddCustomDisplayPreferences.cs | 108 -- ...10320181425_AddIndexesAndCollations.Designer.cs | 535 ------- .../20210320181425_AddIndexesAndCollations.cs | 240 --- ...10407110544_NullableCustomPrefValue.Designer.cs | 520 ------- .../20210407110544_NullableCustomPrefValue.cs | 35 - .../20210814002109_AddDevices.Designer.cs | 653 -------- .../Migrations/20210814002109_AddDevices.cs | 128 -- ...052_AddIndexActivityLogsDateCreated.Designer.cs | 657 -------- ...221022080052_AddIndexActivityLogsDateCreated.cs | 28 - .../20230526173516_RemoveEasyPassword.Designer.cs | 650 -------- .../20230526173516_RemoveEasyPassword.cs | 164 -- .../20230626233818_AddTrickplayInfos.Designer.cs | 681 --------- .../Migrations/20230626233818_AddTrickplayInfos.cs | 40 - .../20230923170422_UserCastReceiver.Designer.cs | 654 -------- .../Migrations/20230923170422_UserCastReceiver.cs | 29 - .../20240729140605_AddMediaSegments.Designer.cs | 708 --------- .../Migrations/20240729140605_AddMediaSegments.cs | 38 - ...30_MarkSegmentProviderIdNonNullable.Designer.cs | 712 --------- ...40928082930_MarkSegmentProviderIdNonNullable.cs | 36 - .../20241020103111_LibraryDbMigration.Designer.cs | 1607 ------------------- .../20241020103111_LibraryDbMigration.cs | 639 -------- .../20241111131257_AddedCustomDataKey.Designer.cs | 1610 -------------------- .../20241111131257_AddedCustomDataKey.cs | 28 - ...0241111135439_AddedCustomDataKeyKey.Designer.cs | 1610 -------------------- .../20241111135439_AddedCustomDataKeyKey.cs | 54 - .../20241112152323_FixAncestorIdConfig.Designer.cs | 1603 ------------------- .../20241112152323_FixAncestorIdConfig.cs | 49 - .../20241112232041_fixMediaStreams.Designer.cs | 1600 ------------------- .../Migrations/20241112232041_fixMediaStreams.cs | 702 --------- .../20241112234144_FixMediaStreams2.Designer.cs | 1594 ------------------- .../Migrations/20241112234144_FixMediaStreams2.cs | 144 -- ...241113133548_EnforceUniqueItemValue.Designer.cs | 1595 ------------------- .../20241113133548_EnforceUniqueItemValue.cs | 37 - .../Migrations/DesignTimeJellyfinDbFactory.cs | 21 - .../Migrations/JellyfinDbModelSnapshot.cs | 1592 ------------------- .../ModelConfiguration/ActivityLogConfiguration.cs | 17 - .../ModelConfiguration/AncestorIdConfiguration.cs | 21 - .../ModelConfiguration/ApiKeyConfiguration.cs | 20 - .../AttachmentStreamInfoConfiguration.cs | 17 - .../ModelConfiguration/BaseItemConfiguration.cs | 59 - .../BaseItemMetadataFieldConfiguration.cs | 22 - .../BaseItemProviderConfiguration.cs | 20 - .../BaseItemTrailerTypeConfiguration.cs | 22 - .../ModelConfiguration/ChapterConfiguration.cs | 19 - .../CustomItemDisplayPreferencesConfiguration.cs | 20 - .../ModelConfiguration/DeviceConfiguration.cs | 28 - .../DeviceOptionsConfiguration.cs | 20 - .../DisplayPreferencesConfiguration.cs | 25 - .../ModelConfiguration/ItemValuesConfiguration.cs | 19 - .../ItemValuesMapConfiguration.cs | 20 - .../MediaStreamInfoConfiguration.cs | 22 - .../PeopleBaseItemMapConfiguration.cs | 22 - .../ModelConfiguration/PeopleConfiguration.cs | 20 - .../ModelConfiguration/PermissionConfiguration.cs | 24 - .../ModelConfiguration/PreferenceConfiguration.cs | 21 - .../TrickplayInfoConfiguration.cs | 18 - .../ModelConfiguration/UserConfiguration.cs | 56 - .../ModelConfiguration/UserDataConfiguration.cs | 23 - .../Users/DeviceAccessHost.cs | 1 + .../Users/UserManager.cs | 1 + Jellyfin.Server/Jellyfin.Server.csproj | 1 + .../Migrations/Routines/MigrateLibraryDb.cs | 19 +- .../Migrations/Routines/MigrateUserDb.cs | 1 + Jellyfin.Server/Program.cs | 18 +- Jellyfin.Server/Startup.cs | 2 +- Jellyfin.sln | 29 +- MediaBrowser.Controller/Channels/Channel.cs | 1 + .../Entities/Audio/MusicAlbum.cs | 1 + .../Entities/Audio/MusicArtist.cs | 1 + MediaBrowser.Controller/Entities/BaseItem.cs | 1 + MediaBrowser.Controller/Entities/Folder.cs | 1 + .../Entities/InternalItemsQuery.cs | 1 + MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 1 + MediaBrowser.Controller/Entities/TV/Series.cs | 2 +- .../Entities/UserViewBuilder.cs | 1 + .../MediaEncoding/EncodingHelper.cs | 1 + MediaBrowser.Controller/Playlists/Playlist.cs | 1 + .../Transcoding/TranscodeManager.cs | 1 + src/Jellyfin.LiveTv/LiveTvManager.cs | 1 + .../Recordings/RecordingNotifier.cs | 1 + .../Auth/CustomAuthenticationHandlerTests.cs | 1 + tests/Jellyfin.Api.Tests/TestHelpers.cs | 1 + .../EfMigrations/EfMigrationTests.cs | 15 +- 381 files changed, 30622 insertions(+), 30200 deletions(-) delete mode 100644 Jellyfin.Data/Entities/AccessSchedule.cs delete mode 100644 Jellyfin.Data/Entities/ActivityLog.cs delete mode 100644 Jellyfin.Data/Entities/AncestorId.cs delete mode 100644 Jellyfin.Data/Entities/AttachmentStreamInfo.cs delete mode 100644 Jellyfin.Data/Entities/BaseItemEntity.cs delete mode 100644 Jellyfin.Data/Entities/BaseItemExtraType.cs delete mode 100644 Jellyfin.Data/Entities/BaseItemImageInfo.cs delete mode 100644 Jellyfin.Data/Entities/BaseItemMetadataField.cs delete mode 100644 Jellyfin.Data/Entities/BaseItemProvider.cs delete mode 100644 Jellyfin.Data/Entities/BaseItemTrailerType.cs delete mode 100644 Jellyfin.Data/Entities/Chapter.cs delete mode 100644 Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs delete mode 100644 Jellyfin.Data/Entities/DisplayPreferences.cs delete mode 100644 Jellyfin.Data/Entities/Group.cs delete mode 100644 Jellyfin.Data/Entities/HomeSection.cs delete mode 100644 Jellyfin.Data/Entities/ImageInfo.cs delete mode 100644 Jellyfin.Data/Entities/ImageInfoImageType.cs delete mode 100644 Jellyfin.Data/Entities/ItemDisplayPreferences.cs delete mode 100644 Jellyfin.Data/Entities/ItemValue.cs delete mode 100644 Jellyfin.Data/Entities/ItemValueMap.cs delete mode 100644 Jellyfin.Data/Entities/ItemValueType.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Artwork.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Book.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/BookMetadata.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Chapter.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Collection.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/CollectionItem.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Company.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/CustomItem.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Episode.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Genre.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/ItemMetadata.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Library.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/LibraryItem.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/MediaFile.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/MediaFileStream.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/MetadataProvider.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Movie.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/MovieMetadata.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/MusicAlbum.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Person.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/PersonRole.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Photo.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Rating.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/RatingSource.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Release.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Season.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Series.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/Track.cs delete mode 100644 Jellyfin.Data/Entities/Libraries/TrackMetadata.cs delete mode 100644 Jellyfin.Data/Entities/MediaSegment.cs delete mode 100644 Jellyfin.Data/Entities/MediaStreamInfo.cs delete mode 100644 Jellyfin.Data/Entities/MediaStreamTypeEntity.cs delete mode 100644 Jellyfin.Data/Entities/People.cs delete mode 100644 Jellyfin.Data/Entities/PeopleBaseItemMap.cs delete mode 100644 Jellyfin.Data/Entities/Permission.cs delete mode 100644 Jellyfin.Data/Entities/Preference.cs delete mode 100644 Jellyfin.Data/Entities/ProgramAudioEntity.cs delete mode 100644 Jellyfin.Data/Entities/Security/ApiKey.cs delete mode 100644 Jellyfin.Data/Entities/Security/Device.cs delete mode 100644 Jellyfin.Data/Entities/Security/DeviceOptions.cs delete mode 100644 Jellyfin.Data/Entities/TrickplayInfo.cs delete mode 100644 Jellyfin.Data/Entities/User.cs delete mode 100644 Jellyfin.Data/Entities/UserData.cs delete mode 100644 Jellyfin.Data/Enums/ArtKind.cs delete mode 100644 Jellyfin.Data/Enums/ChromecastVersion.cs delete mode 100644 Jellyfin.Data/Enums/DynamicDayOfWeek.cs delete mode 100644 Jellyfin.Data/Enums/HomeSectionType.cs delete mode 100644 Jellyfin.Data/Enums/IndexingKind.cs delete mode 100644 Jellyfin.Data/Enums/MediaFileKind.cs delete mode 100644 Jellyfin.Data/Enums/MediaSegmentType.cs delete mode 100644 Jellyfin.Data/Enums/PermissionKind.cs delete mode 100644 Jellyfin.Data/Enums/PersonRoleType.cs delete mode 100644 Jellyfin.Data/Enums/PreferenceKind.cs delete mode 100644 Jellyfin.Data/Enums/ScrollDirection.cs delete mode 100644 Jellyfin.Data/Enums/SortOrder.cs delete mode 100644 Jellyfin.Data/Enums/SubtitlePlaybackMode.cs delete mode 100644 Jellyfin.Data/Enums/SyncPlayUserAccessType.cs delete mode 100644 Jellyfin.Data/Enums/ViewType.cs delete mode 100644 Jellyfin.Data/Interfaces/IHasArtwork.cs delete mode 100644 Jellyfin.Data/Interfaces/IHasCompanies.cs delete mode 100644 Jellyfin.Data/Interfaces/IHasConcurrencyToken.cs delete mode 100644 Jellyfin.Data/Interfaces/IHasPermissions.cs delete mode 100644 Jellyfin.Data/Interfaces/IHasReleases.cs create mode 100644 Jellyfin.Data/UserEntityExtensions.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AncestorId.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemExtraType.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemMetadataField.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemTrailerType.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Chapter.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/CustomItemDisplayPreferences.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfo.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfoImageType.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValue.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueType.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CompanyMetadata.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItemMetadata.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/EpisodeMetadata.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbum.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbumMetadata.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PhotoMetadata.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Season.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeasonMetadata.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Series.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/TrackMetadata.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamTypeEntity.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/People.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/PeopleBaseItemMap.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ProgramAudioEntity.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/ApiKey.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/Device.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/DeviceOptions.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/TrickplayInfo.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ArtKind.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ChromecastVersion.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/DynamicDayOfWeek.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/HomeSectionType.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/IndexingKind.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaFileKind.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PermissionKind.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PersonRoleType.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PreferenceKind.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ScrollDirection.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SortOrder.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SubtitlePlaybackMode.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SyncPlayUserAccessType.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ViewType.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasConcurrencyToken.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/Jellyfin.Database.Implementations.csproj create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDatabaseProviderKeyAttribute.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Jellyfin.Database.Providers.PgSql.csproj create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Jellyfin.Database.Providers.SqLite.csproj create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200514181226_AddActivityLog.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200514181226_AddActivityLog.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200613202153_AddUsers.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200613202153_AddUsers.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200728005145_AddDisplayPreferences.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200728005145_AddDisplayPreferences.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200905220533_FixDisplayPreferencesIndex.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201004171403_AddMaxActiveSessions.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201204223655_AddCustomDisplayPreferences.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210320181425_AddIndexesAndCollations.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210407110544_NullableCustomPrefValue.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210814002109_AddDevices.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210814002109_AddDevices.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230526173516_RemoveEasyPassword.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230526173516_RemoveEasyPassword.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230626233818_AddTrickplayInfos.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230626233818_AddTrickplayInfos.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230923170422_UserCastReceiver.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230923170422_UserCastReceiver.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240729140605_AddMediaSegments.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240729140605_AddMediaSegments.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241020103111_LibraryDbMigration.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241020103111_LibraryDbMigration.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111131257_AddedCustomDataKey.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111131257_AddedCustomDataKey.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111135439_AddedCustomDataKeyKey.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112152323_FixAncestorIdConfig.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112232041_fixMediaStreams.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112232041_fixMediaStreams.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112234144_FixMediaStreams2.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112234144_FixMediaStreams2.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241113133548_EnforceUniqueItemValue.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/DesignTimeJellyfinDbFactory.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/JellyfinDbModelSnapshot.cs create mode 100644 Jellyfin.Database/Jellyfin.Database.Providers.SqLite/SqliteDatabaseProvider.cs create mode 100644 Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationFactory.cs create mode 100644 Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs create mode 100644 Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationStore.cs delete mode 100644 Jellyfin.Server.Implementations/JellyfinDbContext.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20200514181226_AddActivityLog.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20200514181226_AddActivityLog.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20200613202153_AddUsers.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20200613202153_AddUsers.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20201204223655_AddCustomDisplayPreferences.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20210407110544_NullableCustomPrefValue.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20210814002109_AddDevices.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20210814002109_AddDevices.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20221022080052_AddIndexActivityLogsDateCreated.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20230626233818_AddTrickplayInfos.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20230626233818_AddTrickplayInfos.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20230923170422_UserCastReceiver.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20230923170422_UserCastReceiver.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20240729140605_AddMediaSegments.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20240729140605_AddMediaSegments.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241020103111_LibraryDbMigration.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241020103111_LibraryDbMigration.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241111131257_AddedCustomDataKey.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241111131257_AddedCustomDataKey.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241111135439_AddedCustomDataKeyKey.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241112152323_FixAncestorIdConfig.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241112232041_fixMediaStreams.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241112232041_fixMediaStreams.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241112234144_FixMediaStreams2.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241112234144_FixMediaStreams2.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20241113133548_EnforceUniqueItemValue.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/DesignTimeJellyfinDbFactory.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/ActivityLogConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/AncestorIdConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/BaseItemConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/ChapterConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/DeviceConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/ItemValuesConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/PeopleConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/PermissionConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/PreferenceConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/UserConfiguration.cs delete mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/UserDataConfiguration.cs (limited to 'MediaBrowser.MediaEncoding') diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 228d4a17c..bcf484463 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -24,5 +24,19 @@ "hostRequirements": { "memory": "8gb", "cpus": 4 + }, "remoteEnv": { + "JELLYFIN_DATA_DIR": "/config" + }, + "mounts": [ + "source=/opt/docker/data/jellyfin/testConfig/,target=/config,type=bind,consistency=cached", + "source=/opt/docker/data/jellyfin/config10.9.11/metadata,target=/config/metadata,type=bind,consistency=cached", + "source=/mnt/video,target=/media,type=bind,consistency=cached" + ], + "customizations": { + "vscode": { + "extensions": [ + "alexcvzz.vscode-sqlite" + ] + } } } diff --git a/Directory.Packages.props b/Directory.Packages.props index c85d0c032..526ca3770 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -31,6 +31,7 @@ + diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 70dd5eb9a..c94ff924c 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -18,6 +18,7 @@ + diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index 1d04f3da3..82945a4f6 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -1,6 +1,7 @@ #pragma warning disable CS1591 using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Http; diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 93ee47fe8..1fc9ccb14 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -18,6 +18,7 @@ using Emby.Server.Implementations.Library.Validators; using Emby.Server.Implementations.Playlists; using Emby.Server.Implementations.ScheduledTasks.Tasks; using Emby.Server.Implementations.Sorting; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index d0f5e60f7..669db65f7 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -13,6 +13,7 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index e9cf47d46..b4e05ebf0 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs index 7d4e2377d..05223d28a 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs @@ -18,6 +18,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks private readonly ILogger _logger; private readonly ILocalizationManager _localization; private readonly IDbContextFactory _provider; + private readonly IJellyfinDatabaseProvider _jellyfinDatabaseProvider; /// /// Initializes a new instance of the class. @@ -25,14 +26,17 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. + /// Instance of the JellyfinDatabaseProvider that can be used for provider specific operations. public OptimizeDatabaseTask( ILogger logger, ILocalizationManager localization, - IDbContextFactory provider) + IDbContextFactory provider, + IJellyfinDatabaseProvider jellyfinDatabaseProvider) { _logger = logger; _localization = localization; _provider = provider; + _jellyfinDatabaseProvider = jellyfinDatabaseProvider; } /// @@ -73,20 +77,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks try { - var context = await _provider.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); - await using (context.ConfigureAwait(false)) - { - if (context.Database.IsSqlite()) - { - await context.Database.ExecuteSqlRawAsync("PRAGMA optimize", cancellationToken).ConfigureAwait(false); - await context.Database.ExecuteSqlRawAsync("VACUUM", cancellationToken).ConfigureAwait(false); - _logger.LogInformation("jellyfin.db optimized successfully!"); - } - else - { - _logger.LogInformation("This database doesn't support optimization"); - } - } + await _jellyfinDatabaseProvider.RunScheduledOptimisation(cancellationToken).ConfigureAwait(false); } catch (Exception e) { diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index fe2c3d24f..d9ab9bc1d 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -7,6 +7,7 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Entities.Security; using Jellyfin.Data.Enums; diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs index f8ce473da..39e751ca6 100644 --- a/Emby.Server.Implementations/TV/TVSeriesManager.cs +++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; diff --git a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs index 2853e69b0..19c35fc6a 100644 --- a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs +++ b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs @@ -3,6 +3,7 @@ using System.Security.Claims; using System.Text.Encodings.Web; using System.Threading.Tasks; using Jellyfin.Api.Constants; +using Jellyfin.Data; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Net; diff --git a/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs b/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs index 4928d5ed2..07dedb017 100644 --- a/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs +++ b/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; +using Jellyfin.Data; using Jellyfin.Data.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs index f20779f6c..d139eab16 100644 --- a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs +++ b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Jellyfin.Api.Extensions; +using Jellyfin.Data; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Library; diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 775d723b0..d9ebf0667 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -4,6 +4,7 @@ using System.Linq; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; +using Jellyfin.Data; using Jellyfin.Data.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index d7886d247..838578fab 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -7,6 +7,7 @@ using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.UserDtos; +using Jellyfin.Data; using Jellyfin.Data.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Api; diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs index 4adda0b69..2c45789d3 100644 --- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs +++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs @@ -7,6 +7,7 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Extensions; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; diff --git a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs index 99516e938..c472abdf0 100644 --- a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using MediaBrowser.Controller.Authentication; diff --git a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs index a6cfe4d56..f4031be36 100644 --- a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Library; diff --git a/Jellyfin.Data/Entities/AccessSchedule.cs b/Jellyfin.Data/Entities/AccessSchedule.cs deleted file mode 100644 index f534e49f3..000000000 --- a/Jellyfin.Data/Entities/AccessSchedule.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations.Schema; -using System.Xml.Serialization; -using Jellyfin.Data.Enums; - -namespace Jellyfin.Data.Entities -{ - /// - /// An entity representing a user's access schedule. - /// - public class AccessSchedule - { - /// - /// Initializes a new instance of the class. - /// - /// The day of the week. - /// The start hour. - /// The end hour. - /// The associated user's id. - public AccessSchedule(DynamicDayOfWeek dayOfWeek, double startHour, double endHour, Guid userId) - { - UserId = userId; - DayOfWeek = dayOfWeek; - StartHour = startHour; - EndHour = endHour; - } - - /// - /// Gets the id of this instance. - /// - /// - /// Identity, Indexed, Required. - /// - [XmlIgnore] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets the id of the associated user. - /// - [XmlIgnore] - public Guid UserId { get; private set; } - - /// - /// Gets or sets the day of week. - /// - /// The day of week. - public DynamicDayOfWeek DayOfWeek { get; set; } - - /// - /// Gets or sets the start hour. - /// - /// The start hour. - public double StartHour { get; set; } - - /// - /// Gets or sets the end hour. - /// - /// The end hour. - public double EndHour { get; set; } - } -} diff --git a/Jellyfin.Data/Entities/ActivityLog.cs b/Jellyfin.Data/Entities/ActivityLog.cs deleted file mode 100644 index 51dd0ffb8..000000000 --- a/Jellyfin.Data/Entities/ActivityLog.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; -using Microsoft.Extensions.Logging; - -namespace Jellyfin.Data.Entities -{ - /// - /// An entity referencing an activity log entry. - /// - public class ActivityLog : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// Public constructor with required data. - /// - /// The name. - /// The type. - /// The user id. - public ActivityLog(string name, string type, Guid userId) - { - ArgumentException.ThrowIfNullOrEmpty(name); - ArgumentException.ThrowIfNullOrEmpty(type); - - Name = name; - Type = type; - UserId = userId; - DateCreated = DateTime.UtcNow; - LogSeverity = LogLevel.Information; - } - - /// - /// Gets the identity of this instance. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the name. - /// - /// - /// Required, Max length = 512. - /// - [MaxLength(512)] - [StringLength(512)] - public string Name { get; set; } - - /// - /// Gets or sets the overview. - /// - /// - /// Max length = 512. - /// - [MaxLength(512)] - [StringLength(512)] - public string? Overview { get; set; } - - /// - /// Gets or sets the short overview. - /// - /// - /// Max length = 512. - /// - [MaxLength(512)] - [StringLength(512)] - public string? ShortOverview { get; set; } - - /// - /// Gets or sets the type. - /// - /// - /// Required, Max length = 256. - /// - [MaxLength(256)] - [StringLength(256)] - public string Type { get; set; } - - /// - /// Gets or sets the user id. - /// - /// - /// Required. - /// - public Guid UserId { get; set; } - - /// - /// Gets or sets the item id. - /// - /// - /// Max length = 256. - /// - [MaxLength(256)] - [StringLength(256)] - public string? ItemId { get; set; } - - /// - /// Gets or sets the date created. This should be in UTC. - /// - /// - /// Required. - /// - public DateTime DateCreated { get; set; } - - /// - /// Gets or sets the log severity. Default is . - /// - /// - /// Required. - /// - public LogLevel LogSeverity { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/AncestorId.cs b/Jellyfin.Data/Entities/AncestorId.cs deleted file mode 100644 index ef0fe0ba7..000000000 --- a/Jellyfin.Data/Entities/AncestorId.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; - -namespace Jellyfin.Data.Entities; - -/// -/// Represents the relational informations for an . -/// -public class AncestorId -{ - /// - /// Gets or Sets the AncestorId. - /// - public required Guid ParentItemId { get; set; } - - /// - /// Gets or Sets the related BaseItem. - /// - public required Guid ItemId { get; set; } - - /// - /// Gets or Sets the ParentItem. - /// - public required BaseItemEntity ParentItem { get; set; } - - /// - /// Gets or Sets the Child item. - /// - public required BaseItemEntity Item { get; set; } -} diff --git a/Jellyfin.Data/Entities/AttachmentStreamInfo.cs b/Jellyfin.Data/Entities/AttachmentStreamInfo.cs deleted file mode 100644 index 77b627f37..000000000 --- a/Jellyfin.Data/Entities/AttachmentStreamInfo.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; - -namespace Jellyfin.Data.Entities; - -/// -/// Provides informations about an Attachment to an . -/// -public class AttachmentStreamInfo -{ - /// - /// Gets or Sets the reference. - /// - public required Guid ItemId { get; set; } - - /// - /// Gets or Sets the reference. - /// - public required BaseItemEntity Item { get; set; } - - /// - /// Gets or Sets The index within the source file. - /// - public required int Index { get; set; } - - /// - /// Gets or Sets the codec of the attachment. - /// - public required string Codec { get; set; } - - /// - /// Gets or Sets the codec tag of the attachment. - /// - public string? CodecTag { get; set; } - - /// - /// Gets or Sets the comment of the attachment. - /// - public string? Comment { get; set; } - - /// - /// Gets or Sets the filename of the attachment. - /// - public string? Filename { get; set; } - - /// - /// Gets or Sets the attachments mimetype. - /// - public string? MimeType { get; set; } -} diff --git a/Jellyfin.Data/Entities/BaseItemEntity.cs b/Jellyfin.Data/Entities/BaseItemEntity.cs deleted file mode 100644 index 33b2b6741..000000000 --- a/Jellyfin.Data/Entities/BaseItemEntity.cs +++ /dev/null @@ -1,186 +0,0 @@ -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable CA2227 // Collection properties should be read only - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace Jellyfin.Data.Entities; - -public class BaseItemEntity -{ - public required Guid Id { get; set; } - - public required string Type { get; set; } - - public string? Data { get; set; } - - public string? Path { get; set; } - - public DateTime StartDate { get; set; } - - public DateTime EndDate { get; set; } - - public string? ChannelId { get; set; } - - public bool IsMovie { get; set; } - - public float? CommunityRating { get; set; } - - public string? CustomRating { get; set; } - - public int? IndexNumber { get; set; } - - public bool IsLocked { get; set; } - - public string? Name { get; set; } - - public string? OfficialRating { get; set; } - - public string? MediaType { get; set; } - - public string? Overview { get; set; } - - public int? ParentIndexNumber { get; set; } - - public DateTime? PremiereDate { get; set; } - - public int? ProductionYear { get; set; } - - public string? Genres { get; set; } - - public string? SortName { get; set; } - - public string? ForcedSortName { get; set; } - - public long? RunTimeTicks { get; set; } - - public DateTime? DateCreated { get; set; } - - public DateTime? DateModified { get; set; } - - public bool IsSeries { get; set; } - - public string? EpisodeTitle { get; set; } - - public bool IsRepeat { get; set; } - - public string? PreferredMetadataLanguage { get; set; } - - public string? PreferredMetadataCountryCode { get; set; } - - public DateTime? DateLastRefreshed { get; set; } - - public DateTime? DateLastSaved { get; set; } - - public bool IsInMixedFolder { get; set; } - - public string? Studios { get; set; } - - public string? ExternalServiceId { get; set; } - - public string? Tags { get; set; } - - public bool IsFolder { get; set; } - - public int? InheritedParentalRatingValue { get; set; } - - public string? UnratedType { get; set; } - - public float? CriticRating { get; set; } - - public string? CleanName { get; set; } - - public string? PresentationUniqueKey { get; set; } - - public string? OriginalTitle { get; set; } - - public string? PrimaryVersionId { get; set; } - - public DateTime? DateLastMediaAdded { get; set; } - - public string? Album { get; set; } - - public float? LUFS { get; set; } - - public float? NormalizationGain { get; set; } - - public bool IsVirtualItem { get; set; } - - public string? SeriesName { get; set; } - - public string? SeasonName { get; set; } - - public string? ExternalSeriesId { get; set; } - - public string? Tagline { get; set; } - - public string? ProductionLocations { get; set; } - - public string? ExtraIds { get; set; } - - public int? TotalBitrate { get; set; } - - public BaseItemExtraType? ExtraType { get; set; } - - public string? Artists { get; set; } - - public string? AlbumArtists { get; set; } - - public string? ExternalId { get; set; } - - public string? SeriesPresentationUniqueKey { get; set; } - - public string? ShowId { get; set; } - - public string? OwnerId { get; set; } - - public int? Width { get; set; } - - public int? Height { get; set; } - - public long? Size { get; set; } - - public ProgramAudioEntity? Audio { get; set; } - - public Guid? ParentId { get; set; } - - public Guid? TopParentId { get; set; } - - public Guid? SeasonId { get; set; } - - public Guid? SeriesId { get; set; } - - public ICollection? Peoples { get; set; } - - public ICollection? UserData { get; set; } - - public ICollection? ItemValues { get; set; } - - public ICollection? MediaStreams { get; set; } - - public ICollection? Chapters { get; set; } - - public ICollection? Provider { get; set; } - - public ICollection? ParentAncestors { get; set; } - - public ICollection? Children { get; set; } - - public ICollection? LockedFields { get; set; } - - public ICollection? TrailerTypes { get; set; } - - public ICollection? Images { get; set; } - - // those are references to __LOCAL__ ids not DB ids ... TODO: Bring the whole folder structure into the DB - // public ICollection? SeriesEpisodes { get; set; } - // public BaseItemEntity? Series { get; set; } - // public BaseItemEntity? Season { get; set; } - // public BaseItemEntity? Parent { get; set; } - // public ICollection? DirectChildren { get; set; } - // public BaseItemEntity? TopParent { get; set; } - // public ICollection? AllChildren { get; set; } - // public ICollection? SeasonEpisodes { get; set; } -} diff --git a/Jellyfin.Data/Entities/BaseItemExtraType.cs b/Jellyfin.Data/Entities/BaseItemExtraType.cs deleted file mode 100644 index 54aef50e4..000000000 --- a/Jellyfin.Data/Entities/BaseItemExtraType.cs +++ /dev/null @@ -1,18 +0,0 @@ -#pragma warning disable CS1591 -namespace Jellyfin.Data.Entities; - -public enum BaseItemExtraType -{ - Unknown = 0, - Clip = 1, - Trailer = 2, - BehindTheScenes = 3, - DeletedScene = 4, - Interview = 5, - Scene = 6, - Sample = 7, - ThemeSong = 8, - ThemeVideo = 9, - Featurette = 10, - Short = 11 -} diff --git a/Jellyfin.Data/Entities/BaseItemImageInfo.cs b/Jellyfin.Data/Entities/BaseItemImageInfo.cs deleted file mode 100644 index 37723df11..000000000 --- a/Jellyfin.Data/Entities/BaseItemImageInfo.cs +++ /dev/null @@ -1,59 +0,0 @@ -#pragma warning disable CA2227 - -using System; -using System.Collections.Generic; - -namespace Jellyfin.Data.Entities; - -/// -/// Enum TrailerTypes. -/// -public class BaseItemImageInfo -{ - /// - /// Gets or Sets. - /// - public required Guid Id { get; set; } - - /// - /// Gets or Sets the path to the original image. - /// - public required string Path { get; set; } - - /// - /// Gets or Sets the time the image was last modified. - /// - public DateTime DateModified { get; set; } - - /// - /// Gets or Sets the imagetype. - /// - public ImageInfoImageType ImageType { get; set; } - - /// - /// Gets or Sets the width of the original image. - /// - public int Width { get; set; } - - /// - /// Gets or Sets the height of the original image. - /// - public int Height { get; set; } - -#pragma warning disable CA1819 // Properties should not return arrays - /// - /// Gets or Sets the blurhash. - /// - public byte[]? Blurhash { get; set; } -#pragma warning restore CA1819 - - /// - /// Gets or Sets the reference id to the BaseItem. - /// - public required Guid ItemId { get; set; } - - /// - /// Gets or Sets the referenced Item. - /// - public required BaseItemEntity Item { get; set; } -} diff --git a/Jellyfin.Data/Entities/BaseItemMetadataField.cs b/Jellyfin.Data/Entities/BaseItemMetadataField.cs deleted file mode 100644 index c9d44c046..000000000 --- a/Jellyfin.Data/Entities/BaseItemMetadataField.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace Jellyfin.Data.Entities; - -/// -/// Enum MetadataFields. -/// -public class BaseItemMetadataField -{ - /// - /// Gets or Sets Numerical ID of this enumeratable. - /// - public required int Id { get; set; } - - /// - /// Gets or Sets all referenced . - /// - public required Guid ItemId { get; set; } - - /// - /// Gets or Sets all referenced . - /// - public required BaseItemEntity Item { get; set; } -} diff --git a/Jellyfin.Data/Entities/BaseItemProvider.cs b/Jellyfin.Data/Entities/BaseItemProvider.cs deleted file mode 100644 index 9a1565728..000000000 --- a/Jellyfin.Data/Entities/BaseItemProvider.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace Jellyfin.Data.Entities; - -/// -/// Represents a Key-Value relation of an BaseItem's provider. -/// -public class BaseItemProvider -{ - /// - /// Gets or Sets the reference ItemId. - /// - public Guid ItemId { get; set; } - - /// - /// Gets or Sets the reference BaseItem. - /// - public required BaseItemEntity Item { get; set; } - - /// - /// Gets or Sets the ProvidersId. - /// - public required string ProviderId { get; set; } - - /// - /// Gets or Sets the Providers Value. - /// - public required string ProviderValue { get; set; } -} diff --git a/Jellyfin.Data/Entities/BaseItemTrailerType.cs b/Jellyfin.Data/Entities/BaseItemTrailerType.cs deleted file mode 100644 index fb31fc8a4..000000000 --- a/Jellyfin.Data/Entities/BaseItemTrailerType.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace Jellyfin.Data.Entities; - -/// -/// Enum TrailerTypes. -/// -public class BaseItemTrailerType -{ - /// - /// Gets or Sets Numerical ID of this enumeratable. - /// - public required int Id { get; set; } - - /// - /// Gets or Sets all referenced . - /// - public required Guid ItemId { get; set; } - - /// - /// Gets or Sets all referenced . - /// - public required BaseItemEntity Item { get; set; } -} diff --git a/Jellyfin.Data/Entities/Chapter.cs b/Jellyfin.Data/Entities/Chapter.cs deleted file mode 100644 index 579442cdb..000000000 --- a/Jellyfin.Data/Entities/Chapter.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; - -namespace Jellyfin.Data.Entities; - -/// -/// The Chapter entity. -/// -public class Chapter -{ - /// - /// Gets or Sets the reference id. - /// - public required Guid ItemId { get; set; } - - /// - /// Gets or Sets the reference. - /// - public required BaseItemEntity Item { get; set; } - - /// - /// Gets or Sets the chapters index in Item. - /// - public required int ChapterIndex { get; set; } - - /// - /// Gets or Sets the position within the source file. - /// - public required long StartPositionTicks { get; set; } - - /// - /// Gets or Sets the common name. - /// - public string? Name { get; set; } - - /// - /// Gets or Sets the image path. - /// - public string? ImagePath { get; set; } - - /// - /// Gets or Sets the time the image was last modified. - /// - public DateTime? ImageDateModified { get; set; } -} diff --git a/Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs b/Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs deleted file mode 100644 index a60659512..000000000 --- a/Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace Jellyfin.Data.Entities -{ - /// - /// An entity that represents a user's custom display preferences for a specific item. - /// - public class CustomItemDisplayPreferences - { - /// - /// Initializes a new instance of the class. - /// - /// The user id. - /// The item id. - /// The client. - /// The preference key. - /// The preference value. - public CustomItemDisplayPreferences(Guid userId, Guid itemId, string client, string key, string? value) - { - UserId = userId; - ItemId = itemId; - Client = client; - Key = key; - Value = value; - } - - /// - /// Gets the Id. - /// - /// - /// Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the user Id. - /// - /// - /// Required. - /// - public Guid UserId { get; set; } - - /// - /// Gets or sets the id of the associated item. - /// - /// - /// Required. - /// - public Guid ItemId { get; set; } - - /// - /// Gets or sets the client string. - /// - /// - /// Required. Max Length = 32. - /// - [MaxLength(32)] - [StringLength(32)] - public string Client { get; set; } - - /// - /// Gets or sets the preference key. - /// - /// - /// Required. - /// - public string Key { get; set; } - - /// - /// Gets or sets the preference value. - /// - /// - /// Required. - /// - public string? Value { get; set; } - } -} diff --git a/Jellyfin.Data/Entities/DisplayPreferences.cs b/Jellyfin.Data/Entities/DisplayPreferences.cs deleted file mode 100644 index f0be65769..000000000 --- a/Jellyfin.Data/Entities/DisplayPreferences.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; - -namespace Jellyfin.Data.Entities -{ - /// - /// An entity representing a user's display preferences. - /// - public class DisplayPreferences - { - /// - /// Initializes a new instance of the class. - /// - /// The user's id. - /// The item id. - /// The client string. - public DisplayPreferences(Guid userId, Guid itemId, string client) - { - UserId = userId; - ItemId = itemId; - Client = client; - ShowSidebar = false; - ShowBackdrop = true; - SkipForwardLength = 30000; - SkipBackwardLength = 10000; - ScrollDirection = ScrollDirection.Horizontal; - ChromecastVersion = ChromecastVersion.Stable; - - HomeSections = new HashSet(); - } - - /// - /// Gets the Id. - /// - /// - /// Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the user Id. - /// - /// - /// Required. - /// - public Guid UserId { get; set; } - - /// - /// Gets or sets the id of the associated item. - /// - /// - /// Required. - /// - public Guid ItemId { get; set; } - - /// - /// Gets or sets the client string. - /// - /// - /// Required. Max Length = 32. - /// - [MaxLength(32)] - [StringLength(32)] - public string Client { get; set; } - - /// - /// Gets or sets a value indicating whether to show the sidebar. - /// - /// - /// Required. - /// - public bool ShowSidebar { get; set; } - - /// - /// Gets or sets a value indicating whether to show the backdrop. - /// - /// - /// Required. - /// - public bool ShowBackdrop { get; set; } - - /// - /// Gets or sets the scroll direction. - /// - /// - /// Required. - /// - public ScrollDirection ScrollDirection { get; set; } - - /// - /// Gets or sets what the view should be indexed by. - /// - public IndexingKind? IndexBy { get; set; } - - /// - /// Gets or sets the length of time to skip forwards, in milliseconds. - /// - /// - /// Required. - /// - public int SkipForwardLength { get; set; } - - /// - /// Gets or sets the length of time to skip backwards, in milliseconds. - /// - /// - /// Required. - /// - public int SkipBackwardLength { get; set; } - - /// - /// Gets or sets the Chromecast Version. - /// - /// - /// Required. - /// - public ChromecastVersion ChromecastVersion { get; set; } - - /// - /// Gets or sets a value indicating whether the next video info overlay should be shown. - /// - /// - /// Required. - /// - public bool EnableNextVideoInfoOverlay { get; set; } - - /// - /// Gets or sets the dashboard theme. - /// - [MaxLength(32)] - [StringLength(32)] - public string? DashboardTheme { get; set; } - - /// - /// Gets or sets the tv home screen. - /// - [MaxLength(32)] - [StringLength(32)] - public string? TvHome { get; set; } - - /// - /// Gets the home sections. - /// - public virtual ICollection HomeSections { get; private set; } - } -} diff --git a/Jellyfin.Data/Entities/Group.cs b/Jellyfin.Data/Entities/Group.cs deleted file mode 100644 index 1be6f986a..000000000 --- a/Jellyfin.Data/Entities/Group.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities -{ - /// - /// An entity representing a group. - /// - public class Group : IHasPermissions, IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The name of the group. - public Group(string name) - { - ArgumentException.ThrowIfNullOrEmpty(name); - - Name = name; - Id = Guid.NewGuid(); - - Permissions = new HashSet(); - Preferences = new HashSet(); - } - - /// - /// Gets the id of this group. - /// - /// - /// Identity, Indexed, Required. - /// - public Guid Id { get; private set; } - - /// - /// Gets or sets the group's name. - /// - /// - /// Required, Max length = 255. - /// - [MaxLength(255)] - [StringLength(255)] - public string Name { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets a collection containing the group's permissions. - /// - public virtual ICollection Permissions { get; private set; } - - /// - /// Gets a collection containing the group's preferences. - /// - public virtual ICollection Preferences { get; private set; } - - /// - public bool HasPermission(PermissionKind kind) - { - return Permissions.First(p => p.Kind == kind).Value; - } - - /// - public void SetPermission(PermissionKind kind, bool value) - { - Permissions.First(p => p.Kind == kind).Value = value; - } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/HomeSection.cs b/Jellyfin.Data/Entities/HomeSection.cs deleted file mode 100644 index 8dd6e647e..000000000 --- a/Jellyfin.Data/Entities/HomeSection.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; - -namespace Jellyfin.Data.Entities -{ - /// - /// An entity representing a section on the user's home page. - /// - public class HomeSection - { - /// - /// Gets the id. - /// - /// - /// Identity. Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the Id of the associated display preferences. - /// - /// - /// Required. - /// - public int DisplayPreferencesId { get; set; } - - /// - /// Gets or sets the order. - /// - /// - /// Required. - /// - public int Order { get; set; } - - /// - /// Gets or sets the type. - /// - /// - /// Required. - /// - public HomeSectionType Type { get; set; } - } -} diff --git a/Jellyfin.Data/Entities/ImageInfo.cs b/Jellyfin.Data/Entities/ImageInfo.cs deleted file mode 100644 index 935a53a26..000000000 --- a/Jellyfin.Data/Entities/ImageInfo.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace Jellyfin.Data.Entities -{ - /// - /// An entity representing an image. - /// - public class ImageInfo - { - /// - /// Initializes a new instance of the class. - /// - /// The path. - public ImageInfo(string path) - { - Path = path; - LastModified = DateTime.UtcNow; - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets the user id. - /// - public Guid? UserId { get; private set; } - - /// - /// Gets or sets the path of the image. - /// - /// - /// Required. - /// - [MaxLength(512)] - [StringLength(512)] - public string Path { get; set; } - - /// - /// Gets or sets the date last modified. - /// - /// - /// Required. - /// - public DateTime LastModified { get; set; } - } -} diff --git a/Jellyfin.Data/Entities/ImageInfoImageType.cs b/Jellyfin.Data/Entities/ImageInfoImageType.cs deleted file mode 100644 index f78178dd2..000000000 --- a/Jellyfin.Data/Entities/ImageInfoImageType.cs +++ /dev/null @@ -1,76 +0,0 @@ -namespace Jellyfin.Data.Entities; - -/// -/// Enum ImageType. -/// -public enum ImageInfoImageType -{ - /// - /// The primary. - /// - Primary = 0, - - /// - /// The art. - /// - Art = 1, - - /// - /// The backdrop. - /// - Backdrop = 2, - - /// - /// The banner. - /// - Banner = 3, - - /// - /// The logo. - /// - Logo = 4, - - /// - /// The thumb. - /// - Thumb = 5, - - /// - /// The disc. - /// - Disc = 6, - - /// - /// The box. - /// - Box = 7, - - /// - /// The screenshot. - /// - /// - /// This enum value is obsolete. - /// XmlSerializer does not serialize/deserialize objects that are marked as [Obsolete]. - /// - Screenshot = 8, - - /// - /// The menu. - /// - Menu = 9, - - /// - /// The chapter image. - /// - Chapter = 10, - - /// - /// The box rear. - /// - BoxRear = 11, - - /// - /// The user profile image. - /// - Profile = 12 -} diff --git a/Jellyfin.Data/Entities/ItemDisplayPreferences.cs b/Jellyfin.Data/Entities/ItemDisplayPreferences.cs deleted file mode 100644 index 93e6664ea..000000000 --- a/Jellyfin.Data/Entities/ItemDisplayPreferences.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; - -namespace Jellyfin.Data.Entities -{ - /// - /// An entity that represents a user's display preferences for a specific item. - /// - public class ItemDisplayPreferences - { - /// - /// Initializes a new instance of the class. - /// - /// The user id. - /// The item id. - /// The client. - public ItemDisplayPreferences(Guid userId, Guid itemId, string client) - { - UserId = userId; - ItemId = itemId; - Client = client; - - SortBy = "SortName"; - SortOrder = SortOrder.Ascending; - RememberSorting = false; - RememberIndexing = false; - } - - /// - /// Gets the id. - /// - /// - /// Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the user Id. - /// - /// - /// Required. - /// - public Guid UserId { get; set; } - - /// - /// Gets or sets the id of the associated item. - /// - /// - /// Required. - /// - public Guid ItemId { get; set; } - - /// - /// Gets or sets the client string. - /// - /// - /// Required. Max Length = 32. - /// - [MaxLength(32)] - [StringLength(32)] - public string Client { get; set; } - - /// - /// Gets or sets the view type. - /// - /// - /// Required. - /// - public ViewType ViewType { get; set; } - - /// - /// Gets or sets a value indicating whether the indexing should be remembered. - /// - /// - /// Required. - /// - public bool RememberIndexing { get; set; } - - /// - /// Gets or sets what the view should be indexed by. - /// - public IndexingKind? IndexBy { get; set; } - - /// - /// Gets or sets a value indicating whether the sorting type should be remembered. - /// - /// - /// Required. - /// - public bool RememberSorting { get; set; } - - /// - /// Gets or sets what the view should be sorted by. - /// - /// - /// Required. - /// - [MaxLength(64)] - [StringLength(64)] - public string SortBy { get; set; } - - /// - /// Gets or sets the sort order. - /// - /// - /// Required. - /// - public SortOrder SortOrder { get; set; } - } -} diff --git a/Jellyfin.Data/Entities/ItemValue.cs b/Jellyfin.Data/Entities/ItemValue.cs deleted file mode 100644 index 7b1048c10..000000000 --- a/Jellyfin.Data/Entities/ItemValue.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Jellyfin.Data.Entities; - -/// -/// Represents an ItemValue for a BaseItem. -/// -public class ItemValue -{ - /// - /// Gets or Sets the ItemValueId. - /// - public required Guid ItemValueId { get; set; } - - /// - /// Gets or Sets the Type. - /// - public required ItemValueType Type { get; set; } - - /// - /// Gets or Sets the Value. - /// - public required string Value { get; set; } - - /// - /// Gets or Sets the sanatised Value. - /// - public required string CleanValue { get; set; } - - /// - /// Gets or Sets all associated BaseItems. - /// -#pragma warning disable CA2227 // Collection properties should be read only - public ICollection? BaseItemsMap { get; set; } -#pragma warning restore CA2227 // Collection properties should be read only -} diff --git a/Jellyfin.Data/Entities/ItemValueMap.cs b/Jellyfin.Data/Entities/ItemValueMap.cs deleted file mode 100644 index 94db6a011..000000000 --- a/Jellyfin.Data/Entities/ItemValueMap.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Jellyfin.Data.Entities; - -/// -/// Mapping table for the ItemValue BaseItem relation. -/// -public class ItemValueMap -{ - /// - /// Gets or Sets the ItemId. - /// - public required Guid ItemId { get; set; } - - /// - /// Gets or Sets the ItemValueId. - /// - public required Guid ItemValueId { get; set; } - - /// - /// Gets or Sets the referenced . - /// - public required BaseItemEntity Item { get; set; } - - /// - /// Gets or Sets the referenced . - /// - public required ItemValue ItemValue { get; set; } -} diff --git a/Jellyfin.Data/Entities/ItemValueType.cs b/Jellyfin.Data/Entities/ItemValueType.cs deleted file mode 100644 index 3bae3becc..000000000 --- a/Jellyfin.Data/Entities/ItemValueType.cs +++ /dev/null @@ -1,38 +0,0 @@ -#pragma warning disable CA1027 // Mark enums with FlagsAttribute -namespace Jellyfin.Data.Entities; - -/// -/// Provides the Value types for an . -/// -public enum ItemValueType -{ - /// - /// Artists. - /// - Artist = 0, - - /// - /// Album. - /// - AlbumArtist = 1, - - /// - /// Genre. - /// - Genre = 2, - - /// - /// Studios. - /// - Studios = 3, - - /// - /// Tags. - /// - Tags = 4, - - /// - /// InheritedTags. - /// - InheritedTags = 6, -} diff --git a/Jellyfin.Data/Entities/Libraries/Artwork.cs b/Jellyfin.Data/Entities/Libraries/Artwork.cs deleted file mode 100644 index fc3c1036f..000000000 --- a/Jellyfin.Data/Entities/Libraries/Artwork.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing artwork. - /// - public class Artwork : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The path. - /// The kind of art. - public Artwork(string path, ArtKind kind) - { - ArgumentException.ThrowIfNullOrEmpty(path); - - Path = path; - Kind = kind; - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the path. - /// - /// - /// Required, Max length = 65535. - /// - [MaxLength(65535)] - [StringLength(65535)] - public string Path { get; set; } - - /// - /// Gets or sets the kind of artwork. - /// - /// - /// Required. - /// - public ArtKind Kind { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Book.cs b/Jellyfin.Data/Entities/Libraries/Book.cs deleted file mode 100644 index a838686d0..000000000 --- a/Jellyfin.Data/Entities/Libraries/Book.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a book. - /// - public class Book : LibraryItem, IHasReleases - { - /// - /// Initializes a new instance of the class. - /// - /// The library. - public Book(Library library) : base(library) - { - BookMetadata = new HashSet(); - Releases = new HashSet(); - } - - /// - /// Gets a collection containing the metadata for this book. - /// - public virtual ICollection BookMetadata { get; private set; } - - /// - public virtual ICollection Releases { get; private set; } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/BookMetadata.cs b/Jellyfin.Data/Entities/Libraries/BookMetadata.cs deleted file mode 100644 index 4a350d200..000000000 --- a/Jellyfin.Data/Entities/Libraries/BookMetadata.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity containing metadata for a book. - /// - public class BookMetadata : ItemMetadata, IHasCompanies - { - /// - /// Initializes a new instance of the class. - /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - public BookMetadata(string title, string language) : base(title, language) - { - Publishers = new HashSet(); - } - - /// - /// Gets or sets the ISBN. - /// - public long? Isbn { get; set; } - - /// - /// Gets a collection of the publishers for this book. - /// - public virtual ICollection Publishers { get; private set; } - - /// - public ICollection Companies => Publishers; - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Chapter.cs b/Jellyfin.Data/Entities/Libraries/Chapter.cs deleted file mode 100644 index f068338f9..000000000 --- a/Jellyfin.Data/Entities/Libraries/Chapter.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a chapter. - /// - public class Chapter : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// ISO-639-3 3-character language codes. - /// The start time for this chapter. - public Chapter(string language, long startTime) - { - ArgumentException.ThrowIfNullOrEmpty(language); - - Language = language; - StartTime = startTime; - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the name. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? Name { get; set; } - - /// - /// Gets or sets the language. - /// - /// - /// Required, Min length = 3, Max length = 3 - /// ISO-639-3 3-character language codes. - /// - [MinLength(3)] - [MaxLength(3)] - [StringLength(3)] - public string Language { get; set; } - - /// - /// Gets or sets the start time. - /// - /// - /// Required. - /// - public long StartTime { get; set; } - - /// - /// Gets or sets the end time. - /// - public long? EndTime { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Collection.cs b/Jellyfin.Data/Entities/Libraries/Collection.cs deleted file mode 100644 index 7de601969..000000000 --- a/Jellyfin.Data/Entities/Libraries/Collection.cs +++ /dev/null @@ -1,57 +0,0 @@ -#pragma warning disable CA1711 // Identifiers should not have incorrect suffix - -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a collection. - /// - public class Collection : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - public Collection() - { - Items = new HashSet(); - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the name. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? Name { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets a collection containing this collection's items. - /// - public virtual ICollection Items { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/CollectionItem.cs b/Jellyfin.Data/Entities/Libraries/CollectionItem.cs deleted file mode 100644 index 0cb4716db..000000000 --- a/Jellyfin.Data/Entities/Libraries/CollectionItem.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a collection item. - /// - public class CollectionItem : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The library item. - public CollectionItem(LibraryItem libraryItem) - { - LibraryItem = libraryItem; - } - - /// - /// Gets or sets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets or sets the library item. - /// - /// - /// Required. - /// - public virtual LibraryItem LibraryItem { get; set; } - - /// - /// Gets or sets the next item in the collection. - /// - /// - /// TODO check if this properly updated Dependant and has the proper principal relationship. - /// - public virtual CollectionItem? Next { get; set; } - - /// - /// Gets or sets the previous item in the collection. - /// - /// - /// TODO check if this properly updated Dependant and has the proper principal relationship. - /// - public virtual CollectionItem? Previous { get; set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Company.cs b/Jellyfin.Data/Entities/Libraries/Company.cs deleted file mode 100644 index 1abbee445..000000000 --- a/Jellyfin.Data/Entities/Libraries/Company.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a company. - /// - public class Company : IHasCompanies, IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - public Company() - { - CompanyMetadata = new HashSet(); - ChildCompanies = new HashSet(); - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets a collection containing the metadata. - /// - public virtual ICollection CompanyMetadata { get; private set; } - - /// - /// Gets a collection containing this company's child companies. - /// - public virtual ICollection ChildCompanies { get; private set; } - - /// - public ICollection Companies => ChildCompanies; - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs b/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs deleted file mode 100644 index a29f08c7f..000000000 --- a/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity holding metadata for a . - /// - public class CompanyMetadata : ItemMetadata - { - /// - /// Initializes a new instance of the class. - /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - public CompanyMetadata(string title, string language) : base(title, language) - { - } - - /// - /// Gets or sets the description. - /// - /// - /// Max length = 65535. - /// - [MaxLength(65535)] - [StringLength(65535)] - public string? Description { get; set; } - - /// - /// Gets or sets the headquarters. - /// - /// - /// Max length = 255. - /// - [MaxLength(255)] - [StringLength(255)] - public string? Headquarters { get; set; } - - /// - /// Gets or sets the country code. - /// - /// - /// Max length = 2. - /// - [MaxLength(2)] - [StringLength(2)] - public string? Country { get; set; } - - /// - /// Gets or sets the homepage. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? Homepage { get; set; } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/CustomItem.cs b/Jellyfin.Data/Entities/Libraries/CustomItem.cs deleted file mode 100644 index e27d01d86..000000000 --- a/Jellyfin.Data/Entities/Libraries/CustomItem.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a custom item. - /// - public class CustomItem : LibraryItem, IHasReleases - { - /// - /// Initializes a new instance of the class. - /// - /// The library. - public CustomItem(Library library) : base(library) - { - CustomItemMetadata = new HashSet(); - Releases = new HashSet(); - } - - /// - /// Gets a collection containing the metadata for this item. - /// - public virtual ICollection CustomItemMetadata { get; private set; } - - /// - public virtual ICollection Releases { get; private set; } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs b/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs deleted file mode 100644 index af2393870..000000000 --- a/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity containing metadata for a custom item. - /// - public class CustomItemMetadata : ItemMetadata - { - /// - /// Initializes a new instance of the class. - /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - public CustomItemMetadata(string title, string language) : base(title, language) - { - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Episode.cs b/Jellyfin.Data/Entities/Libraries/Episode.cs deleted file mode 100644 index ce2f0c617..000000000 --- a/Jellyfin.Data/Entities/Libraries/Episode.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing an episode. - /// - public class Episode : LibraryItem, IHasReleases - { - /// - /// Initializes a new instance of the class. - /// - /// The library. - public Episode(Library library) : base(library) - { - Releases = new HashSet(); - EpisodeMetadata = new HashSet(); - } - - /// - /// Gets or sets the episode number. - /// - public int? EpisodeNumber { get; set; } - - /// - public virtual ICollection Releases { get; private set; } - - /// - /// Gets a collection containing the metadata for this episode. - /// - public virtual ICollection EpisodeMetadata { get; private set; } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs b/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs deleted file mode 100644 index b0ef11e0f..000000000 --- a/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity containing metadata for an . - /// - public class EpisodeMetadata : ItemMetadata - { - /// - /// Initializes a new instance of the class. - /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - public EpisodeMetadata(string title, string language) : base(title, language) - { - } - - /// - /// Gets or sets the outline. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? Outline { get; set; } - - /// - /// Gets or sets the plot. - /// - /// - /// Max length = 65535. - /// - [MaxLength(65535)] - [StringLength(65535)] - public string? Plot { get; set; } - - /// - /// Gets or sets the tagline. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? Tagline { get; set; } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Genre.cs b/Jellyfin.Data/Entities/Libraries/Genre.cs deleted file mode 100644 index 3b822ee82..000000000 --- a/Jellyfin.Data/Entities/Libraries/Genre.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a genre. - /// - public class Genre : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The name. - public Genre(string name) - { - Name = name; - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the name. - /// - /// - /// Indexed, Required, Max length = 255. - /// - [MaxLength(255)] - [StringLength(255)] - public string Name { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs b/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs deleted file mode 100644 index fa9276c66..000000000 --- a/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An abstract class that holds metadata. - /// - public abstract class ItemMetadata : IHasArtwork, IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - protected ItemMetadata(string title, string language) - { - ArgumentException.ThrowIfNullOrEmpty(title); - ArgumentException.ThrowIfNullOrEmpty(language); - - Title = title; - Language = language; - DateAdded = DateTime.UtcNow; - DateModified = DateAdded; - - PersonRoles = new HashSet(); - Genres = new HashSet(); - Artwork = new HashSet(); - Ratings = new HashSet(); - Sources = new HashSet(); - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the title. - /// - /// - /// Required, Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string Title { get; set; } - - /// - /// Gets or sets the original title. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? OriginalTitle { get; set; } - - /// - /// Gets or sets the sort title. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? SortTitle { get; set; } - - /// - /// Gets or sets the language. - /// - /// - /// Required, Min length = 3, Max length = 3. - /// ISO-639-3 3-character language codes. - /// - [MinLength(3)] - [MaxLength(3)] - [StringLength(3)] - public string Language { get; set; } - - /// - /// Gets or sets the release date. - /// - public DateTimeOffset? ReleaseDate { get; set; } - - /// - /// Gets the date added. - /// - /// - /// Required. - /// - public DateTime DateAdded { get; private set; } - - /// - /// Gets or sets the date modified. - /// - /// - /// Required. - /// - public DateTime DateModified { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets a collection containing the person roles for this item. - /// - public virtual ICollection PersonRoles { get; private set; } - - /// - /// Gets a collection containing the genres for this item. - /// - public virtual ICollection Genres { get; private set; } - - /// - public virtual ICollection Artwork { get; private set; } - - /// - /// Gets a collection containing the ratings for this item. - /// - public virtual ICollection Ratings { get; private set; } - - /// - /// Gets a collection containing the metadata sources for this item. - /// - public virtual ICollection Sources { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Library.cs b/Jellyfin.Data/Entities/Libraries/Library.cs deleted file mode 100644 index 0db42a1c7..000000000 --- a/Jellyfin.Data/Entities/Libraries/Library.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a library. - /// - public class Library : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The name of the library. - /// The path of the library. - public Library(string name, string path) - { - Name = name; - Path = path; - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the name. - /// - /// - /// Required, Max length = 128. - /// - [MaxLength(128)] - [StringLength(128)] - public string Name { get; set; } - - /// - /// Gets or sets the root path of the library. - /// - /// - /// Required. - /// - public string Path { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/LibraryItem.cs b/Jellyfin.Data/Entities/Libraries/LibraryItem.cs deleted file mode 100644 index d889b871e..000000000 --- a/Jellyfin.Data/Entities/Libraries/LibraryItem.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a library item. - /// - public abstract class LibraryItem : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The library of this item. - protected LibraryItem(Library library) - { - DateAdded = DateTime.UtcNow; - Library = library; - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets the date this library item was added. - /// - public DateTime DateAdded { get; private set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets or sets the library of this item. - /// - /// - /// Required. - /// - public virtual Library Library { get; set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/MediaFile.cs b/Jellyfin.Data/Entities/Libraries/MediaFile.cs deleted file mode 100644 index 7b5a3af64..000000000 --- a/Jellyfin.Data/Entities/Libraries/MediaFile.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a file on disk. - /// - public class MediaFile : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The path relative to the LibraryRoot. - /// The file kind. - public MediaFile(string path, MediaFileKind kind) - { - ArgumentException.ThrowIfNullOrEmpty(path); - - Path = path; - Kind = kind; - - MediaFileStreams = new HashSet(); - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the path relative to the library root. - /// - /// - /// Required, Max length = 65535. - /// - [MaxLength(65535)] - [StringLength(65535)] - public string Path { get; set; } - - /// - /// Gets or sets the kind of media file. - /// - /// - /// Required. - /// - public MediaFileKind Kind { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets a collection containing the streams in this file. - /// - public virtual ICollection MediaFileStreams { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/MediaFileStream.cs b/Jellyfin.Data/Entities/Libraries/MediaFileStream.cs deleted file mode 100644 index e24e73ecb..000000000 --- a/Jellyfin.Data/Entities/Libraries/MediaFileStream.cs +++ /dev/null @@ -1,50 +0,0 @@ -#pragma warning disable CA1711 // Identifiers should not have incorrect suffix - -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a stream in a media file. - /// - public class MediaFileStream : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The number of this stream. - public MediaFileStream(int streamNumber) - { - StreamNumber = streamNumber; - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the stream number. - /// - /// - /// Required. - /// - public int StreamNumber { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs b/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs deleted file mode 100644 index b38d6a4f1..000000000 --- a/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a metadata provider. - /// - public class MetadataProvider : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The name of the metadata provider. - public MetadataProvider(string name) - { - ArgumentException.ThrowIfNullOrEmpty(name); - - Name = name; - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the name. - /// - /// - /// Required, Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string Name { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs b/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs deleted file mode 100644 index a198f53ba..000000000 --- a/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a unique identifier for a metadata provider. - /// - public class MetadataProviderId : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The provider id. - /// The metadata provider. - public MetadataProviderId(string providerId, MetadataProvider metadataProvider) - { - ArgumentException.ThrowIfNullOrEmpty(providerId); - - ProviderId = providerId; - MetadataProvider = metadataProvider; - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the provider id. - /// - /// - /// Required, Max length = 255. - /// - [MaxLength(255)] - [StringLength(255)] - public string ProviderId { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets or sets the metadata provider. - /// - /// - /// Required. - /// - public virtual MetadataProvider MetadataProvider { get; set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Movie.cs b/Jellyfin.Data/Entities/Libraries/Movie.cs deleted file mode 100644 index 499fafd0e..000000000 --- a/Jellyfin.Data/Entities/Libraries/Movie.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a movie. - /// - public class Movie : LibraryItem, IHasReleases - { - /// - /// Initializes a new instance of the class. - /// - /// The library. - public Movie(Library library) : base(library) - { - Releases = new HashSet(); - MovieMetadata = new HashSet(); - } - - /// - public virtual ICollection Releases { get; private set; } - - /// - /// Gets a collection containing the metadata for this movie. - /// - public virtual ICollection MovieMetadata { get; private set; } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs b/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs deleted file mode 100644 index 44b5f34d7..000000000 --- a/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity holding the metadata for a movie. - /// - public class MovieMetadata : ItemMetadata, IHasCompanies - { - /// - /// Initializes a new instance of the class. - /// - /// The title or name of the movie. - /// ISO-639-3 3-character language codes. - public MovieMetadata(string title, string language) : base(title, language) - { - Studios = new HashSet(); - } - - /// - /// Gets or sets the outline. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? Outline { get; set; } - - /// - /// Gets or sets the tagline. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? Tagline { get; set; } - - /// - /// Gets or sets the plot. - /// - /// - /// Max length = 65535. - /// - [MaxLength(65535)] - [StringLength(65535)] - public string? Plot { get; set; } - - /// - /// Gets or sets the country code. - /// - /// - /// Max length = 2. - /// - [MaxLength(2)] - [StringLength(2)] - public string? Country { get; set; } - - /// - /// Gets the studios that produced this movie. - /// - public virtual ICollection Studios { get; private set; } - - /// - public ICollection Companies => Studios; - } -} diff --git a/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs b/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs deleted file mode 100644 index d6231bbf0..000000000 --- a/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a music album. - /// - public class MusicAlbum : LibraryItem - { - /// - /// Initializes a new instance of the class. - /// - /// The library. - public MusicAlbum(Library library) : base(library) - { - MusicAlbumMetadata = new HashSet(); - Tracks = new HashSet(); - } - - /// - /// Gets a collection containing the album metadata. - /// - public virtual ICollection MusicAlbumMetadata { get; private set; } - - /// - /// Gets a collection containing the tracks. - /// - public virtual ICollection Tracks { get; private set; } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs b/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs deleted file mode 100644 index 691f3504f..000000000 --- a/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity holding the metadata for a music album. - /// - public class MusicAlbumMetadata : ItemMetadata - { - /// - /// Initializes a new instance of the class. - /// - /// The title or name of the album. - /// ISO-639-3 3-character language codes. - public MusicAlbumMetadata(string title, string language) : base(title, language) - { - Labels = new HashSet(); - } - - /// - /// Gets or sets the barcode. - /// - /// - /// Max length = 255. - /// - [MaxLength(255)] - [StringLength(255)] - public string? Barcode { get; set; } - - /// - /// Gets or sets the label number. - /// - /// - /// Max length = 255. - /// - [MaxLength(255)] - [StringLength(255)] - public string? LabelNumber { get; set; } - - /// - /// Gets or sets the country code. - /// - /// - /// Max length = 2. - /// - [MaxLength(2)] - [StringLength(2)] - public string? Country { get; set; } - - /// - /// Gets a collection containing the labels. - /// - public virtual ICollection Labels { get; private set; } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Person.cs b/Jellyfin.Data/Entities/Libraries/Person.cs deleted file mode 100644 index 90dc55b70..000000000 --- a/Jellyfin.Data/Entities/Libraries/Person.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a person. - /// - public class Person : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The name of the person. - public Person(string name) - { - ArgumentException.ThrowIfNullOrEmpty(name); - - Name = name; - DateAdded = DateTime.UtcNow; - DateModified = DateAdded; - - Sources = new HashSet(); - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the name. - /// - /// - /// Required, Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string Name { get; set; } - - /// - /// Gets or sets the source id. - /// - /// - /// Max length = 255. - /// - [MaxLength(256)] - [StringLength(256)] - public string? SourceId { get; set; } - - /// - /// Gets the date added. - /// - /// - /// Required. - /// - public DateTime DateAdded { get; private set; } - - /// - /// Gets or sets the date modified. - /// - /// - /// Required. - /// - public DateTime DateModified { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets a list of metadata sources for this person. - /// - public virtual ICollection Sources { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/PersonRole.cs b/Jellyfin.Data/Entities/Libraries/PersonRole.cs deleted file mode 100644 index 7d40bdf44..000000000 --- a/Jellyfin.Data/Entities/Libraries/PersonRole.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a person's role in media. - /// - public class PersonRole : IHasArtwork, IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The role type. - /// The person. - public PersonRole(PersonRoleType type, Person person) - { - Type = type; - Person = person; - Artwork = new HashSet(); - Sources = new HashSet(); - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the name of the person's role. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? Role { get; set; } - - /// - /// Gets or sets the person's role type. - /// - /// - /// Required. - /// - public PersonRoleType Type { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets or sets the person. - /// - /// - /// Required. - /// - public virtual Person Person { get; set; } - - /// - public virtual ICollection Artwork { get; private set; } - - /// - /// Gets a collection containing the metadata sources for this person role. - /// - public virtual ICollection Sources { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Photo.cs b/Jellyfin.Data/Entities/Libraries/Photo.cs deleted file mode 100644 index 4b459432b..000000000 --- a/Jellyfin.Data/Entities/Libraries/Photo.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a photo. - /// - public class Photo : LibraryItem, IHasReleases - { - /// - /// Initializes a new instance of the class. - /// - /// The library. - public Photo(Library library) : base(library) - { - PhotoMetadata = new HashSet(); - Releases = new HashSet(); - } - - /// - /// Gets a collection containing the photo metadata. - /// - public virtual ICollection PhotoMetadata { get; private set; } - - /// - public virtual ICollection Releases { get; private set; } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs b/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs deleted file mode 100644 index 6c284307d..000000000 --- a/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity that holds metadata for a photo. - /// - public class PhotoMetadata : ItemMetadata - { - /// - /// Initializes a new instance of the class. - /// - /// The title or name of the photo. - /// ISO-639-3 3-character language codes. - public PhotoMetadata(string title, string language) : base(title, language) - { - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Rating.cs b/Jellyfin.Data/Entities/Libraries/Rating.cs deleted file mode 100644 index 58c8fa49e..000000000 --- a/Jellyfin.Data/Entities/Libraries/Rating.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a rating for an entity. - /// - public class Rating : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The value. - public Rating(double value) - { - Value = value; - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the value. - /// - /// - /// Required. - /// - public double Value { get; set; } - - /// - /// Gets or sets the number of votes. - /// - public int? Votes { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets or sets the rating type. - /// If this is null it's the internal user rating. - /// - public virtual RatingSource? RatingType { get; set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/RatingSource.cs b/Jellyfin.Data/Entities/Libraries/RatingSource.cs deleted file mode 100644 index 0f3a07324..000000000 --- a/Jellyfin.Data/Entities/Libraries/RatingSource.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// This is the entity to store review ratings, not age ratings. - /// - public class RatingSource : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The minimum value. - /// The maximum value. - public RatingSource(double minimumValue, double maximumValue) - { - MinimumValue = minimumValue; - MaximumValue = maximumValue; - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the name. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? Name { get; set; } - - /// - /// Gets or sets the minimum value. - /// - /// - /// Required. - /// - public double MinimumValue { get; set; } - - /// - /// Gets or sets the maximum value. - /// - /// - /// Required. - /// - public double MaximumValue { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets or sets the metadata source. - /// - public virtual MetadataProviderId? Source { get; set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Release.cs b/Jellyfin.Data/Entities/Libraries/Release.cs deleted file mode 100644 index e68ab9105..000000000 --- a/Jellyfin.Data/Entities/Libraries/Release.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a release for a library item, eg. Director's cut vs. standard. - /// - public class Release : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// - /// The name of this release. - public Release(string name) - { - ArgumentException.ThrowIfNullOrEmpty(name); - - Name = name; - - MediaFiles = new HashSet(); - Chapters = new HashSet(); - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the name. - /// - /// - /// Required, Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string Name { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets a collection containing the media files for this release. - /// - public virtual ICollection MediaFiles { get; private set; } - - /// - /// Gets a collection containing the chapters for this release. - /// - public virtual ICollection Chapters { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Season.cs b/Jellyfin.Data/Entities/Libraries/Season.cs deleted file mode 100644 index fc110b49d..000000000 --- a/Jellyfin.Data/Entities/Libraries/Season.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a season. - /// - public class Season : LibraryItem - { - /// - /// Initializes a new instance of the class. - /// - /// The library. - public Season(Library library) : base(library) - { - Episodes = new HashSet(); - SeasonMetadata = new HashSet(); - } - - /// - /// Gets or sets the season number. - /// - public int? SeasonNumber { get; set; } - - /// - /// Gets the season metadata. - /// - public virtual ICollection SeasonMetadata { get; private set; } - - /// - /// Gets a collection containing the number of episodes. - /// - public virtual ICollection Episodes { get; private set; } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs b/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs deleted file mode 100644 index da40a075f..000000000 --- a/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity that holds metadata for seasons. - /// - public class SeasonMetadata : ItemMetadata - { - /// - /// Initializes a new instance of the class. - /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - public SeasonMetadata(string title, string language) : base(title, language) - { - } - - /// - /// Gets or sets the outline. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? Outline { get; set; } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Series.cs b/Jellyfin.Data/Entities/Libraries/Series.cs deleted file mode 100644 index 0354433e0..000000000 --- a/Jellyfin.Data/Entities/Libraries/Series.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a a series. - /// - public class Series : LibraryItem - { - /// - /// Initializes a new instance of the class. - /// - /// The library. - public Series(Library library) : base(library) - { - Seasons = new HashSet(); - SeriesMetadata = new HashSet(); - } - - /// - /// Gets or sets the days of week. - /// - public DayOfWeek? AirsDayOfWeek { get; set; } - - /// - /// Gets or sets the time the show airs, ignore the date portion. - /// - public DateTimeOffset? AirsTime { get; set; } - - /// - /// Gets or sets the date the series first aired. - /// - public DateTime? FirstAired { get; set; } - - /// - /// Gets a collection containing the series metadata. - /// - public virtual ICollection SeriesMetadata { get; private set; } - - /// - /// Gets a collection containing the seasons. - /// - public virtual ICollection Seasons { get; private set; } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs b/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs deleted file mode 100644 index 42115802c..000000000 --- a/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing series metadata. - /// - public class SeriesMetadata : ItemMetadata, IHasCompanies - { - /// - /// Initializes a new instance of the class. - /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - public SeriesMetadata(string title, string language) : base(title, language) - { - Networks = new HashSet(); - } - - /// - /// Gets or sets the outline. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? Outline { get; set; } - - /// - /// Gets or sets the plot. - /// - /// - /// Max length = 65535. - /// - [MaxLength(65535)] - [StringLength(65535)] - public string? Plot { get; set; } - - /// - /// Gets or sets the tagline. - /// - /// - /// Max length = 1024. - /// - [MaxLength(1024)] - [StringLength(1024)] - public string? Tagline { get; set; } - - /// - /// Gets or sets the country code. - /// - /// - /// Max length = 2. - /// - [MaxLength(2)] - [StringLength(2)] - public string? Country { get; set; } - - /// - /// Gets a collection containing the networks. - /// - public virtual ICollection Networks { get; private set; } - - /// - public ICollection Companies => Networks; - } -} diff --git a/Jellyfin.Data/Entities/Libraries/Track.cs b/Jellyfin.Data/Entities/Libraries/Track.cs deleted file mode 100644 index d35400033..000000000 --- a/Jellyfin.Data/Entities/Libraries/Track.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity representing a track. - /// - public class Track : LibraryItem, IHasReleases - { - /// - /// Initializes a new instance of the class. - /// - /// The library. - public Track(Library library) : base(library) - { - Releases = new HashSet(); - TrackMetadata = new HashSet(); - } - - /// - /// Gets or sets the track number. - /// - public int? TrackNumber { get; set; } - - /// - public virtual ICollection Releases { get; private set; } - - /// - /// Gets a collection containing the track metadata. - /// - public virtual ICollection TrackMetadata { get; private set; } - } -} diff --git a/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs b/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs deleted file mode 100644 index 042d2b90d..000000000 --- a/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Jellyfin.Data.Entities.Libraries -{ - /// - /// An entity holding metadata for a track. - /// - public class TrackMetadata : ItemMetadata - { - /// - /// Initializes a new instance of the class. - /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - public TrackMetadata(string title, string language) : base(title, language) - { - } - } -} diff --git a/Jellyfin.Data/Entities/MediaSegment.cs b/Jellyfin.Data/Entities/MediaSegment.cs deleted file mode 100644 index 90120d772..000000000 --- a/Jellyfin.Data/Entities/MediaSegment.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; - -namespace Jellyfin.Data.Entities; - -/// -/// An entity representing the metadata for a group of trickplay tiles. -/// -public class MediaSegment -{ - /// - /// Gets or sets the id of the media segment. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public Guid Id { get; set; } - - /// - /// Gets or sets the id of the associated item. - /// - public Guid ItemId { get; set; } - - /// - /// Gets or sets the Type of content this segment defines. - /// - public MediaSegmentType Type { get; set; } - - /// - /// Gets or sets the end of the segment. - /// - public long EndTicks { get; set; } - - /// - /// Gets or sets the start of the segment. - /// - public long StartTicks { get; set; } - - /// - /// Gets or sets Id of the media segment provider this entry originates from. - /// - public required string SegmentProviderId { get; set; } -} diff --git a/Jellyfin.Data/Entities/MediaStreamInfo.cs b/Jellyfin.Data/Entities/MediaStreamInfo.cs deleted file mode 100644 index 77816565a..000000000 --- a/Jellyfin.Data/Entities/MediaStreamInfo.cs +++ /dev/null @@ -1,103 +0,0 @@ -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace Jellyfin.Data.Entities; - -public class MediaStreamInfo -{ - public required Guid ItemId { get; set; } - - public required BaseItemEntity Item { get; set; } - - public int StreamIndex { get; set; } - - public required MediaStreamTypeEntity StreamType { get; set; } - - public string? Codec { get; set; } - - public string? Language { get; set; } - - public string? ChannelLayout { get; set; } - - public string? Profile { get; set; } - - public string? AspectRatio { get; set; } - - public string? Path { get; set; } - - public bool? IsInterlaced { get; set; } - - public int? BitRate { get; set; } - - public int? Channels { get; set; } - - public int? SampleRate { get; set; } - - public bool IsDefault { get; set; } - - public bool IsForced { get; set; } - - public bool IsExternal { get; set; } - - public int? Height { get; set; } - - public int? Width { get; set; } - - public float? AverageFrameRate { get; set; } - - public float? RealFrameRate { get; set; } - - public float? Level { get; set; } - - public string? PixelFormat { get; set; } - - public int? BitDepth { get; set; } - - public bool? IsAnamorphic { get; set; } - - public int? RefFrames { get; set; } - - public string? CodecTag { get; set; } - - public string? Comment { get; set; } - - public string? NalLengthSize { get; set; } - - public bool? IsAvc { get; set; } - - public string? Title { get; set; } - - public string? TimeBase { get; set; } - - public string? CodecTimeBase { get; set; } - - public string? ColorPrimaries { get; set; } - - public string? ColorSpace { get; set; } - - public string? ColorTransfer { get; set; } - - public int? DvVersionMajor { get; set; } - - public int? DvVersionMinor { get; set; } - - public int? DvProfile { get; set; } - - public int? DvLevel { get; set; } - - public int? RpuPresentFlag { get; set; } - - public int? ElPresentFlag { get; set; } - - public int? BlPresentFlag { get; set; } - - public int? DvBlSignalCompatibilityId { get; set; } - - public bool? IsHearingImpaired { get; set; } - - public int? Rotation { get; set; } - - public string? KeyFrames { get; set; } -} diff --git a/Jellyfin.Data/Entities/MediaStreamTypeEntity.cs b/Jellyfin.Data/Entities/MediaStreamTypeEntity.cs deleted file mode 100644 index f57672a2c..000000000 --- a/Jellyfin.Data/Entities/MediaStreamTypeEntity.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Jellyfin.Data.Entities; - -/// -/// Enum MediaStreamType. -/// -public enum MediaStreamTypeEntity -{ - /// - /// The audio. - /// - Audio = 0, - - /// - /// The video. - /// - Video = 1, - - /// - /// The subtitle. - /// - Subtitle = 2, - - /// - /// The embedded image. - /// - EmbeddedImage = 3, - - /// - /// The data. - /// - Data = 4, - - /// - /// The lyric. - /// - Lyric = 5 -} diff --git a/Jellyfin.Data/Entities/People.cs b/Jellyfin.Data/Entities/People.cs deleted file mode 100644 index 18c778b17..000000000 --- a/Jellyfin.Data/Entities/People.cs +++ /dev/null @@ -1,32 +0,0 @@ -#pragma warning disable CA2227 // Collection properties should be read only - -using System; -using System.Collections.Generic; - -namespace Jellyfin.Data.Entities; - -/// -/// People entity. -/// -public class People -{ - /// - /// Gets or Sets the PeopleId. - /// - public required Guid Id { get; set; } - - /// - /// Gets or Sets the Persons Name. - /// - public required string Name { get; set; } - - /// - /// Gets or Sets the Type. - /// - public string? PersonType { get; set; } - - /// - /// Gets or Sets the mapping of People to BaseItems. - /// - public ICollection? BaseItems { get; set; } -} diff --git a/Jellyfin.Data/Entities/PeopleBaseItemMap.cs b/Jellyfin.Data/Entities/PeopleBaseItemMap.cs deleted file mode 100644 index 5ce7300b5..000000000 --- a/Jellyfin.Data/Entities/PeopleBaseItemMap.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; - -namespace Jellyfin.Data.Entities; - -/// -/// Mapping table for People to BaseItems. -/// -public class PeopleBaseItemMap -{ - /// - /// Gets or Sets the SortOrder. - /// - public int? SortOrder { get; set; } - - /// - /// Gets or Sets the ListOrder. - /// - public int? ListOrder { get; set; } - - /// - /// Gets or Sets the Role name the assosiated actor played in the . - /// - public string? Role { get; set; } - - /// - /// Gets or Sets The ItemId. - /// - public required Guid ItemId { get; set; } - - /// - /// Gets or Sets Reference Item. - /// - public required BaseItemEntity Item { get; set; } - - /// - /// Gets or Sets The PeopleId. - /// - public required Guid PeopleId { get; set; } - - /// - /// Gets or Sets Reference People. - /// - public required People People { get; set; } -} diff --git a/Jellyfin.Data/Entities/Permission.cs b/Jellyfin.Data/Entities/Permission.cs deleted file mode 100644 index 6d2e68077..000000000 --- a/Jellyfin.Data/Entities/Permission.cs +++ /dev/null @@ -1,68 +0,0 @@ -#pragma warning disable CA1711 // Identifiers should not have incorrect suffix - -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities -{ - /// - /// An entity representing whether the associated user has a specific permission. - /// - public class Permission : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// Public constructor with required data. - /// - /// The permission kind. - /// The value of this permission. - public Permission(PermissionKind kind, bool value) - { - Kind = kind; - Value = value; - } - - /// - /// Gets the id of this permission. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the id of the associated user. - /// - public Guid? UserId { get; set; } - - /// - /// Gets the type of this permission. - /// - /// - /// Required. - /// - public PermissionKind Kind { get; private set; } - - /// - /// Gets or sets a value indicating whether the associated user has this permission. - /// - /// - /// Required. - /// - public bool Value { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/Preference.cs b/Jellyfin.Data/Entities/Preference.cs deleted file mode 100644 index a6ab275d3..000000000 --- a/Jellyfin.Data/Entities/Preference.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities -{ - /// - /// An entity representing a preference attached to a user or group. - /// - public class Preference : IHasConcurrencyToken - { - /// - /// Initializes a new instance of the class. - /// Public constructor with required data. - /// - /// The preference kind. - /// The value. - public Preference(PreferenceKind kind, string value) - { - Kind = kind; - Value = value ?? throw new ArgumentNullException(nameof(value)); - } - - /// - /// Gets the id of this preference. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the id of the associated user. - /// - public Guid? UserId { get; set; } - - /// - /// Gets the type of this preference. - /// - /// - /// Required. - /// - public PreferenceKind Kind { get; private set; } - - /// - /// Gets or sets the value of this preference. - /// - /// - /// Required, Max length = 65535. - /// - [MaxLength(65535)] - [StringLength(65535)] - public string Value { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/Jellyfin.Data/Entities/ProgramAudioEntity.cs b/Jellyfin.Data/Entities/ProgramAudioEntity.cs deleted file mode 100644 index 5b225a002..000000000 --- a/Jellyfin.Data/Entities/ProgramAudioEntity.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Jellyfin.Data.Entities; - -/// -/// Lists types of Audio. -/// -public enum ProgramAudioEntity -{ - /// - /// Mono. - /// - Mono = 0, - - /// - /// Sterio. - /// - Stereo = 1, - - /// - /// Dolby. - /// - Dolby = 2, - - /// - /// DolbyDigital. - /// - DolbyDigital = 3, - - /// - /// Thx. - /// - Thx = 4, - - /// - /// Atmos. - /// - Atmos = 5 -} diff --git a/Jellyfin.Data/Entities/Security/ApiKey.cs b/Jellyfin.Data/Entities/Security/ApiKey.cs deleted file mode 100644 index 1fcbe0f5e..000000000 --- a/Jellyfin.Data/Entities/Security/ApiKey.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Globalization; - -namespace Jellyfin.Data.Entities.Security -{ - /// - /// An entity representing an API key. - /// - public class ApiKey - { - /// - /// Initializes a new instance of the class. - /// - /// The name. - public ApiKey(string name) - { - Name = name; - - AccessToken = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); - DateCreated = DateTime.UtcNow; - } - - /// - /// Gets the id. - /// - /// - /// Identity, Indexed, Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets or sets the date created. - /// - public DateTime DateCreated { get; set; } - - /// - /// Gets or sets the date of last activity. - /// - public DateTime DateLastActivity { get; set; } - - /// - /// Gets or sets the name. - /// - [MaxLength(64)] - [StringLength(64)] - public string Name { get; set; } - - /// - /// Gets or sets the access token. - /// - public string AccessToken { get; set; } - } -} diff --git a/Jellyfin.Data/Entities/Security/Device.cs b/Jellyfin.Data/Entities/Security/Device.cs deleted file mode 100644 index 67d7f78ed..000000000 --- a/Jellyfin.Data/Entities/Security/Device.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Globalization; - -namespace Jellyfin.Data.Entities.Security -{ - /// - /// An entity representing a device. - /// - public class Device - { - /// - /// Initializes a new instance of the class. - /// - /// The user id. - /// The app name. - /// The app version. - /// The device name. - /// The device id. - public Device(Guid userId, string appName, string appVersion, string deviceName, string deviceId) - { - UserId = userId; - AppName = appName; - AppVersion = appVersion; - DeviceName = deviceName; - DeviceId = deviceId; - - AccessToken = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); - DateCreated = DateTime.UtcNow; - DateModified = DateCreated; - DateLastActivity = DateCreated; - - // Non-nullable for EF Core, as this is a required relationship. - User = null!; - } - - /// - /// Gets the id. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets the user id. - /// - public Guid UserId { get; private set; } - - /// - /// Gets or sets the access token. - /// - public string AccessToken { get; set; } - - /// - /// Gets or sets the app name. - /// - [MaxLength(64)] - [StringLength(64)] - public string AppName { get; set; } - - /// - /// Gets or sets the app version. - /// - [MaxLength(32)] - [StringLength(32)] - public string AppVersion { get; set; } - - /// - /// Gets or sets the device name. - /// - [MaxLength(64)] - [StringLength(64)] - public string DeviceName { get; set; } - - /// - /// Gets or sets the device id. - /// - [MaxLength(256)] - [StringLength(256)] - public string DeviceId { get; set; } - - /// - /// Gets or sets a value indicating whether this device is active. - /// - public bool IsActive { get; set; } - - /// - /// Gets or sets the date created. - /// - public DateTime DateCreated { get; set; } - - /// - /// Gets or sets the date modified. - /// - public DateTime DateModified { get; set; } - - /// - /// Gets or sets the date of last activity. - /// - public DateTime DateLastActivity { get; set; } - - /// - /// Gets the user. - /// - public User User { get; private set; } - } -} diff --git a/Jellyfin.Data/Entities/Security/DeviceOptions.cs b/Jellyfin.Data/Entities/Security/DeviceOptions.cs deleted file mode 100644 index 531f66c62..000000000 --- a/Jellyfin.Data/Entities/Security/DeviceOptions.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.ComponentModel.DataAnnotations.Schema; - -namespace Jellyfin.Data.Entities.Security -{ - /// - /// An entity representing custom options for a device. - /// - public class DeviceOptions - { - /// - /// Initializes a new instance of the class. - /// - /// The device id. - public DeviceOptions(string deviceId) - { - DeviceId = deviceId; - } - - /// - /// Gets the id. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } - - /// - /// Gets the device id. - /// - public string DeviceId { get; private set; } - - /// - /// Gets or sets the custom name. - /// - public string? CustomName { get; set; } - } -} diff --git a/Jellyfin.Data/Entities/TrickplayInfo.cs b/Jellyfin.Data/Entities/TrickplayInfo.cs deleted file mode 100644 index 64e7da1b5..000000000 --- a/Jellyfin.Data/Entities/TrickplayInfo.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Text.Json.Serialization; - -namespace Jellyfin.Data.Entities; - -/// -/// An entity representing the metadata for a group of trickplay tiles. -/// -public class TrickplayInfo -{ - /// - /// Gets or sets the id of the associated item. - /// - /// - /// Required. - /// - [JsonIgnore] - public Guid ItemId { get; set; } - - /// - /// Gets or sets width of an individual thumbnail. - /// - /// - /// Required. - /// - public int Width { get; set; } - - /// - /// Gets or sets height of an individual thumbnail. - /// - /// - /// Required. - /// - public int Height { get; set; } - - /// - /// Gets or sets amount of thumbnails per row. - /// - /// - /// Required. - /// - public int TileWidth { get; set; } - - /// - /// Gets or sets amount of thumbnails per column. - /// - /// - /// Required. - /// - public int TileHeight { get; set; } - - /// - /// Gets or sets total amount of non-black thumbnails. - /// - /// - /// Required. - /// - public int ThumbnailCount { get; set; } - - /// - /// Gets or sets interval in milliseconds between each trickplay thumbnail. - /// - /// - /// Required. - /// - public int Interval { get; set; } - - /// - /// Gets or sets peak bandwith usage in bits per second. - /// - /// - /// Required. - /// - public int Bandwidth { get; set; } -} diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs deleted file mode 100644 index 9bbe9efe8..000000000 --- a/Jellyfin.Data/Entities/User.cs +++ /dev/null @@ -1,534 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Text.Json.Serialization; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; - -namespace Jellyfin.Data.Entities -{ - /// - /// An entity representing a user. - /// - public class User : IHasPermissions, IHasConcurrencyToken - { - /// - /// The values being delimited here are Guids, so commas work as they do not appear in Guids. - /// - private const char Delimiter = ','; - - /// - /// Initializes a new instance of the class. - /// Public constructor with required data. - /// - /// The username for the new user. - /// The Id of the user's authentication provider. - /// The Id of the user's password reset provider. - public User(string username, string authenticationProviderId, string passwordResetProviderId) - { - ArgumentException.ThrowIfNullOrEmpty(username); - ArgumentException.ThrowIfNullOrEmpty(authenticationProviderId); - ArgumentException.ThrowIfNullOrEmpty(passwordResetProviderId); - - Username = username; - AuthenticationProviderId = authenticationProviderId; - PasswordResetProviderId = passwordResetProviderId; - - AccessSchedules = new HashSet(); - DisplayPreferences = new HashSet(); - ItemDisplayPreferences = new HashSet(); - // Groups = new HashSet(); - Permissions = new HashSet(); - Preferences = new HashSet(); - // ProviderMappings = new HashSet(); - - // Set default values - Id = Guid.NewGuid(); - InvalidLoginAttemptCount = 0; - EnableUserPreferenceAccess = true; - MustUpdatePassword = false; - DisplayMissingEpisodes = false; - DisplayCollectionsView = false; - HidePlayedInLatest = true; - RememberAudioSelections = true; - RememberSubtitleSelections = true; - EnableNextEpisodeAutoPlay = true; - EnableAutoLogin = false; - PlayDefaultAudioTrack = true; - SubtitleMode = SubtitlePlaybackMode.Default; - SyncPlayAccess = SyncPlayUserAccessType.CreateAndJoinGroups; - } - - /// - /// Gets or sets the Id of the user. - /// - /// - /// Identity, Indexed, Required. - /// - [JsonIgnore] - public Guid Id { get; set; } - - /// - /// Gets or sets the user's name. - /// - /// - /// Required, Max length = 255. - /// - [MaxLength(255)] - [StringLength(255)] - public string Username { get; set; } - - /// - /// Gets or sets the user's password, or null if none is set. - /// - /// - /// Max length = 65535. - /// - [MaxLength(65535)] - [StringLength(65535)] - public string? Password { get; set; } - - /// - /// Gets or sets a value indicating whether the user must update their password. - /// - /// - /// Required. - /// - public bool MustUpdatePassword { get; set; } - - /// - /// Gets or sets the audio language preference. - /// - /// - /// Max length = 255. - /// - [MaxLength(255)] - [StringLength(255)] - public string? AudioLanguagePreference { get; set; } - - /// - /// Gets or sets the authentication provider id. - /// - /// - /// Required, Max length = 255. - /// - [MaxLength(255)] - [StringLength(255)] - public string AuthenticationProviderId { get; set; } - - /// - /// Gets or sets the password reset provider id. - /// - /// - /// Required, Max length = 255. - /// - [MaxLength(255)] - [StringLength(255)] - public string PasswordResetProviderId { get; set; } - - /// - /// Gets or sets the invalid login attempt count. - /// - /// - /// Required. - /// - public int InvalidLoginAttemptCount { get; set; } - - /// - /// Gets or sets the last activity date. - /// - public DateTime? LastActivityDate { get; set; } - - /// - /// Gets or sets the last login date. - /// - public DateTime? LastLoginDate { get; set; } - - /// - /// Gets or sets the number of login attempts the user can make before they are locked out. - /// - public int? LoginAttemptsBeforeLockout { get; set; } - - /// - /// Gets or sets the maximum number of active sessions the user can have at once. - /// - public int MaxActiveSessions { get; set; } - - /// - /// Gets or sets the subtitle mode. - /// - /// - /// Required. - /// - public SubtitlePlaybackMode SubtitleMode { get; set; } - - /// - /// Gets or sets a value indicating whether the default audio track should be played. - /// - /// - /// Required. - /// - public bool PlayDefaultAudioTrack { get; set; } - - /// - /// Gets or sets the subtitle language preference. - /// - /// - /// Max length = 255. - /// - [MaxLength(255)] - [StringLength(255)] - public string? SubtitleLanguagePreference { get; set; } - - /// - /// Gets or sets a value indicating whether missing episodes should be displayed. - /// - /// - /// Required. - /// - public bool DisplayMissingEpisodes { get; set; } - - /// - /// Gets or sets a value indicating whether to display the collections view. - /// - /// - /// Required. - /// - public bool DisplayCollectionsView { get; set; } - - /// - /// Gets or sets a value indicating whether the user has a local password. - /// - /// - /// Required. - /// - public bool EnableLocalPassword { get; set; } - - /// - /// Gets or sets a value indicating whether the server should hide played content in "Latest". - /// - /// - /// Required. - /// - public bool HidePlayedInLatest { get; set; } - - /// - /// Gets or sets a value indicating whether to remember audio selections on played content. - /// - /// - /// Required. - /// - public bool RememberAudioSelections { get; set; } - - /// - /// Gets or sets a value indicating whether to remember subtitle selections on played content. - /// - /// - /// Required. - /// - public bool RememberSubtitleSelections { get; set; } - - /// - /// Gets or sets a value indicating whether to enable auto-play for the next episode. - /// - /// - /// Required. - /// - public bool EnableNextEpisodeAutoPlay { get; set; } - - /// - /// Gets or sets a value indicating whether the user should auto-login. - /// - /// - /// Required. - /// - public bool EnableAutoLogin { get; set; } - - /// - /// Gets or sets a value indicating whether the user can change their preferences. - /// - /// - /// Required. - /// - public bool EnableUserPreferenceAccess { get; set; } - - /// - /// Gets or sets the maximum parental age rating. - /// - public int? MaxParentalAgeRating { get; set; } - - /// - /// Gets or sets the remote client bitrate limit. - /// - public int? RemoteClientBitrateLimit { get; set; } - - /// - /// Gets or sets the internal id. - /// This is a temporary stopgap for until the library db is migrated. - /// This corresponds to the value of the index of this user in the library db. - /// - public long InternalId { get; set; } - - /// - /// Gets or sets the user's profile image. Can be null. - /// - // [ForeignKey("UserId")] - public virtual ImageInfo? ProfileImage { get; set; } - - /// - /// Gets the user's display preferences. - /// - public virtual ICollection DisplayPreferences { get; private set; } - - /// - /// Gets or sets the level of sync play permissions this user has. - /// - public SyncPlayUserAccessType SyncPlayAccess { get; set; } - - /// - /// Gets or sets the cast receiver id. - /// - [StringLength(32)] - public string? CastReceiverId { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - /// Gets the list of access schedules this user has. - /// - public virtual ICollection AccessSchedules { get; private set; } - - /// - /// Gets the list of item display preferences. - /// - public virtual ICollection ItemDisplayPreferences { get; private set; } - - /* - /// - /// Gets the list of groups this user is a member of. - /// - public virtual ICollection Groups { get; private set; } - */ - - /// - /// Gets the list of permissions this user has. - /// - [ForeignKey("Permission_Permissions_Guid")] - public virtual ICollection Permissions { get; private set; } - - /* - /// - /// Gets the list of provider mappings this user has. - /// - public virtual ICollection ProviderMappings { get; private set; } - */ - - /// - /// Gets the list of preferences this user has. - /// - [ForeignKey("Preference_Preferences_Guid")] - public virtual ICollection Preferences { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - - /// - /// Checks whether the user has the specified permission. - /// - /// The permission kind. - /// True if the user has the specified permission. - public bool HasPermission(PermissionKind kind) - { - return Permissions.FirstOrDefault(p => p.Kind == kind)?.Value ?? false; - } - - /// - /// Sets the given permission kind to the provided value. - /// - /// The permission kind. - /// The value to set. - public void SetPermission(PermissionKind kind, bool value) - { - var currentPermission = Permissions.FirstOrDefault(p => p.Kind == kind); - if (currentPermission is null) - { - Permissions.Add(new Permission(kind, value)); - } - else - { - currentPermission.Value = value; - } - } - - /// - /// Gets the user's preferences for the given preference kind. - /// - /// The preference kind. - /// A string array containing the user's preferences. - public string[] GetPreference(PreferenceKind preference) - { - var val = Preferences.FirstOrDefault(p => p.Kind == preference)?.Value; - - return string.IsNullOrEmpty(val) ? Array.Empty() : val.Split(Delimiter); - } - - /// - /// Gets the user's preferences for the given preference kind. - /// - /// The preference kind. - /// Type of preference. - /// A {T} array containing the user's preference. - public T[] GetPreferenceValues(PreferenceKind preference) - { - var val = Preferences.FirstOrDefault(p => p.Kind == preference)?.Value; - if (string.IsNullOrEmpty(val)) - { - return Array.Empty(); - } - - // Convert array of {string} to array of {T} - var converter = TypeDescriptor.GetConverter(typeof(T)); - var stringValues = val.Split(Delimiter); - var convertedCount = 0; - var parsedValues = new T[stringValues.Length]; - for (var i = 0; i < stringValues.Length; i++) - { - try - { - var parsedValue = converter.ConvertFromString(stringValues[i].Trim()); - if (parsedValue is not null) - { - parsedValues[convertedCount++] = (T)parsedValue; - } - } - catch (FormatException) - { - // Unable to convert value - } - } - - return parsedValues[..convertedCount]; - } - - /// - /// Sets the specified preference to the given value. - /// - /// The preference kind. - /// The values. - public void SetPreference(PreferenceKind preference, string[] values) - { - var value = string.Join(Delimiter, values); - var currentPreference = Preferences.FirstOrDefault(p => p.Kind == preference); - if (currentPreference is null) - { - Preferences.Add(new Preference(preference, value)); - } - else - { - currentPreference.Value = value; - } - } - - /// - /// Sets the specified preference to the given value. - /// - /// The preference kind. - /// The values. - /// The type of value. - public void SetPreference(PreferenceKind preference, T[] values) - { - var value = string.Join(Delimiter, values); - var currentPreference = Preferences.FirstOrDefault(p => p.Kind == preference); - if (currentPreference is null) - { - Preferences.Add(new Preference(preference, value)); - } - else - { - currentPreference.Value = value; - } - } - - /// - /// Checks whether this user is currently allowed to use the server. - /// - /// True if the current time is within an access schedule, or there are no access schedules. - public bool IsParentalScheduleAllowed() - { - return AccessSchedules.Count == 0 - || AccessSchedules.Any(i => IsParentalScheduleAllowed(i, DateTime.UtcNow)); - } - - /// - /// Checks whether the provided folder is in this user's grouped folders. - /// - /// The Guid of the folder. - /// True if the folder is in the user's grouped folders. - public bool IsFolderGrouped(Guid id) - { - return Array.IndexOf(GetPreferenceValues(PreferenceKind.GroupedFolders), id) != -1; - } - - /// - /// Initializes the default permissions for a user. Should only be called on user creation. - /// - // TODO: make these user configurable? - public void AddDefaultPermissions() - { - Permissions.Add(new Permission(PermissionKind.IsAdministrator, false)); - Permissions.Add(new Permission(PermissionKind.IsDisabled, false)); - Permissions.Add(new Permission(PermissionKind.IsHidden, true)); - Permissions.Add(new Permission(PermissionKind.EnableAllChannels, true)); - Permissions.Add(new Permission(PermissionKind.EnableAllDevices, true)); - Permissions.Add(new Permission(PermissionKind.EnableAllFolders, true)); - Permissions.Add(new Permission(PermissionKind.EnableContentDeletion, false)); - Permissions.Add(new Permission(PermissionKind.EnableContentDownloading, true)); - Permissions.Add(new Permission(PermissionKind.EnableMediaConversion, true)); - Permissions.Add(new Permission(PermissionKind.EnableMediaPlayback, true)); - Permissions.Add(new Permission(PermissionKind.EnablePlaybackRemuxing, true)); - Permissions.Add(new Permission(PermissionKind.EnablePublicSharing, true)); - Permissions.Add(new Permission(PermissionKind.EnableRemoteAccess, true)); - Permissions.Add(new Permission(PermissionKind.EnableSyncTranscoding, true)); - Permissions.Add(new Permission(PermissionKind.EnableAudioPlaybackTranscoding, true)); - Permissions.Add(new Permission(PermissionKind.EnableLiveTvAccess, true)); - Permissions.Add(new Permission(PermissionKind.EnableLiveTvManagement, true)); - Permissions.Add(new Permission(PermissionKind.EnableSharedDeviceControl, true)); - Permissions.Add(new Permission(PermissionKind.EnableVideoPlaybackTranscoding, true)); - Permissions.Add(new Permission(PermissionKind.ForceRemoteSourceTranscoding, false)); - Permissions.Add(new Permission(PermissionKind.EnableRemoteControlOfOtherUsers, false)); - Permissions.Add(new Permission(PermissionKind.EnableCollectionManagement, false)); - Permissions.Add(new Permission(PermissionKind.EnableSubtitleManagement, false)); - Permissions.Add(new Permission(PermissionKind.EnableLyricManagement, false)); - } - - /// - /// Initializes the default preferences. Should only be called on user creation. - /// - public void AddDefaultPreferences() - { - foreach (var val in Enum.GetValues()) - { - Preferences.Add(new Preference(val, string.Empty)); - } - } - - private static bool IsParentalScheduleAllowed(AccessSchedule schedule, DateTime date) - { - var localTime = date.ToLocalTime(); - var hour = localTime.TimeOfDay.TotalHours; - var currentDayOfWeek = localTime.DayOfWeek; - - return schedule.DayOfWeek.Contains(currentDayOfWeek) - && hour >= schedule.StartHour - && hour <= schedule.EndHour; - } - } -} diff --git a/Jellyfin.Data/Entities/UserData.cs b/Jellyfin.Data/Entities/UserData.cs deleted file mode 100644 index 05ab6dd2d..000000000 --- a/Jellyfin.Data/Entities/UserData.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations.Schema; - -namespace Jellyfin.Data.Entities; - -/// -/// Provides and related data. -/// -public class UserData -{ - /// - /// Gets or sets the custom data key. - /// - /// The rating. - public required string CustomDataKey { get; set; } - - /// - /// Gets or sets the users 0-10 rating. - /// - /// The rating. - public double? Rating { get; set; } - - /// - /// Gets or sets the playback position ticks. - /// - /// The playback position ticks. - public long PlaybackPositionTicks { get; set; } - - /// - /// Gets or sets the play count. - /// - /// The play count. - public int PlayCount { get; set; } - - /// - /// Gets or sets a value indicating whether this instance is favorite. - /// - /// true if this instance is favorite; otherwise, false. - public bool IsFavorite { get; set; } - - /// - /// Gets or sets the last played date. - /// - /// The last played date. - public DateTime? LastPlayedDate { get; set; } - - /// - /// Gets or sets a value indicating whether this is played. - /// - /// true if played; otherwise, false. - public bool Played { get; set; } - - /// - /// Gets or sets the index of the audio stream. - /// - /// The index of the audio stream. - public int? AudioStreamIndex { get; set; } - - /// - /// Gets or sets the index of the subtitle stream. - /// - /// The index of the subtitle stream. - public int? SubtitleStreamIndex { get; set; } - - /// - /// Gets or sets a value indicating whether the item is liked or not. - /// This should never be serialized. - /// - /// null if [likes] contains no value, true if [likes]; otherwise, false. - public bool? Likes { get; set; } - - /// - /// Gets or sets the key. - /// - /// The key. - public required Guid ItemId { get; set; } - - /// - /// Gets or Sets the BaseItem. - /// - public required BaseItemEntity? Item { get; set; } - - /// - /// Gets or Sets the UserId. - /// - public required Guid UserId { get; set; } - - /// - /// Gets or Sets the User. - /// - public required User? User { get; set; } -} diff --git a/Jellyfin.Data/Enums/ArtKind.cs b/Jellyfin.Data/Enums/ArtKind.cs deleted file mode 100644 index f7a73848c..000000000 --- a/Jellyfin.Data/Enums/ArtKind.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// An enum representing types of art. - /// - public enum ArtKind - { - /// - /// Another type of art, not covered by the other members. - /// - Other = 0, - - /// - /// A poster. - /// - Poster = 1, - - /// - /// A banner. - /// - Banner = 2, - - /// - /// A thumbnail. - /// - Thumbnail = 3, - - /// - /// A logo. - /// - Logo = 4 - } -} diff --git a/Jellyfin.Data/Enums/ChromecastVersion.cs b/Jellyfin.Data/Enums/ChromecastVersion.cs deleted file mode 100644 index c9c8a4a62..000000000 --- a/Jellyfin.Data/Enums/ChromecastVersion.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// An enum representing the version of Chromecast to be used by clients. - /// - public enum ChromecastVersion - { - /// - /// Stable Chromecast version. - /// - Stable = 0, - - /// - /// Unstable Chromecast version. - /// - Unstable = 1 - } -} diff --git a/Jellyfin.Data/Enums/DynamicDayOfWeek.cs b/Jellyfin.Data/Enums/DynamicDayOfWeek.cs deleted file mode 100644 index d3d8dd822..000000000 --- a/Jellyfin.Data/Enums/DynamicDayOfWeek.cs +++ /dev/null @@ -1,58 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// An enum that represents a day of the week, weekdays, weekends, or all days. - /// - public enum DynamicDayOfWeek - { - /// - /// Sunday. - /// - Sunday = 0, - - /// - /// Monday. - /// - Monday = 1, - - /// - /// Tuesday. - /// - Tuesday = 2, - - /// - /// Wednesday. - /// - Wednesday = 3, - - /// - /// Thursday. - /// - Thursday = 4, - - /// - /// Friday. - /// - Friday = 5, - - /// - /// Saturday. - /// - Saturday = 6, - - /// - /// All days of the week. - /// - Everyday = 7, - - /// - /// A week day, or Monday-Friday. - /// - Weekday = 8, - - /// - /// Saturday and Sunday. - /// - Weekend = 9 - } -} diff --git a/Jellyfin.Data/Enums/HomeSectionType.cs b/Jellyfin.Data/Enums/HomeSectionType.cs deleted file mode 100644 index 62da8c3ff..000000000 --- a/Jellyfin.Data/Enums/HomeSectionType.cs +++ /dev/null @@ -1,58 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// An enum representing the different options for the home screen sections. - /// - public enum HomeSectionType - { - /// - /// None. - /// - None = 0, - - /// - /// My Media. - /// - SmallLibraryTiles = 1, - - /// - /// My Media Small. - /// - LibraryButtons = 2, - - /// - /// Active Recordings. - /// - ActiveRecordings = 3, - - /// - /// Continue Watching. - /// - Resume = 4, - - /// - /// Continue Listening. - /// - ResumeAudio = 5, - - /// - /// Latest Media. - /// - LatestMedia = 6, - - /// - /// Next Up. - /// - NextUp = 7, - - /// - /// Live TV. - /// - LiveTv = 8, - - /// - /// Continue Reading. - /// - ResumeBook = 9 - } -} diff --git a/Jellyfin.Data/Enums/IndexingKind.cs b/Jellyfin.Data/Enums/IndexingKind.cs deleted file mode 100644 index 3967712b0..000000000 --- a/Jellyfin.Data/Enums/IndexingKind.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// An enum representing a type of indexing in a user's display preferences. - /// - public enum IndexingKind - { - /// - /// Index by the premiere date. - /// - PremiereDate = 0, - - /// - /// Index by the production year. - /// - ProductionYear = 1, - - /// - /// Index by the community rating. - /// - CommunityRating = 2 - } -} diff --git a/Jellyfin.Data/Enums/MediaFileKind.cs b/Jellyfin.Data/Enums/MediaFileKind.cs deleted file mode 100644 index 797c26ec2..000000000 --- a/Jellyfin.Data/Enums/MediaFileKind.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// An enum representing the type of media file. - /// - public enum MediaFileKind - { - /// - /// The main file. - /// - Main = 0, - - /// - /// A sidecar file. - /// - Sidecar = 1, - - /// - /// An additional part to the main file. - /// - AdditionalPart = 2, - - /// - /// An alternative format to the main file. - /// - AlternativeFormat = 3, - - /// - /// An additional stream for the main file. - /// - AdditionalStream = 4 - } -} diff --git a/Jellyfin.Data/Enums/MediaSegmentType.cs b/Jellyfin.Data/Enums/MediaSegmentType.cs deleted file mode 100644 index 458635450..000000000 --- a/Jellyfin.Data/Enums/MediaSegmentType.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Jellyfin.Data.Entities; - -namespace Jellyfin.Data.Enums; - -/// -/// Defines the types of content an individual represents. -/// -public enum MediaSegmentType -{ - /// - /// Default media type or custom one. - /// - Unknown = 0, - - /// - /// Commercial. - /// - Commercial = 1, - - /// - /// Preview. - /// - Preview = 2, - - /// - /// Recap. - /// - Recap = 3, - - /// - /// Outro. - /// - Outro = 4, - - /// - /// Intro. - /// - Intro = 5 -} diff --git a/Jellyfin.Data/Enums/PermissionKind.cs b/Jellyfin.Data/Enums/PermissionKind.cs deleted file mode 100644 index c3d6705c2..000000000 --- a/Jellyfin.Data/Enums/PermissionKind.cs +++ /dev/null @@ -1,128 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// The types of user permissions. - /// - public enum PermissionKind - { - /// - /// Whether the user is an administrator. - /// - IsAdministrator = 0, - - /// - /// Whether the user is hidden. - /// - IsHidden = 1, - - /// - /// Whether the user is disabled. - /// - IsDisabled = 2, - - /// - /// Whether the user can control shared devices. - /// - EnableSharedDeviceControl = 3, - - /// - /// Whether the user can access the server remotely. - /// - EnableRemoteAccess = 4, - - /// - /// Whether the user can manage live tv. - /// - EnableLiveTvManagement = 5, - - /// - /// Whether the user can access live tv. - /// - EnableLiveTvAccess = 6, - - /// - /// Whether the user can play media. - /// - EnableMediaPlayback = 7, - - /// - /// Whether the server should transcode audio for the user if requested. - /// - EnableAudioPlaybackTranscoding = 8, - - /// - /// Whether the server should transcode video for the user if requested. - /// - EnableVideoPlaybackTranscoding = 9, - - /// - /// Whether the user can delete content. - /// - EnableContentDeletion = 10, - - /// - /// Whether the user can download content. - /// - EnableContentDownloading = 11, - - /// - /// Whether to enable sync transcoding for the user. - /// - EnableSyncTranscoding = 12, - - /// - /// Whether the user can do media conversion. - /// - EnableMediaConversion = 13, - - /// - /// Whether the user has access to all devices. - /// - EnableAllDevices = 14, - - /// - /// Whether the user has access to all channels. - /// - EnableAllChannels = 15, - - /// - /// Whether the user has access to all folders. - /// - EnableAllFolders = 16, - - /// - /// Whether to enable public sharing for the user. - /// - EnablePublicSharing = 17, - - /// - /// Whether the user can remotely control other users. - /// - EnableRemoteControlOfOtherUsers = 18, - - /// - /// Whether the user is permitted to do playback remuxing. - /// - EnablePlaybackRemuxing = 19, - - /// - /// Whether the server should force transcoding on remote connections for the user. - /// - ForceRemoteSourceTranscoding = 20, - - /// - /// Whether the user can create, modify and delete collections. - /// - EnableCollectionManagement = 21, - - /// - /// Whether the user can edit subtitles. - /// - EnableSubtitleManagement = 22, - - /// - /// Whether the user can edit lyrics. - /// - EnableLyricManagement = 23, - } -} diff --git a/Jellyfin.Data/Enums/PersonRoleType.cs b/Jellyfin.Data/Enums/PersonRoleType.cs deleted file mode 100644 index 1e619f5ee..000000000 --- a/Jellyfin.Data/Enums/PersonRoleType.cs +++ /dev/null @@ -1,68 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// An enum representing a person's role in a specific media item. - /// - public enum PersonRoleType - { - /// - /// Another role, not covered by the other types. - /// - Other = 0, - - /// - /// The director of the media. - /// - Director = 1, - - /// - /// An artist. - /// - Artist = 2, - - /// - /// The original artist. - /// - OriginalArtist = 3, - - /// - /// An actor. - /// - Actor = 4, - - /// - /// A voice actor. - /// - VoiceActor = 5, - - /// - /// A producer. - /// - Producer = 6, - - /// - /// A remixer. - /// - Remixer = 7, - - /// - /// A conductor. - /// - Conductor = 8, - - /// - /// A composer. - /// - Composer = 9, - - /// - /// An author. - /// - Author = 10, - - /// - /// An editor. - /// - Editor = 11 - } -} diff --git a/Jellyfin.Data/Enums/PreferenceKind.cs b/Jellyfin.Data/Enums/PreferenceKind.cs deleted file mode 100644 index d2b412e45..000000000 --- a/Jellyfin.Data/Enums/PreferenceKind.cs +++ /dev/null @@ -1,73 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// The types of user preferences. - /// - public enum PreferenceKind - { - /// - /// A list of blocked tags. - /// - BlockedTags = 0, - - /// - /// A list of blocked channels. - /// - BlockedChannels = 1, - - /// - /// A list of blocked media folders. - /// - BlockedMediaFolders = 2, - - /// - /// A list of enabled devices. - /// - EnabledDevices = 3, - - /// - /// A list of enabled channels. - /// - EnabledChannels = 4, - - /// - /// A list of enabled folders. - /// - EnabledFolders = 5, - - /// - /// A list of folders to allow content deletion from. - /// - EnableContentDeletionFromFolders = 6, - - /// - /// A list of latest items to exclude. - /// - LatestItemExcludes = 7, - - /// - /// A list of media to exclude. - /// - MyMediaExcludes = 8, - - /// - /// A list of grouped folders. - /// - GroupedFolders = 9, - - /// - /// A list of unrated items to block. - /// - BlockUnratedItems = 10, - - /// - /// A list of ordered views. - /// - OrderedViews = 11, - - /// - /// A list of allowed tags. - /// - AllowedTags = 12 - } -} diff --git a/Jellyfin.Data/Enums/ScrollDirection.cs b/Jellyfin.Data/Enums/ScrollDirection.cs deleted file mode 100644 index 29c50e2c4..000000000 --- a/Jellyfin.Data/Enums/ScrollDirection.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// An enum representing the axis that should be scrolled. - /// - public enum ScrollDirection - { - /// - /// Horizontal scrolling direction. - /// - Horizontal = 0, - - /// - /// Vertical scrolling direction. - /// - Vertical = 1 - } -} diff --git a/Jellyfin.Data/Enums/SortOrder.cs b/Jellyfin.Data/Enums/SortOrder.cs deleted file mode 100644 index 4151448e4..000000000 --- a/Jellyfin.Data/Enums/SortOrder.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// An enum representing the sorting order. - /// - public enum SortOrder - { - /// - /// Sort in increasing order. - /// - Ascending = 0, - - /// - /// Sort in decreasing order. - /// - Descending = 1 - } -} diff --git a/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs b/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs deleted file mode 100644 index 79693d321..000000000 --- a/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// An enum representing a subtitle playback mode. - /// - public enum SubtitlePlaybackMode - { - /// - /// The default subtitle playback mode. - /// - Default = 0, - - /// - /// Always show subtitles. - /// - Always = 1, - - /// - /// Only show forced subtitles. - /// - OnlyForced = 2, - - /// - /// Don't show subtitles. - /// - None = 3, - - /// - /// Only show subtitles when the current audio stream is in a different language. - /// - Smart = 4 - } -} diff --git a/Jellyfin.Data/Enums/SyncPlayUserAccessType.cs b/Jellyfin.Data/Enums/SyncPlayUserAccessType.cs deleted file mode 100644 index 030d16fb9..000000000 --- a/Jellyfin.Data/Enums/SyncPlayUserAccessType.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// Enum SyncPlayUserAccessType. - /// - public enum SyncPlayUserAccessType - { - /// - /// User can create groups and join them. - /// - CreateAndJoinGroups = 0, - - /// - /// User can only join already existing groups. - /// - JoinGroups = 1, - - /// - /// SyncPlay is disabled for the user. - /// - None = 2 - } -} diff --git a/Jellyfin.Data/Enums/ViewType.cs b/Jellyfin.Data/Enums/ViewType.cs deleted file mode 100644 index c0fd7d448..000000000 --- a/Jellyfin.Data/Enums/ViewType.cs +++ /dev/null @@ -1,113 +0,0 @@ -namespace Jellyfin.Data.Enums -{ - /// - /// An enum representing the type of view for a library or collection. - /// - public enum ViewType - { - /// - /// Shows albums. - /// - Albums = 0, - - /// - /// Shows album artists. - /// - AlbumArtists = 1, - - /// - /// Shows artists. - /// - Artists = 2, - - /// - /// Shows channels. - /// - Channels = 3, - - /// - /// Shows collections. - /// - Collections = 4, - - /// - /// Shows episodes. - /// - Episodes = 5, - - /// - /// Shows favorites. - /// - Favorites = 6, - - /// - /// Shows genres. - /// - Genres = 7, - - /// - /// Shows guide. - /// - Guide = 8, - - /// - /// Shows movies. - /// - Movies = 9, - - /// - /// Shows networks. - /// - Networks = 10, - - /// - /// Shows playlists. - /// - Playlists = 11, - - /// - /// Shows programs. - /// - Programs = 12, - - /// - /// Shows recordings. - /// - Recordings = 13, - - /// - /// Shows schedule. - /// - Schedule = 14, - - /// - /// Shows series. - /// - Series = 15, - - /// - /// Shows shows. - /// - Shows = 16, - - /// - /// Shows songs. - /// - Songs = 17, - - /// - /// Shows songs. - /// - Suggestions = 18, - - /// - /// Shows trailers. - /// - Trailers = 19, - - /// - /// Shows upcoming. - /// - Upcoming = 20 - } -} diff --git a/Jellyfin.Data/Interfaces/IHasArtwork.cs b/Jellyfin.Data/Interfaces/IHasArtwork.cs deleted file mode 100644 index a4d9c54af..000000000 --- a/Jellyfin.Data/Interfaces/IHasArtwork.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Data.Entities.Libraries; - -namespace Jellyfin.Data.Interfaces -{ - /// - /// An interface abstracting an entity that has artwork. - /// - public interface IHasArtwork - { - /// - /// Gets a collection containing this entity's artwork. - /// - ICollection Artwork { get; } - } -} diff --git a/Jellyfin.Data/Interfaces/IHasCompanies.cs b/Jellyfin.Data/Interfaces/IHasCompanies.cs deleted file mode 100644 index 8f19ce04f..000000000 --- a/Jellyfin.Data/Interfaces/IHasCompanies.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Data.Entities.Libraries; - -namespace Jellyfin.Data.Interfaces -{ - /// - /// An abstraction representing an entity that has companies. - /// - public interface IHasCompanies - { - /// - /// Gets a collection containing this entity's companies. - /// - ICollection Companies { get; } - } -} diff --git a/Jellyfin.Data/Interfaces/IHasConcurrencyToken.cs b/Jellyfin.Data/Interfaces/IHasConcurrencyToken.cs deleted file mode 100644 index 2c4091493..000000000 --- a/Jellyfin.Data/Interfaces/IHasConcurrencyToken.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Jellyfin.Data.Interfaces -{ - /// - /// An interface abstracting an entity that has a concurrency token. - /// - public interface IHasConcurrencyToken - { - /// - /// Gets the version of this row. Acts as a concurrency token. - /// - uint RowVersion { get; } - - /// - /// Called when saving changes to this entity. - /// - void OnSavingChanges(); - } -} diff --git a/Jellyfin.Data/Interfaces/IHasPermissions.cs b/Jellyfin.Data/Interfaces/IHasPermissions.cs deleted file mode 100644 index bf8ec9d88..000000000 --- a/Jellyfin.Data/Interfaces/IHasPermissions.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; - -namespace Jellyfin.Data.Interfaces -{ - /// - /// An abstraction representing an entity that has permissions. - /// - public interface IHasPermissions - { - /// - /// Gets a collection containing this entity's permissions. - /// - ICollection Permissions { get; } - - /// - /// Checks whether this entity has the specified permission kind. - /// - /// The kind of permission. - /// true if this entity has the specified permission, false otherwise. - bool HasPermission(PermissionKind kind); - - /// - /// Sets the specified permission to the provided value. - /// - /// The kind of permission. - /// The value to set. - void SetPermission(PermissionKind kind, bool value); - } -} diff --git a/Jellyfin.Data/Interfaces/IHasReleases.cs b/Jellyfin.Data/Interfaces/IHasReleases.cs deleted file mode 100644 index 3b615893e..000000000 --- a/Jellyfin.Data/Interfaces/IHasReleases.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Data.Entities.Libraries; - -namespace Jellyfin.Data.Interfaces -{ - /// - /// An abstraction representing an entity that has releases. - /// - public interface IHasReleases - { - /// - /// Gets a collection containing this entity's releases. - /// - ICollection Releases { get; } - } -} diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 921cf2d8c..432f1846e 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -38,6 +38,10 @@ + + + + diff --git a/Jellyfin.Data/UserEntityExtensions.cs b/Jellyfin.Data/UserEntityExtensions.cs new file mode 100644 index 000000000..8d84a6b6e --- /dev/null +++ b/Jellyfin.Data/UserEntityExtensions.cs @@ -0,0 +1,220 @@ +using System; +using System.ComponentModel; +using System.Linq; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data; + +/// +/// Contains extension methods for manipulation of entities. +/// +public static class UserEntityExtensions +{ + /// + /// The values being delimited here are Guids, so commas work as they do not appear in Guids. + /// + private const char Delimiter = ','; + + /// + /// Checks whether the user has the specified permission. + /// + /// The entity to update. + /// The permission kind. + /// True if the user has the specified permission. + public static bool HasPermission(this IHasPermissions entity, PermissionKind kind) + { + return entity.Permissions.FirstOrDefault(p => p.Kind == kind)?.Value ?? false; + } + + /// + /// Sets the given permission kind to the provided value. + /// + /// The entity to update. + /// The permission kind. + /// The value to set. + public static void SetPermission(this IHasPermissions entity, PermissionKind kind, bool value) + { + var currentPermission = entity.Permissions.FirstOrDefault(p => p.Kind == kind); + if (currentPermission is null) + { + entity.Permissions.Add(new Permission(kind, value)); + } + else + { + currentPermission.Value = value; + } + } + + /// + /// Gets the user's preferences for the given preference kind. + /// + /// The entity to update. + /// The preference kind. + /// A string array containing the user's preferences. + public static string[] GetPreference(this User entity, PreferenceKind preference) + { + var val = entity.Preferences.FirstOrDefault(p => p.Kind == preference)?.Value; + + return string.IsNullOrEmpty(val) ? Array.Empty() : val.Split(Delimiter); + } + + /// + /// Gets the user's preferences for the given preference kind. + /// + /// The entity to update. + /// The preference kind. + /// Type of preference. + /// A {T} array containing the user's preference. + public static T[] GetPreferenceValues(this User entity, PreferenceKind preference) + { + var val = entity.Preferences.FirstOrDefault(p => p.Kind == preference)?.Value; + if (string.IsNullOrEmpty(val)) + { + return Array.Empty(); + } + + // Convert array of {string} to array of {T} + var converter = TypeDescriptor.GetConverter(typeof(T)); + var stringValues = val.Split(Delimiter); + var convertedCount = 0; + var parsedValues = new T[stringValues.Length]; + for (var i = 0; i < stringValues.Length; i++) + { + try + { + var parsedValue = converter.ConvertFromString(stringValues[i].Trim()); + if (parsedValue is not null) + { + parsedValues[convertedCount++] = (T)parsedValue; + } + } + catch (FormatException) + { + // Unable to convert value + } + } + + return parsedValues[..convertedCount]; + } + + /// + /// Sets the specified preference to the given value. + /// + /// The entity to update. + /// The preference kind. + /// The values. + public static void SetPreference(this User entity, PreferenceKind preference, string[] values) + { + var value = string.Join(Delimiter, values); + var currentPreference = entity.Preferences.FirstOrDefault(p => p.Kind == preference); + if (currentPreference is null) + { + entity.Preferences.Add(new Preference(preference, value)); + } + else + { + currentPreference.Value = value; + } + } + + /// + /// Sets the specified preference to the given value. + /// + /// The entity to update. + /// The preference kind. + /// The values. + /// The type of value. + public static void SetPreference(this User entity, PreferenceKind preference, T[] values) + { + var value = string.Join(Delimiter, values); + var currentPreference = entity.Preferences.FirstOrDefault(p => p.Kind == preference); + if (currentPreference is null) + { + entity.Preferences.Add(new Preference(preference, value)); + } + else + { + currentPreference.Value = value; + } + } + + /// + /// Checks whether this user is currently allowed to use the server. + /// + /// The entity to update. + /// True if the current time is within an access schedule, or there are no access schedules. + public static bool IsParentalScheduleAllowed(this User entity) + { + return entity.AccessSchedules.Count == 0 + || entity.AccessSchedules.Any(i => IsParentalScheduleAllowed(i, DateTime.UtcNow)); + } + + /// + /// Checks whether the provided folder is in this user's grouped folders. + /// + /// The entity to update. + /// The Guid of the folder. + /// True if the folder is in the user's grouped folders. + public static bool IsFolderGrouped(this User entity, Guid id) + { + return Array.IndexOf(GetPreferenceValues(entity, PreferenceKind.GroupedFolders), id) != -1; + } + + /// + /// Initializes the default permissions for a user. Should only be called on user creation. + /// + /// The entity to update. + // TODO: make these user configurable? + public static void AddDefaultPermissions(this User entity) + { + entity.Permissions.Add(new Permission(PermissionKind.IsAdministrator, false)); + entity.Permissions.Add(new Permission(PermissionKind.IsDisabled, false)); + entity.Permissions.Add(new Permission(PermissionKind.IsHidden, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnableAllChannels, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnableAllDevices, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnableAllFolders, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnableContentDeletion, false)); + entity.Permissions.Add(new Permission(PermissionKind.EnableContentDownloading, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnableMediaConversion, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnableMediaPlayback, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnablePlaybackRemuxing, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnablePublicSharing, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnableRemoteAccess, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnableSyncTranscoding, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnableAudioPlaybackTranscoding, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnableLiveTvAccess, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnableLiveTvManagement, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnableSharedDeviceControl, true)); + entity.Permissions.Add(new Permission(PermissionKind.EnableVideoPlaybackTranscoding, true)); + entity.Permissions.Add(new Permission(PermissionKind.ForceRemoteSourceTranscoding, false)); + entity.Permissions.Add(new Permission(PermissionKind.EnableRemoteControlOfOtherUsers, false)); + entity.Permissions.Add(new Permission(PermissionKind.EnableCollectionManagement, false)); + entity.Permissions.Add(new Permission(PermissionKind.EnableSubtitleManagement, false)); + entity.Permissions.Add(new Permission(PermissionKind.EnableLyricManagement, false)); + } + + /// + /// Initializes the default preferences. Should only be called on user creation. + /// + /// The entity to update. + public static void AddDefaultPreferences(this User entity) + { + foreach (var val in Enum.GetValues()) + { + entity.Preferences.Add(new Preference(val, string.Empty)); + } + } + + private static bool IsParentalScheduleAllowed(AccessSchedule schedule, DateTime date) + { + var localTime = date.ToLocalTime(); + var hour = localTime.TimeOfDay.TotalHours; + var currentDayOfWeek = localTime.DayOfWeek; + + return schedule.DayOfWeek.Contains(currentDayOfWeek) + && hour >= schedule.StartHour + && hour <= schedule.EndHour; + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs new file mode 100644 index 000000000..f534e49f3 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs @@ -0,0 +1,62 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using System.Xml.Serialization; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data.Entities +{ + /// + /// An entity representing a user's access schedule. + /// + public class AccessSchedule + { + /// + /// Initializes a new instance of the class. + /// + /// The day of the week. + /// The start hour. + /// The end hour. + /// The associated user's id. + public AccessSchedule(DynamicDayOfWeek dayOfWeek, double startHour, double endHour, Guid userId) + { + UserId = userId; + DayOfWeek = dayOfWeek; + StartHour = startHour; + EndHour = endHour; + } + + /// + /// Gets the id of this instance. + /// + /// + /// Identity, Indexed, Required. + /// + [XmlIgnore] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets the id of the associated user. + /// + [XmlIgnore] + public Guid UserId { get; private set; } + + /// + /// Gets or sets the day of week. + /// + /// The day of week. + public DynamicDayOfWeek DayOfWeek { get; set; } + + /// + /// Gets or sets the start hour. + /// + /// The start hour. + public double StartHour { get; set; } + + /// + /// Gets or sets the end hour. + /// + /// The end hour. + public double EndHour { get; set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs new file mode 100644 index 000000000..51dd0ffb8 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs @@ -0,0 +1,123 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Data.Entities +{ + /// + /// An entity referencing an activity log entry. + /// + public class ActivityLog : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// Public constructor with required data. + /// + /// The name. + /// The type. + /// The user id. + public ActivityLog(string name, string type, Guid userId) + { + ArgumentException.ThrowIfNullOrEmpty(name); + ArgumentException.ThrowIfNullOrEmpty(type); + + Name = name; + Type = type; + UserId = userId; + DateCreated = DateTime.UtcNow; + LogSeverity = LogLevel.Information; + } + + /// + /// Gets the identity of this instance. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the name. + /// + /// + /// Required, Max length = 512. + /// + [MaxLength(512)] + [StringLength(512)] + public string Name { get; set; } + + /// + /// Gets or sets the overview. + /// + /// + /// Max length = 512. + /// + [MaxLength(512)] + [StringLength(512)] + public string? Overview { get; set; } + + /// + /// Gets or sets the short overview. + /// + /// + /// Max length = 512. + /// + [MaxLength(512)] + [StringLength(512)] + public string? ShortOverview { get; set; } + + /// + /// Gets or sets the type. + /// + /// + /// Required, Max length = 256. + /// + [MaxLength(256)] + [StringLength(256)] + public string Type { get; set; } + + /// + /// Gets or sets the user id. + /// + /// + /// Required. + /// + public Guid UserId { get; set; } + + /// + /// Gets or sets the item id. + /// + /// + /// Max length = 256. + /// + [MaxLength(256)] + [StringLength(256)] + public string? ItemId { get; set; } + + /// + /// Gets or sets the date created. This should be in UTC. + /// + /// + /// Required. + /// + public DateTime DateCreated { get; set; } + + /// + /// Gets or sets the log severity. Default is . + /// + /// + /// Required. + /// + public LogLevel LogSeverity { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AncestorId.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AncestorId.cs new file mode 100644 index 000000000..ef0fe0ba7 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AncestorId.cs @@ -0,0 +1,29 @@ +using System; + +namespace Jellyfin.Data.Entities; + +/// +/// Represents the relational informations for an . +/// +public class AncestorId +{ + /// + /// Gets or Sets the AncestorId. + /// + public required Guid ParentItemId { get; set; } + + /// + /// Gets or Sets the related BaseItem. + /// + public required Guid ItemId { get; set; } + + /// + /// Gets or Sets the ParentItem. + /// + public required BaseItemEntity ParentItem { get; set; } + + /// + /// Gets or Sets the Child item. + /// + public required BaseItemEntity Item { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs new file mode 100644 index 000000000..77b627f37 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs @@ -0,0 +1,49 @@ +using System; + +namespace Jellyfin.Data.Entities; + +/// +/// Provides informations about an Attachment to an . +/// +public class AttachmentStreamInfo +{ + /// + /// Gets or Sets the reference. + /// + public required Guid ItemId { get; set; } + + /// + /// Gets or Sets the reference. + /// + public required BaseItemEntity Item { get; set; } + + /// + /// Gets or Sets The index within the source file. + /// + public required int Index { get; set; } + + /// + /// Gets or Sets the codec of the attachment. + /// + public required string Codec { get; set; } + + /// + /// Gets or Sets the codec tag of the attachment. + /// + public string? CodecTag { get; set; } + + /// + /// Gets or Sets the comment of the attachment. + /// + public string? Comment { get; set; } + + /// + /// Gets or Sets the filename of the attachment. + /// + public string? Filename { get; set; } + + /// + /// Gets or Sets the attachments mimetype. + /// + public string? MimeType { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs new file mode 100644 index 000000000..33b2b6741 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs @@ -0,0 +1,186 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CA2227 // Collection properties should be read only + +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Jellyfin.Data.Entities; + +public class BaseItemEntity +{ + public required Guid Id { get; set; } + + public required string Type { get; set; } + + public string? Data { get; set; } + + public string? Path { get; set; } + + public DateTime StartDate { get; set; } + + public DateTime EndDate { get; set; } + + public string? ChannelId { get; set; } + + public bool IsMovie { get; set; } + + public float? CommunityRating { get; set; } + + public string? CustomRating { get; set; } + + public int? IndexNumber { get; set; } + + public bool IsLocked { get; set; } + + public string? Name { get; set; } + + public string? OfficialRating { get; set; } + + public string? MediaType { get; set; } + + public string? Overview { get; set; } + + public int? ParentIndexNumber { get; set; } + + public DateTime? PremiereDate { get; set; } + + public int? ProductionYear { get; set; } + + public string? Genres { get; set; } + + public string? SortName { get; set; } + + public string? ForcedSortName { get; set; } + + public long? RunTimeTicks { get; set; } + + public DateTime? DateCreated { get; set; } + + public DateTime? DateModified { get; set; } + + public bool IsSeries { get; set; } + + public string? EpisodeTitle { get; set; } + + public bool IsRepeat { get; set; } + + public string? PreferredMetadataLanguage { get; set; } + + public string? PreferredMetadataCountryCode { get; set; } + + public DateTime? DateLastRefreshed { get; set; } + + public DateTime? DateLastSaved { get; set; } + + public bool IsInMixedFolder { get; set; } + + public string? Studios { get; set; } + + public string? ExternalServiceId { get; set; } + + public string? Tags { get; set; } + + public bool IsFolder { get; set; } + + public int? InheritedParentalRatingValue { get; set; } + + public string? UnratedType { get; set; } + + public float? CriticRating { get; set; } + + public string? CleanName { get; set; } + + public string? PresentationUniqueKey { get; set; } + + public string? OriginalTitle { get; set; } + + public string? PrimaryVersionId { get; set; } + + public DateTime? DateLastMediaAdded { get; set; } + + public string? Album { get; set; } + + public float? LUFS { get; set; } + + public float? NormalizationGain { get; set; } + + public bool IsVirtualItem { get; set; } + + public string? SeriesName { get; set; } + + public string? SeasonName { get; set; } + + public string? ExternalSeriesId { get; set; } + + public string? Tagline { get; set; } + + public string? ProductionLocations { get; set; } + + public string? ExtraIds { get; set; } + + public int? TotalBitrate { get; set; } + + public BaseItemExtraType? ExtraType { get; set; } + + public string? Artists { get; set; } + + public string? AlbumArtists { get; set; } + + public string? ExternalId { get; set; } + + public string? SeriesPresentationUniqueKey { get; set; } + + public string? ShowId { get; set; } + + public string? OwnerId { get; set; } + + public int? Width { get; set; } + + public int? Height { get; set; } + + public long? Size { get; set; } + + public ProgramAudioEntity? Audio { get; set; } + + public Guid? ParentId { get; set; } + + public Guid? TopParentId { get; set; } + + public Guid? SeasonId { get; set; } + + public Guid? SeriesId { get; set; } + + public ICollection? Peoples { get; set; } + + public ICollection? UserData { get; set; } + + public ICollection? ItemValues { get; set; } + + public ICollection? MediaStreams { get; set; } + + public ICollection? Chapters { get; set; } + + public ICollection? Provider { get; set; } + + public ICollection? ParentAncestors { get; set; } + + public ICollection? Children { get; set; } + + public ICollection? LockedFields { get; set; } + + public ICollection? TrailerTypes { get; set; } + + public ICollection? Images { get; set; } + + // those are references to __LOCAL__ ids not DB ids ... TODO: Bring the whole folder structure into the DB + // public ICollection? SeriesEpisodes { get; set; } + // public BaseItemEntity? Series { get; set; } + // public BaseItemEntity? Season { get; set; } + // public BaseItemEntity? Parent { get; set; } + // public ICollection? DirectChildren { get; set; } + // public BaseItemEntity? TopParent { get; set; } + // public ICollection? AllChildren { get; set; } + // public ICollection? SeasonEpisodes { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemExtraType.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemExtraType.cs new file mode 100644 index 000000000..54aef50e4 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemExtraType.cs @@ -0,0 +1,18 @@ +#pragma warning disable CS1591 +namespace Jellyfin.Data.Entities; + +public enum BaseItemExtraType +{ + Unknown = 0, + Clip = 1, + Trailer = 2, + BehindTheScenes = 3, + DeletedScene = 4, + Interview = 5, + Scene = 6, + Sample = 7, + ThemeSong = 8, + ThemeVideo = 9, + Featurette = 10, + Short = 11 +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs new file mode 100644 index 000000000..37723df11 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs @@ -0,0 +1,59 @@ +#pragma warning disable CA2227 + +using System; +using System.Collections.Generic; + +namespace Jellyfin.Data.Entities; + +/// +/// Enum TrailerTypes. +/// +public class BaseItemImageInfo +{ + /// + /// Gets or Sets. + /// + public required Guid Id { get; set; } + + /// + /// Gets or Sets the path to the original image. + /// + public required string Path { get; set; } + + /// + /// Gets or Sets the time the image was last modified. + /// + public DateTime DateModified { get; set; } + + /// + /// Gets or Sets the imagetype. + /// + public ImageInfoImageType ImageType { get; set; } + + /// + /// Gets or Sets the width of the original image. + /// + public int Width { get; set; } + + /// + /// Gets or Sets the height of the original image. + /// + public int Height { get; set; } + +#pragma warning disable CA1819 // Properties should not return arrays + /// + /// Gets or Sets the blurhash. + /// + public byte[]? Blurhash { get; set; } +#pragma warning restore CA1819 + + /// + /// Gets or Sets the reference id to the BaseItem. + /// + public required Guid ItemId { get; set; } + + /// + /// Gets or Sets the referenced Item. + /// + public required BaseItemEntity Item { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemMetadataField.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemMetadataField.cs new file mode 100644 index 000000000..c9d44c046 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemMetadataField.cs @@ -0,0 +1,24 @@ +using System; + +namespace Jellyfin.Data.Entities; + +/// +/// Enum MetadataFields. +/// +public class BaseItemMetadataField +{ + /// + /// Gets or Sets Numerical ID of this enumeratable. + /// + public required int Id { get; set; } + + /// + /// Gets or Sets all referenced . + /// + public required Guid ItemId { get; set; } + + /// + /// Gets or Sets all referenced . + /// + public required BaseItemEntity Item { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs new file mode 100644 index 000000000..9a1565728 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Jellyfin.Data.Entities; + +/// +/// Represents a Key-Value relation of an BaseItem's provider. +/// +public class BaseItemProvider +{ + /// + /// Gets or Sets the reference ItemId. + /// + public Guid ItemId { get; set; } + + /// + /// Gets or Sets the reference BaseItem. + /// + public required BaseItemEntity Item { get; set; } + + /// + /// Gets or Sets the ProvidersId. + /// + public required string ProviderId { get; set; } + + /// + /// Gets or Sets the Providers Value. + /// + public required string ProviderValue { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemTrailerType.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemTrailerType.cs new file mode 100644 index 000000000..fb31fc8a4 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemTrailerType.cs @@ -0,0 +1,24 @@ +using System; + +namespace Jellyfin.Data.Entities; + +/// +/// Enum TrailerTypes. +/// +public class BaseItemTrailerType +{ + /// + /// Gets or Sets Numerical ID of this enumeratable. + /// + public required int Id { get; set; } + + /// + /// Gets or Sets all referenced . + /// + public required Guid ItemId { get; set; } + + /// + /// Gets or Sets all referenced . + /// + public required BaseItemEntity Item { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Chapter.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Chapter.cs new file mode 100644 index 000000000..579442cdb --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Chapter.cs @@ -0,0 +1,44 @@ +using System; + +namespace Jellyfin.Data.Entities; + +/// +/// The Chapter entity. +/// +public class Chapter +{ + /// + /// Gets or Sets the reference id. + /// + public required Guid ItemId { get; set; } + + /// + /// Gets or Sets the reference. + /// + public required BaseItemEntity Item { get; set; } + + /// + /// Gets or Sets the chapters index in Item. + /// + public required int ChapterIndex { get; set; } + + /// + /// Gets or Sets the position within the source file. + /// + public required long StartPositionTicks { get; set; } + + /// + /// Gets or Sets the common name. + /// + public string? Name { get; set; } + + /// + /// Gets or Sets the image path. + /// + public string? ImagePath { get; set; } + + /// + /// Gets or Sets the time the image was last modified. + /// + public DateTime? ImageDateModified { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/CustomItemDisplayPreferences.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/CustomItemDisplayPreferences.cs new file mode 100644 index 000000000..a60659512 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/CustomItemDisplayPreferences.cs @@ -0,0 +1,80 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Jellyfin.Data.Entities +{ + /// + /// An entity that represents a user's custom display preferences for a specific item. + /// + public class CustomItemDisplayPreferences + { + /// + /// Initializes a new instance of the class. + /// + /// The user id. + /// The item id. + /// The client. + /// The preference key. + /// The preference value. + public CustomItemDisplayPreferences(Guid userId, Guid itemId, string client, string key, string? value) + { + UserId = userId; + ItemId = itemId; + Client = client; + Key = key; + Value = value; + } + + /// + /// Gets the Id. + /// + /// + /// Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the user Id. + /// + /// + /// Required. + /// + public Guid UserId { get; set; } + + /// + /// Gets or sets the id of the associated item. + /// + /// + /// Required. + /// + public Guid ItemId { get; set; } + + /// + /// Gets or sets the client string. + /// + /// + /// Required. Max Length = 32. + /// + [MaxLength(32)] + [StringLength(32)] + public string Client { get; set; } + + /// + /// Gets or sets the preference key. + /// + /// + /// Required. + /// + public string Key { get; set; } + + /// + /// Gets or sets the preference value. + /// + /// + /// Required. + /// + public string? Value { get; set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs new file mode 100644 index 000000000..f0be65769 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data.Entities +{ + /// + /// An entity representing a user's display preferences. + /// + public class DisplayPreferences + { + /// + /// Initializes a new instance of the class. + /// + /// The user's id. + /// The item id. + /// The client string. + public DisplayPreferences(Guid userId, Guid itemId, string client) + { + UserId = userId; + ItemId = itemId; + Client = client; + ShowSidebar = false; + ShowBackdrop = true; + SkipForwardLength = 30000; + SkipBackwardLength = 10000; + ScrollDirection = ScrollDirection.Horizontal; + ChromecastVersion = ChromecastVersion.Stable; + + HomeSections = new HashSet(); + } + + /// + /// Gets the Id. + /// + /// + /// Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the user Id. + /// + /// + /// Required. + /// + public Guid UserId { get; set; } + + /// + /// Gets or sets the id of the associated item. + /// + /// + /// Required. + /// + public Guid ItemId { get; set; } + + /// + /// Gets or sets the client string. + /// + /// + /// Required. Max Length = 32. + /// + [MaxLength(32)] + [StringLength(32)] + public string Client { get; set; } + + /// + /// Gets or sets a value indicating whether to show the sidebar. + /// + /// + /// Required. + /// + public bool ShowSidebar { get; set; } + + /// + /// Gets or sets a value indicating whether to show the backdrop. + /// + /// + /// Required. + /// + public bool ShowBackdrop { get; set; } + + /// + /// Gets or sets the scroll direction. + /// + /// + /// Required. + /// + public ScrollDirection ScrollDirection { get; set; } + + /// + /// Gets or sets what the view should be indexed by. + /// + public IndexingKind? IndexBy { get; set; } + + /// + /// Gets or sets the length of time to skip forwards, in milliseconds. + /// + /// + /// Required. + /// + public int SkipForwardLength { get; set; } + + /// + /// Gets or sets the length of time to skip backwards, in milliseconds. + /// + /// + /// Required. + /// + public int SkipBackwardLength { get; set; } + + /// + /// Gets or sets the Chromecast Version. + /// + /// + /// Required. + /// + public ChromecastVersion ChromecastVersion { get; set; } + + /// + /// Gets or sets a value indicating whether the next video info overlay should be shown. + /// + /// + /// Required. + /// + public bool EnableNextVideoInfoOverlay { get; set; } + + /// + /// Gets or sets the dashboard theme. + /// + [MaxLength(32)] + [StringLength(32)] + public string? DashboardTheme { get; set; } + + /// + /// Gets or sets the tv home screen. + /// + [MaxLength(32)] + [StringLength(32)] + public string? TvHome { get; set; } + + /// + /// Gets the home sections. + /// + public virtual ICollection HomeSections { get; private set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs new file mode 100644 index 000000000..09f237289 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities +{ + /// + /// An entity representing a group. + /// + public class Group : IHasPermissions, IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The name of the group. + public Group(string name) + { + ArgumentException.ThrowIfNullOrEmpty(name); + + Name = name; + Id = Guid.NewGuid(); + + Permissions = new HashSet(); + Preferences = new HashSet(); + } + + /// + /// Gets the id of this group. + /// + /// + /// Identity, Indexed, Required. + /// + public Guid Id { get; private set; } + + /// + /// Gets or sets the group's name. + /// + /// + /// Required, Max length = 255. + /// + [MaxLength(255)] + [StringLength(255)] + public string Name { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets a collection containing the group's permissions. + /// + public virtual ICollection Permissions { get; private set; } + + /// + /// Gets a collection containing the group's preferences. + /// + public virtual ICollection Preferences { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs new file mode 100644 index 000000000..8dd6e647e --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs @@ -0,0 +1,44 @@ +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data.Entities +{ + /// + /// An entity representing a section on the user's home page. + /// + public class HomeSection + { + /// + /// Gets the id. + /// + /// + /// Identity. Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the Id of the associated display preferences. + /// + /// + /// Required. + /// + public int DisplayPreferencesId { get; set; } + + /// + /// Gets or sets the order. + /// + /// + /// Required. + /// + public int Order { get; set; } + + /// + /// Gets or sets the type. + /// + /// + /// Required. + /// + public HomeSectionType Type { get; set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfo.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfo.cs new file mode 100644 index 000000000..935a53a26 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfo.cs @@ -0,0 +1,54 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Jellyfin.Data.Entities +{ + /// + /// An entity representing an image. + /// + public class ImageInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The path. + public ImageInfo(string path) + { + Path = path; + LastModified = DateTime.UtcNow; + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets the user id. + /// + public Guid? UserId { get; private set; } + + /// + /// Gets or sets the path of the image. + /// + /// + /// Required. + /// + [MaxLength(512)] + [StringLength(512)] + public string Path { get; set; } + + /// + /// Gets or sets the date last modified. + /// + /// + /// Required. + /// + public DateTime LastModified { get; set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfoImageType.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfoImageType.cs new file mode 100644 index 000000000..f78178dd2 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfoImageType.cs @@ -0,0 +1,76 @@ +namespace Jellyfin.Data.Entities; + +/// +/// Enum ImageType. +/// +public enum ImageInfoImageType +{ + /// + /// The primary. + /// + Primary = 0, + + /// + /// The art. + /// + Art = 1, + + /// + /// The backdrop. + /// + Backdrop = 2, + + /// + /// The banner. + /// + Banner = 3, + + /// + /// The logo. + /// + Logo = 4, + + /// + /// The thumb. + /// + Thumb = 5, + + /// + /// The disc. + /// + Disc = 6, + + /// + /// The box. + /// + Box = 7, + + /// + /// The screenshot. + /// + /// + /// This enum value is obsolete. + /// XmlSerializer does not serialize/deserialize objects that are marked as [Obsolete]. + /// + Screenshot = 8, + + /// + /// The menu. + /// + Menu = 9, + + /// + /// The chapter image. + /// + Chapter = 10, + + /// + /// The box rear. + /// + BoxRear = 11, + + /// + /// The user profile image. + /// + Profile = 12 +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs new file mode 100644 index 000000000..93e6664ea --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs @@ -0,0 +1,113 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data.Entities +{ + /// + /// An entity that represents a user's display preferences for a specific item. + /// + public class ItemDisplayPreferences + { + /// + /// Initializes a new instance of the class. + /// + /// The user id. + /// The item id. + /// The client. + public ItemDisplayPreferences(Guid userId, Guid itemId, string client) + { + UserId = userId; + ItemId = itemId; + Client = client; + + SortBy = "SortName"; + SortOrder = SortOrder.Ascending; + RememberSorting = false; + RememberIndexing = false; + } + + /// + /// Gets the id. + /// + /// + /// Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the user Id. + /// + /// + /// Required. + /// + public Guid UserId { get; set; } + + /// + /// Gets or sets the id of the associated item. + /// + /// + /// Required. + /// + public Guid ItemId { get; set; } + + /// + /// Gets or sets the client string. + /// + /// + /// Required. Max Length = 32. + /// + [MaxLength(32)] + [StringLength(32)] + public string Client { get; set; } + + /// + /// Gets or sets the view type. + /// + /// + /// Required. + /// + public ViewType ViewType { get; set; } + + /// + /// Gets or sets a value indicating whether the indexing should be remembered. + /// + /// + /// Required. + /// + public bool RememberIndexing { get; set; } + + /// + /// Gets or sets what the view should be indexed by. + /// + public IndexingKind? IndexBy { get; set; } + + /// + /// Gets or sets a value indicating whether the sorting type should be remembered. + /// + /// + /// Required. + /// + public bool RememberSorting { get; set; } + + /// + /// Gets or sets what the view should be sorted by. + /// + /// + /// Required. + /// + [MaxLength(64)] + [StringLength(64)] + public string SortBy { get; set; } + + /// + /// Gets or sets the sort order. + /// + /// + /// Required. + /// + public SortOrder SortOrder { get; set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValue.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValue.cs new file mode 100644 index 000000000..7b1048c10 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValue.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; + +namespace Jellyfin.Data.Entities; + +/// +/// Represents an ItemValue for a BaseItem. +/// +public class ItemValue +{ + /// + /// Gets or Sets the ItemValueId. + /// + public required Guid ItemValueId { get; set; } + + /// + /// Gets or Sets the Type. + /// + public required ItemValueType Type { get; set; } + + /// + /// Gets or Sets the Value. + /// + public required string Value { get; set; } + + /// + /// Gets or Sets the sanatised Value. + /// + public required string CleanValue { get; set; } + + /// + /// Gets or Sets all associated BaseItems. + /// +#pragma warning disable CA2227 // Collection properties should be read only + public ICollection? BaseItemsMap { get; set; } +#pragma warning restore CA2227 // Collection properties should be read only +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs new file mode 100644 index 000000000..94db6a011 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; + +namespace Jellyfin.Data.Entities; + +/// +/// Mapping table for the ItemValue BaseItem relation. +/// +public class ItemValueMap +{ + /// + /// Gets or Sets the ItemId. + /// + public required Guid ItemId { get; set; } + + /// + /// Gets or Sets the ItemValueId. + /// + public required Guid ItemValueId { get; set; } + + /// + /// Gets or Sets the referenced . + /// + public required BaseItemEntity Item { get; set; } + + /// + /// Gets or Sets the referenced . + /// + public required ItemValue ItemValue { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueType.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueType.cs new file mode 100644 index 000000000..3bae3becc --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueType.cs @@ -0,0 +1,38 @@ +#pragma warning disable CA1027 // Mark enums with FlagsAttribute +namespace Jellyfin.Data.Entities; + +/// +/// Provides the Value types for an . +/// +public enum ItemValueType +{ + /// + /// Artists. + /// + Artist = 0, + + /// + /// Album. + /// + AlbumArtist = 1, + + /// + /// Genre. + /// + Genre = 2, + + /// + /// Studios. + /// + Studios = 3, + + /// + /// Tags. + /// + Tags = 4, + + /// + /// InheritedTags. + /// + InheritedTags = 6, +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs new file mode 100644 index 000000000..fc3c1036f --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs @@ -0,0 +1,64 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing artwork. + /// + public class Artwork : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The path. + /// The kind of art. + public Artwork(string path, ArtKind kind) + { + ArgumentException.ThrowIfNullOrEmpty(path); + + Path = path; + Kind = kind; + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the path. + /// + /// + /// Required, Max length = 65535. + /// + [MaxLength(65535)] + [StringLength(65535)] + public string Path { get; set; } + + /// + /// Gets or sets the kind of artwork. + /// + /// + /// Required. + /// + public ArtKind Kind { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs new file mode 100644 index 000000000..a838686d0 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a book. + /// + public class Book : LibraryItem, IHasReleases + { + /// + /// Initializes a new instance of the class. + /// + /// The library. + public Book(Library library) : base(library) + { + BookMetadata = new HashSet(); + Releases = new HashSet(); + } + + /// + /// Gets a collection containing the metadata for this book. + /// + public virtual ICollection BookMetadata { get; private set; } + + /// + public virtual ICollection Releases { get; private set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs new file mode 100644 index 000000000..4a350d200 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity containing metadata for a book. + /// + public class BookMetadata : ItemMetadata, IHasCompanies + { + /// + /// Initializes a new instance of the class. + /// + /// The title or name of the object. + /// ISO-639-3 3-character language codes. + public BookMetadata(string title, string language) : base(title, language) + { + Publishers = new HashSet(); + } + + /// + /// Gets or sets the ISBN. + /// + public long? Isbn { get; set; } + + /// + /// Gets a collection of the publishers for this book. + /// + public virtual ICollection Publishers { get; private set; } + + /// + public ICollection Companies => Publishers; + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs new file mode 100644 index 000000000..f068338f9 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs @@ -0,0 +1,80 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a chapter. + /// + public class Chapter : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// ISO-639-3 3-character language codes. + /// The start time for this chapter. + public Chapter(string language, long startTime) + { + ArgumentException.ThrowIfNullOrEmpty(language); + + Language = language; + StartTime = startTime; + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the name. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? Name { get; set; } + + /// + /// Gets or sets the language. + /// + /// + /// Required, Min length = 3, Max length = 3 + /// ISO-639-3 3-character language codes. + /// + [MinLength(3)] + [MaxLength(3)] + [StringLength(3)] + public string Language { get; set; } + + /// + /// Gets or sets the start time. + /// + /// + /// Required. + /// + public long StartTime { get; set; } + + /// + /// Gets or sets the end time. + /// + public long? EndTime { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs new file mode 100644 index 000000000..7de601969 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs @@ -0,0 +1,57 @@ +#pragma warning disable CA1711 // Identifiers should not have incorrect suffix + +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a collection. + /// + public class Collection : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + public Collection() + { + Items = new HashSet(); + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the name. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? Name { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets a collection containing this collection's items. + /// + public virtual ICollection Items { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs new file mode 100644 index 000000000..0cb4716db --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs @@ -0,0 +1,64 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a collection item. + /// + public class CollectionItem : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The library item. + public CollectionItem(LibraryItem libraryItem) + { + LibraryItem = libraryItem; + } + + /// + /// Gets or sets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets or sets the library item. + /// + /// + /// Required. + /// + public virtual LibraryItem LibraryItem { get; set; } + + /// + /// Gets or sets the next item in the collection. + /// + /// + /// TODO check if this properly updated Dependant and has the proper principal relationship. + /// + public virtual CollectionItem? Next { get; set; } + + /// + /// Gets or sets the previous item in the collection. + /// + /// + /// TODO check if this properly updated Dependant and has the proper principal relationship. + /// + public virtual CollectionItem? Previous { get; set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs new file mode 100644 index 000000000..1abbee445 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a company. + /// + public class Company : IHasCompanies, IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + public Company() + { + CompanyMetadata = new HashSet(); + ChildCompanies = new HashSet(); + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets a collection containing the metadata. + /// + public virtual ICollection CompanyMetadata { get; private set; } + + /// + /// Gets a collection containing this company's child companies. + /// + public virtual ICollection ChildCompanies { get; private set; } + + /// + public ICollection Companies => ChildCompanies; + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CompanyMetadata.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CompanyMetadata.cs new file mode 100644 index 000000000..a29f08c7f --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CompanyMetadata.cs @@ -0,0 +1,59 @@ +using System.ComponentModel.DataAnnotations; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity holding metadata for a . + /// + public class CompanyMetadata : ItemMetadata + { + /// + /// Initializes a new instance of the class. + /// + /// The title or name of the object. + /// ISO-639-3 3-character language codes. + public CompanyMetadata(string title, string language) : base(title, language) + { + } + + /// + /// Gets or sets the description. + /// + /// + /// Max length = 65535. + /// + [MaxLength(65535)] + [StringLength(65535)] + public string? Description { get; set; } + + /// + /// Gets or sets the headquarters. + /// + /// + /// Max length = 255. + /// + [MaxLength(255)] + [StringLength(255)] + public string? Headquarters { get; set; } + + /// + /// Gets or sets the country code. + /// + /// + /// Max length = 2. + /// + [MaxLength(2)] + [StringLength(2)] + public string? Country { get; set; } + + /// + /// Gets or sets the homepage. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? Homepage { get; set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs new file mode 100644 index 000000000..e27d01d86 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a custom item. + /// + public class CustomItem : LibraryItem, IHasReleases + { + /// + /// Initializes a new instance of the class. + /// + /// The library. + public CustomItem(Library library) : base(library) + { + CustomItemMetadata = new HashSet(); + Releases = new HashSet(); + } + + /// + /// Gets a collection containing the metadata for this item. + /// + public virtual ICollection CustomItemMetadata { get; private set; } + + /// + public virtual ICollection Releases { get; private set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItemMetadata.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItemMetadata.cs new file mode 100644 index 000000000..af2393870 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItemMetadata.cs @@ -0,0 +1,17 @@ +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity containing metadata for a custom item. + /// + public class CustomItemMetadata : ItemMetadata + { + /// + /// Initializes a new instance of the class. + /// + /// The title or name of the object. + /// ISO-639-3 3-character language codes. + public CustomItemMetadata(string title, string language) : base(title, language) + { + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs new file mode 100644 index 000000000..ce2f0c617 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing an episode. + /// + public class Episode : LibraryItem, IHasReleases + { + /// + /// Initializes a new instance of the class. + /// + /// The library. + public Episode(Library library) : base(library) + { + Releases = new HashSet(); + EpisodeMetadata = new HashSet(); + } + + /// + /// Gets or sets the episode number. + /// + public int? EpisodeNumber { get; set; } + + /// + public virtual ICollection Releases { get; private set; } + + /// + /// Gets a collection containing the metadata for this episode. + /// + public virtual ICollection EpisodeMetadata { get; private set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/EpisodeMetadata.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/EpisodeMetadata.cs new file mode 100644 index 000000000..b0ef11e0f --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/EpisodeMetadata.cs @@ -0,0 +1,49 @@ +using System.ComponentModel.DataAnnotations; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity containing metadata for an . + /// + public class EpisodeMetadata : ItemMetadata + { + /// + /// Initializes a new instance of the class. + /// + /// The title or name of the object. + /// ISO-639-3 3-character language codes. + public EpisodeMetadata(string title, string language) : base(title, language) + { + } + + /// + /// Gets or sets the outline. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? Outline { get; set; } + + /// + /// Gets or sets the plot. + /// + /// + /// Max length = 65535. + /// + [MaxLength(65535)] + [StringLength(65535)] + public string? Plot { get; set; } + + /// + /// Gets or sets the tagline. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? Tagline { get; set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs new file mode 100644 index 000000000..3b822ee82 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs @@ -0,0 +1,50 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a genre. + /// + public class Genre : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The name. + public Genre(string name) + { + Name = name; + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the name. + /// + /// + /// Indexed, Required, Max length = 255. + /// + [MaxLength(255)] + [StringLength(255)] + public string Name { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs new file mode 100644 index 000000000..fa9276c66 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An abstract class that holds metadata. + /// + public abstract class ItemMetadata : IHasArtwork, IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The title or name of the object. + /// ISO-639-3 3-character language codes. + protected ItemMetadata(string title, string language) + { + ArgumentException.ThrowIfNullOrEmpty(title); + ArgumentException.ThrowIfNullOrEmpty(language); + + Title = title; + Language = language; + DateAdded = DateTime.UtcNow; + DateModified = DateAdded; + + PersonRoles = new HashSet(); + Genres = new HashSet(); + Artwork = new HashSet(); + Ratings = new HashSet(); + Sources = new HashSet(); + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the title. + /// + /// + /// Required, Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string Title { get; set; } + + /// + /// Gets or sets the original title. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? OriginalTitle { get; set; } + + /// + /// Gets or sets the sort title. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? SortTitle { get; set; } + + /// + /// Gets or sets the language. + /// + /// + /// Required, Min length = 3, Max length = 3. + /// ISO-639-3 3-character language codes. + /// + [MinLength(3)] + [MaxLength(3)] + [StringLength(3)] + public string Language { get; set; } + + /// + /// Gets or sets the release date. + /// + public DateTimeOffset? ReleaseDate { get; set; } + + /// + /// Gets the date added. + /// + /// + /// Required. + /// + public DateTime DateAdded { get; private set; } + + /// + /// Gets or sets the date modified. + /// + /// + /// Required. + /// + public DateTime DateModified { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets a collection containing the person roles for this item. + /// + public virtual ICollection PersonRoles { get; private set; } + + /// + /// Gets a collection containing the genres for this item. + /// + public virtual ICollection Genres { get; private set; } + + /// + public virtual ICollection Artwork { get; private set; } + + /// + /// Gets a collection containing the ratings for this item. + /// + public virtual ICollection Ratings { get; private set; } + + /// + /// Gets a collection containing the metadata sources for this item. + /// + public virtual ICollection Sources { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs new file mode 100644 index 000000000..0db42a1c7 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs @@ -0,0 +1,60 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a library. + /// + public class Library : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The name of the library. + /// The path of the library. + public Library(string name, string path) + { + Name = name; + Path = path; + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the name. + /// + /// + /// Required, Max length = 128. + /// + [MaxLength(128)] + [StringLength(128)] + public string Name { get; set; } + + /// + /// Gets or sets the root path of the library. + /// + /// + /// Required. + /// + public string Path { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs new file mode 100644 index 000000000..d889b871e --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs @@ -0,0 +1,55 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a library item. + /// + public abstract class LibraryItem : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The library of this item. + protected LibraryItem(Library library) + { + DateAdded = DateTime.UtcNow; + Library = library; + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets the date this library item was added. + /// + public DateTime DateAdded { get; private set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets or sets the library of this item. + /// + /// + /// Required. + /// + public virtual Library Library { get; set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs new file mode 100644 index 000000000..7b5a3af64 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a file on disk. + /// + public class MediaFile : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The path relative to the LibraryRoot. + /// The file kind. + public MediaFile(string path, MediaFileKind kind) + { + ArgumentException.ThrowIfNullOrEmpty(path); + + Path = path; + Kind = kind; + + MediaFileStreams = new HashSet(); + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the path relative to the library root. + /// + /// + /// Required, Max length = 65535. + /// + [MaxLength(65535)] + [StringLength(65535)] + public string Path { get; set; } + + /// + /// Gets or sets the kind of media file. + /// + /// + /// Required. + /// + public MediaFileKind Kind { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets a collection containing the streams in this file. + /// + public virtual ICollection MediaFileStreams { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs new file mode 100644 index 000000000..e24e73ecb --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs @@ -0,0 +1,50 @@ +#pragma warning disable CA1711 // Identifiers should not have incorrect suffix + +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a stream in a media file. + /// + public class MediaFileStream : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The number of this stream. + public MediaFileStream(int streamNumber) + { + StreamNumber = streamNumber; + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the stream number. + /// + /// + /// Required. + /// + public int StreamNumber { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs new file mode 100644 index 000000000..b38d6a4f1 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs @@ -0,0 +1,53 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a metadata provider. + /// + public class MetadataProvider : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The name of the metadata provider. + public MetadataProvider(string name) + { + ArgumentException.ThrowIfNullOrEmpty(name); + + Name = name; + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the name. + /// + /// + /// Required, Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string Name { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs new file mode 100644 index 000000000..a198f53ba --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs @@ -0,0 +1,63 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a unique identifier for a metadata provider. + /// + public class MetadataProviderId : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The provider id. + /// The metadata provider. + public MetadataProviderId(string providerId, MetadataProvider metadataProvider) + { + ArgumentException.ThrowIfNullOrEmpty(providerId); + + ProviderId = providerId; + MetadataProvider = metadataProvider; + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the provider id. + /// + /// + /// Required, Max length = 255. + /// + [MaxLength(255)] + [StringLength(255)] + public string ProviderId { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets or sets the metadata provider. + /// + /// + /// Required. + /// + public virtual MetadataProvider MetadataProvider { get; set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs new file mode 100644 index 000000000..499fafd0e --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a movie. + /// + public class Movie : LibraryItem, IHasReleases + { + /// + /// Initializes a new instance of the class. + /// + /// The library. + public Movie(Library library) : base(library) + { + Releases = new HashSet(); + MovieMetadata = new HashSet(); + } + + /// + public virtual ICollection Releases { get; private set; } + + /// + /// Gets a collection containing the metadata for this movie. + /// + public virtual ICollection MovieMetadata { get; private set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs new file mode 100644 index 000000000..44b5f34d7 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity holding the metadata for a movie. + /// + public class MovieMetadata : ItemMetadata, IHasCompanies + { + /// + /// Initializes a new instance of the class. + /// + /// The title or name of the movie. + /// ISO-639-3 3-character language codes. + public MovieMetadata(string title, string language) : base(title, language) + { + Studios = new HashSet(); + } + + /// + /// Gets or sets the outline. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? Outline { get; set; } + + /// + /// Gets or sets the tagline. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? Tagline { get; set; } + + /// + /// Gets or sets the plot. + /// + /// + /// Max length = 65535. + /// + [MaxLength(65535)] + [StringLength(65535)] + public string? Plot { get; set; } + + /// + /// Gets or sets the country code. + /// + /// + /// Max length = 2. + /// + [MaxLength(2)] + [StringLength(2)] + public string? Country { get; set; } + + /// + /// Gets the studios that produced this movie. + /// + public virtual ICollection Studios { get; private set; } + + /// + public ICollection Companies => Studios; + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbum.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbum.cs new file mode 100644 index 000000000..d6231bbf0 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbum.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a music album. + /// + public class MusicAlbum : LibraryItem + { + /// + /// Initializes a new instance of the class. + /// + /// The library. + public MusicAlbum(Library library) : base(library) + { + MusicAlbumMetadata = new HashSet(); + Tracks = new HashSet(); + } + + /// + /// Gets a collection containing the album metadata. + /// + public virtual ICollection MusicAlbumMetadata { get; private set; } + + /// + /// Gets a collection containing the tracks. + /// + public virtual ICollection Tracks { get; private set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbumMetadata.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbumMetadata.cs new file mode 100644 index 000000000..691f3504f --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbumMetadata.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity holding the metadata for a music album. + /// + public class MusicAlbumMetadata : ItemMetadata + { + /// + /// Initializes a new instance of the class. + /// + /// The title or name of the album. + /// ISO-639-3 3-character language codes. + public MusicAlbumMetadata(string title, string language) : base(title, language) + { + Labels = new HashSet(); + } + + /// + /// Gets or sets the barcode. + /// + /// + /// Max length = 255. + /// + [MaxLength(255)] + [StringLength(255)] + public string? Barcode { get; set; } + + /// + /// Gets or sets the label number. + /// + /// + /// Max length = 255. + /// + [MaxLength(255)] + [StringLength(255)] + public string? LabelNumber { get; set; } + + /// + /// Gets or sets the country code. + /// + /// + /// Max length = 2. + /// + [MaxLength(2)] + [StringLength(2)] + public string? Country { get; set; } + + /// + /// Gets a collection containing the labels. + /// + public virtual ICollection Labels { get; private set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs new file mode 100644 index 000000000..90dc55b70 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a person. + /// + public class Person : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The name of the person. + public Person(string name) + { + ArgumentException.ThrowIfNullOrEmpty(name); + + Name = name; + DateAdded = DateTime.UtcNow; + DateModified = DateAdded; + + Sources = new HashSet(); + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the name. + /// + /// + /// Required, Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string Name { get; set; } + + /// + /// Gets or sets the source id. + /// + /// + /// Max length = 255. + /// + [MaxLength(256)] + [StringLength(256)] + public string? SourceId { get; set; } + + /// + /// Gets the date added. + /// + /// + /// Required. + /// + public DateTime DateAdded { get; private set; } + + /// + /// Gets or sets the date modified. + /// + /// + /// Required. + /// + public DateTime DateModified { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets a list of metadata sources for this person. + /// + public virtual ICollection Sources { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs new file mode 100644 index 000000000..7d40bdf44 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a person's role in media. + /// + public class PersonRole : IHasArtwork, IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The role type. + /// The person. + public PersonRole(PersonRoleType type, Person person) + { + Type = type; + Person = person; + Artwork = new HashSet(); + Sources = new HashSet(); + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the name of the person's role. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? Role { get; set; } + + /// + /// Gets or sets the person's role type. + /// + /// + /// Required. + /// + public PersonRoleType Type { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets or sets the person. + /// + /// + /// Required. + /// + public virtual Person Person { get; set; } + + /// + public virtual ICollection Artwork { get; private set; } + + /// + /// Gets a collection containing the metadata sources for this person role. + /// + public virtual ICollection Sources { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs new file mode 100644 index 000000000..4b459432b --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a photo. + /// + public class Photo : LibraryItem, IHasReleases + { + /// + /// Initializes a new instance of the class. + /// + /// The library. + public Photo(Library library) : base(library) + { + PhotoMetadata = new HashSet(); + Releases = new HashSet(); + } + + /// + /// Gets a collection containing the photo metadata. + /// + public virtual ICollection PhotoMetadata { get; private set; } + + /// + public virtual ICollection Releases { get; private set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PhotoMetadata.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PhotoMetadata.cs new file mode 100644 index 000000000..6c284307d --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PhotoMetadata.cs @@ -0,0 +1,17 @@ +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity that holds metadata for a photo. + /// + public class PhotoMetadata : ItemMetadata + { + /// + /// Initializes a new instance of the class. + /// + /// The title or name of the photo. + /// ISO-639-3 3-character language codes. + public PhotoMetadata(string title, string language) : base(title, language) + { + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs new file mode 100644 index 000000000..58c8fa49e --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs @@ -0,0 +1,59 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a rating for an entity. + /// + public class Rating : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The value. + public Rating(double value) + { + Value = value; + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the value. + /// + /// + /// Required. + /// + public double Value { get; set; } + + /// + /// Gets or sets the number of votes. + /// + public int? Votes { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets or sets the rating type. + /// If this is null it's the internal user rating. + /// + public virtual RatingSource? RatingType { get; set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs new file mode 100644 index 000000000..0f3a07324 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs @@ -0,0 +1,73 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// This is the entity to store review ratings, not age ratings. + /// + public class RatingSource : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The minimum value. + /// The maximum value. + public RatingSource(double minimumValue, double maximumValue) + { + MinimumValue = minimumValue; + MaximumValue = maximumValue; + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the name. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? Name { get; set; } + + /// + /// Gets or sets the minimum value. + /// + /// + /// Required. + /// + public double MinimumValue { get; set; } + + /// + /// Gets or sets the maximum value. + /// + /// + /// Required. + /// + public double MaximumValue { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets or sets the metadata source. + /// + public virtual MetadataProviderId? Source { get; set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs new file mode 100644 index 000000000..e68ab9105 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a release for a library item, eg. Director's cut vs. standard. + /// + public class Release : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// + /// The name of this release. + public Release(string name) + { + ArgumentException.ThrowIfNullOrEmpty(name); + + Name = name; + + MediaFiles = new HashSet(); + Chapters = new HashSet(); + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the name. + /// + /// + /// Required, Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string Name { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets a collection containing the media files for this release. + /// + public virtual ICollection MediaFiles { get; private set; } + + /// + /// Gets a collection containing the chapters for this release. + /// + public virtual ICollection Chapters { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Season.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Season.cs new file mode 100644 index 000000000..fc110b49d --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Season.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a season. + /// + public class Season : LibraryItem + { + /// + /// Initializes a new instance of the class. + /// + /// The library. + public Season(Library library) : base(library) + { + Episodes = new HashSet(); + SeasonMetadata = new HashSet(); + } + + /// + /// Gets or sets the season number. + /// + public int? SeasonNumber { get; set; } + + /// + /// Gets the season metadata. + /// + public virtual ICollection SeasonMetadata { get; private set; } + + /// + /// Gets a collection containing the number of episodes. + /// + public virtual ICollection Episodes { get; private set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeasonMetadata.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeasonMetadata.cs new file mode 100644 index 000000000..da40a075f --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeasonMetadata.cs @@ -0,0 +1,29 @@ +using System.ComponentModel.DataAnnotations; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity that holds metadata for seasons. + /// + public class SeasonMetadata : ItemMetadata + { + /// + /// Initializes a new instance of the class. + /// + /// The title or name of the object. + /// ISO-639-3 3-character language codes. + public SeasonMetadata(string title, string language) : base(title, language) + { + } + + /// + /// Gets or sets the outline. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? Outline { get; set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Series.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Series.cs new file mode 100644 index 000000000..0354433e0 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Series.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a a series. + /// + public class Series : LibraryItem + { + /// + /// Initializes a new instance of the class. + /// + /// The library. + public Series(Library library) : base(library) + { + Seasons = new HashSet(); + SeriesMetadata = new HashSet(); + } + + /// + /// Gets or sets the days of week. + /// + public DayOfWeek? AirsDayOfWeek { get; set; } + + /// + /// Gets or sets the time the show airs, ignore the date portion. + /// + public DateTimeOffset? AirsTime { get; set; } + + /// + /// Gets or sets the date the series first aired. + /// + public DateTime? FirstAired { get; set; } + + /// + /// Gets a collection containing the series metadata. + /// + public virtual ICollection SeriesMetadata { get; private set; } + + /// + /// Gets a collection containing the seasons. + /// + public virtual ICollection Seasons { get; private set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs new file mode 100644 index 000000000..42115802c --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing series metadata. + /// + public class SeriesMetadata : ItemMetadata, IHasCompanies + { + /// + /// Initializes a new instance of the class. + /// + /// The title or name of the object. + /// ISO-639-3 3-character language codes. + public SeriesMetadata(string title, string language) : base(title, language) + { + Networks = new HashSet(); + } + + /// + /// Gets or sets the outline. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? Outline { get; set; } + + /// + /// Gets or sets the plot. + /// + /// + /// Max length = 65535. + /// + [MaxLength(65535)] + [StringLength(65535)] + public string? Plot { get; set; } + + /// + /// Gets or sets the tagline. + /// + /// + /// Max length = 1024. + /// + [MaxLength(1024)] + [StringLength(1024)] + public string? Tagline { get; set; } + + /// + /// Gets or sets the country code. + /// + /// + /// Max length = 2. + /// + [MaxLength(2)] + [StringLength(2)] + public string? Country { get; set; } + + /// + /// Gets a collection containing the networks. + /// + public virtual ICollection Networks { get; private set; } + + /// + public ICollection Companies => Networks; + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs new file mode 100644 index 000000000..d35400033 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity representing a track. + /// + public class Track : LibraryItem, IHasReleases + { + /// + /// Initializes a new instance of the class. + /// + /// The library. + public Track(Library library) : base(library) + { + Releases = new HashSet(); + TrackMetadata = new HashSet(); + } + + /// + /// Gets or sets the track number. + /// + public int? TrackNumber { get; set; } + + /// + public virtual ICollection Releases { get; private set; } + + /// + /// Gets a collection containing the track metadata. + /// + public virtual ICollection TrackMetadata { get; private set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/TrackMetadata.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/TrackMetadata.cs new file mode 100644 index 000000000..042d2b90d --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/TrackMetadata.cs @@ -0,0 +1,17 @@ +namespace Jellyfin.Data.Entities.Libraries +{ + /// + /// An entity holding metadata for a track. + /// + public class TrackMetadata : ItemMetadata + { + /// + /// Initializes a new instance of the class. + /// + /// The title or name of the object. + /// ISO-639-3 3-character language codes. + public TrackMetadata(string title, string language) : base(title, language) + { + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs new file mode 100644 index 000000000..90120d772 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs @@ -0,0 +1,42 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data.Entities; + +/// +/// An entity representing the metadata for a group of trickplay tiles. +/// +public class MediaSegment +{ + /// + /// Gets or sets the id of the media segment. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + /// + /// Gets or sets the id of the associated item. + /// + public Guid ItemId { get; set; } + + /// + /// Gets or sets the Type of content this segment defines. + /// + public MediaSegmentType Type { get; set; } + + /// + /// Gets or sets the end of the segment. + /// + public long EndTicks { get; set; } + + /// + /// Gets or sets the start of the segment. + /// + public long StartTicks { get; set; } + + /// + /// Gets or sets Id of the media segment provider this entry originates from. + /// + public required string SegmentProviderId { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs new file mode 100644 index 000000000..77816565a --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs @@ -0,0 +1,103 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Jellyfin.Data.Entities; + +public class MediaStreamInfo +{ + public required Guid ItemId { get; set; } + + public required BaseItemEntity Item { get; set; } + + public int StreamIndex { get; set; } + + public required MediaStreamTypeEntity StreamType { get; set; } + + public string? Codec { get; set; } + + public string? Language { get; set; } + + public string? ChannelLayout { get; set; } + + public string? Profile { get; set; } + + public string? AspectRatio { get; set; } + + public string? Path { get; set; } + + public bool? IsInterlaced { get; set; } + + public int? BitRate { get; set; } + + public int? Channels { get; set; } + + public int? SampleRate { get; set; } + + public bool IsDefault { get; set; } + + public bool IsForced { get; set; } + + public bool IsExternal { get; set; } + + public int? Height { get; set; } + + public int? Width { get; set; } + + public float? AverageFrameRate { get; set; } + + public float? RealFrameRate { get; set; } + + public float? Level { get; set; } + + public string? PixelFormat { get; set; } + + public int? BitDepth { get; set; } + + public bool? IsAnamorphic { get; set; } + + public int? RefFrames { get; set; } + + public string? CodecTag { get; set; } + + public string? Comment { get; set; } + + public string? NalLengthSize { get; set; } + + public bool? IsAvc { get; set; } + + public string? Title { get; set; } + + public string? TimeBase { get; set; } + + public string? CodecTimeBase { get; set; } + + public string? ColorPrimaries { get; set; } + + public string? ColorSpace { get; set; } + + public string? ColorTransfer { get; set; } + + public int? DvVersionMajor { get; set; } + + public int? DvVersionMinor { get; set; } + + public int? DvProfile { get; set; } + + public int? DvLevel { get; set; } + + public int? RpuPresentFlag { get; set; } + + public int? ElPresentFlag { get; set; } + + public int? BlPresentFlag { get; set; } + + public int? DvBlSignalCompatibilityId { get; set; } + + public bool? IsHearingImpaired { get; set; } + + public int? Rotation { get; set; } + + public string? KeyFrames { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamTypeEntity.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamTypeEntity.cs new file mode 100644 index 000000000..f57672a2c --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamTypeEntity.cs @@ -0,0 +1,37 @@ +namespace Jellyfin.Data.Entities; + +/// +/// Enum MediaStreamType. +/// +public enum MediaStreamTypeEntity +{ + /// + /// The audio. + /// + Audio = 0, + + /// + /// The video. + /// + Video = 1, + + /// + /// The subtitle. + /// + Subtitle = 2, + + /// + /// The embedded image. + /// + EmbeddedImage = 3, + + /// + /// The data. + /// + Data = 4, + + /// + /// The lyric. + /// + Lyric = 5 +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/People.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/People.cs new file mode 100644 index 000000000..18c778b17 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/People.cs @@ -0,0 +1,32 @@ +#pragma warning disable CA2227 // Collection properties should be read only + +using System; +using System.Collections.Generic; + +namespace Jellyfin.Data.Entities; + +/// +/// People entity. +/// +public class People +{ + /// + /// Gets or Sets the PeopleId. + /// + public required Guid Id { get; set; } + + /// + /// Gets or Sets the Persons Name. + /// + public required string Name { get; set; } + + /// + /// Gets or Sets the Type. + /// + public string? PersonType { get; set; } + + /// + /// Gets or Sets the mapping of People to BaseItems. + /// + public ICollection? BaseItems { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/PeopleBaseItemMap.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/PeopleBaseItemMap.cs new file mode 100644 index 000000000..5ce7300b5 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/PeopleBaseItemMap.cs @@ -0,0 +1,44 @@ +using System; + +namespace Jellyfin.Data.Entities; + +/// +/// Mapping table for People to BaseItems. +/// +public class PeopleBaseItemMap +{ + /// + /// Gets or Sets the SortOrder. + /// + public int? SortOrder { get; set; } + + /// + /// Gets or Sets the ListOrder. + /// + public int? ListOrder { get; set; } + + /// + /// Gets or Sets the Role name the assosiated actor played in the . + /// + public string? Role { get; set; } + + /// + /// Gets or Sets The ItemId. + /// + public required Guid ItemId { get; set; } + + /// + /// Gets or Sets Reference Item. + /// + public required BaseItemEntity Item { get; set; } + + /// + /// Gets or Sets The PeopleId. + /// + public required Guid PeopleId { get; set; } + + /// + /// Gets or Sets Reference People. + /// + public required People People { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs new file mode 100644 index 000000000..6d2e68077 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs @@ -0,0 +1,68 @@ +#pragma warning disable CA1711 // Identifiers should not have incorrect suffix + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities +{ + /// + /// An entity representing whether the associated user has a specific permission. + /// + public class Permission : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// Public constructor with required data. + /// + /// The permission kind. + /// The value of this permission. + public Permission(PermissionKind kind, bool value) + { + Kind = kind; + Value = value; + } + + /// + /// Gets the id of this permission. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the id of the associated user. + /// + public Guid? UserId { get; set; } + + /// + /// Gets the type of this permission. + /// + /// + /// Required. + /// + public PermissionKind Kind { get; private set; } + + /// + /// Gets or sets a value indicating whether the associated user has this permission. + /// + /// + /// Required. + /// + public bool Value { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs new file mode 100644 index 000000000..a6ab275d3 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs @@ -0,0 +1,68 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities +{ + /// + /// An entity representing a preference attached to a user or group. + /// + public class Preference : IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// Public constructor with required data. + /// + /// The preference kind. + /// The value. + public Preference(PreferenceKind kind, string value) + { + Kind = kind; + Value = value ?? throw new ArgumentNullException(nameof(value)); + } + + /// + /// Gets the id of this preference. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the id of the associated user. + /// + public Guid? UserId { get; set; } + + /// + /// Gets the type of this preference. + /// + /// + /// Required. + /// + public PreferenceKind Kind { get; private set; } + + /// + /// Gets or sets the value of this preference. + /// + /// + /// Required, Max length = 65535. + /// + [MaxLength(65535)] + [StringLength(65535)] + public string Value { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ProgramAudioEntity.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ProgramAudioEntity.cs new file mode 100644 index 000000000..5b225a002 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ProgramAudioEntity.cs @@ -0,0 +1,37 @@ +namespace Jellyfin.Data.Entities; + +/// +/// Lists types of Audio. +/// +public enum ProgramAudioEntity +{ + /// + /// Mono. + /// + Mono = 0, + + /// + /// Sterio. + /// + Stereo = 1, + + /// + /// Dolby. + /// + Dolby = 2, + + /// + /// DolbyDigital. + /// + DolbyDigital = 3, + + /// + /// Thx. + /// + Thx = 4, + + /// + /// Atmos. + /// + Atmos = 5 +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/ApiKey.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/ApiKey.cs new file mode 100644 index 000000000..1fcbe0f5e --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/ApiKey.cs @@ -0,0 +1,56 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Globalization; + +namespace Jellyfin.Data.Entities.Security +{ + /// + /// An entity representing an API key. + /// + public class ApiKey + { + /// + /// Initializes a new instance of the class. + /// + /// The name. + public ApiKey(string name) + { + Name = name; + + AccessToken = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); + DateCreated = DateTime.UtcNow; + } + + /// + /// Gets the id. + /// + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets or sets the date created. + /// + public DateTime DateCreated { get; set; } + + /// + /// Gets or sets the date of last activity. + /// + public DateTime DateLastActivity { get; set; } + + /// + /// Gets or sets the name. + /// + [MaxLength(64)] + [StringLength(64)] + public string Name { get; set; } + + /// + /// Gets or sets the access token. + /// + public string AccessToken { get; set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/Device.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/Device.cs new file mode 100644 index 000000000..67d7f78ed --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/Device.cs @@ -0,0 +1,107 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Globalization; + +namespace Jellyfin.Data.Entities.Security +{ + /// + /// An entity representing a device. + /// + public class Device + { + /// + /// Initializes a new instance of the class. + /// + /// The user id. + /// The app name. + /// The app version. + /// The device name. + /// The device id. + public Device(Guid userId, string appName, string appVersion, string deviceName, string deviceId) + { + UserId = userId; + AppName = appName; + AppVersion = appVersion; + DeviceName = deviceName; + DeviceId = deviceId; + + AccessToken = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); + DateCreated = DateTime.UtcNow; + DateModified = DateCreated; + DateLastActivity = DateCreated; + + // Non-nullable for EF Core, as this is a required relationship. + User = null!; + } + + /// + /// Gets the id. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets the user id. + /// + public Guid UserId { get; private set; } + + /// + /// Gets or sets the access token. + /// + public string AccessToken { get; set; } + + /// + /// Gets or sets the app name. + /// + [MaxLength(64)] + [StringLength(64)] + public string AppName { get; set; } + + /// + /// Gets or sets the app version. + /// + [MaxLength(32)] + [StringLength(32)] + public string AppVersion { get; set; } + + /// + /// Gets or sets the device name. + /// + [MaxLength(64)] + [StringLength(64)] + public string DeviceName { get; set; } + + /// + /// Gets or sets the device id. + /// + [MaxLength(256)] + [StringLength(256)] + public string DeviceId { get; set; } + + /// + /// Gets or sets a value indicating whether this device is active. + /// + public bool IsActive { get; set; } + + /// + /// Gets or sets the date created. + /// + public DateTime DateCreated { get; set; } + + /// + /// Gets or sets the date modified. + /// + public DateTime DateModified { get; set; } + + /// + /// Gets or sets the date of last activity. + /// + public DateTime DateLastActivity { get; set; } + + /// + /// Gets the user. + /// + public User User { get; private set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/DeviceOptions.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/DeviceOptions.cs new file mode 100644 index 000000000..531f66c62 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/DeviceOptions.cs @@ -0,0 +1,35 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace Jellyfin.Data.Entities.Security +{ + /// + /// An entity representing custom options for a device. + /// + public class DeviceOptions + { + /// + /// Initializes a new instance of the class. + /// + /// The device id. + public DeviceOptions(string deviceId) + { + DeviceId = deviceId; + } + + /// + /// Gets the id. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; private set; } + + /// + /// Gets the device id. + /// + public string DeviceId { get; private set; } + + /// + /// Gets or sets the custom name. + /// + public string? CustomName { get; set; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/TrickplayInfo.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/TrickplayInfo.cs new file mode 100644 index 000000000..64e7da1b5 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/TrickplayInfo.cs @@ -0,0 +1,75 @@ +using System; +using System.Text.Json.Serialization; + +namespace Jellyfin.Data.Entities; + +/// +/// An entity representing the metadata for a group of trickplay tiles. +/// +public class TrickplayInfo +{ + /// + /// Gets or sets the id of the associated item. + /// + /// + /// Required. + /// + [JsonIgnore] + public Guid ItemId { get; set; } + + /// + /// Gets or sets width of an individual thumbnail. + /// + /// + /// Required. + /// + public int Width { get; set; } + + /// + /// Gets or sets height of an individual thumbnail. + /// + /// + /// Required. + /// + public int Height { get; set; } + + /// + /// Gets or sets amount of thumbnails per row. + /// + /// + /// Required. + /// + public int TileWidth { get; set; } + + /// + /// Gets or sets amount of thumbnails per column. + /// + /// + /// Required. + /// + public int TileHeight { get; set; } + + /// + /// Gets or sets total amount of non-black thumbnails. + /// + /// + /// Required. + /// + public int ThumbnailCount { get; set; } + + /// + /// Gets or sets interval in milliseconds between each trickplay thumbnail. + /// + /// + /// Required. + /// + public int Interval { get; set; } + + /// + /// Gets or sets peak bandwith usage in bits per second. + /// + /// + /// Required. + /// + public int Bandwidth { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs new file mode 100644 index 000000000..f3398eeea --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs @@ -0,0 +1,338 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text.Json.Serialization; +using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; + +namespace Jellyfin.Data.Entities +{ + /// + /// An entity representing a user. + /// + public class User : IHasPermissions, IHasConcurrencyToken + { + /// + /// Initializes a new instance of the class. + /// Public constructor with required data. + /// + /// The username for the new user. + /// The Id of the user's authentication provider. + /// The Id of the user's password reset provider. + public User(string username, string authenticationProviderId, string passwordResetProviderId) + { + ArgumentException.ThrowIfNullOrEmpty(username); + ArgumentException.ThrowIfNullOrEmpty(authenticationProviderId); + ArgumentException.ThrowIfNullOrEmpty(passwordResetProviderId); + + Username = username; + AuthenticationProviderId = authenticationProviderId; + PasswordResetProviderId = passwordResetProviderId; + + AccessSchedules = new HashSet(); + DisplayPreferences = new HashSet(); + ItemDisplayPreferences = new HashSet(); + // Groups = new HashSet(); + Permissions = new HashSet(); + Preferences = new HashSet(); + // ProviderMappings = new HashSet(); + + // Set default values + Id = Guid.NewGuid(); + InvalidLoginAttemptCount = 0; + EnableUserPreferenceAccess = true; + MustUpdatePassword = false; + DisplayMissingEpisodes = false; + DisplayCollectionsView = false; + HidePlayedInLatest = true; + RememberAudioSelections = true; + RememberSubtitleSelections = true; + EnableNextEpisodeAutoPlay = true; + EnableAutoLogin = false; + PlayDefaultAudioTrack = true; + SubtitleMode = SubtitlePlaybackMode.Default; + SyncPlayAccess = SyncPlayUserAccessType.CreateAndJoinGroups; + } + + /// + /// Gets or sets the Id of the user. + /// + /// + /// Identity, Indexed, Required. + /// + [JsonIgnore] + public Guid Id { get; set; } + + /// + /// Gets or sets the user's name. + /// + /// + /// Required, Max length = 255. + /// + [MaxLength(255)] + [StringLength(255)] + public string Username { get; set; } + + /// + /// Gets or sets the user's password, or null if none is set. + /// + /// + /// Max length = 65535. + /// + [MaxLength(65535)] + [StringLength(65535)] + public string? Password { get; set; } + + /// + /// Gets or sets a value indicating whether the user must update their password. + /// + /// + /// Required. + /// + public bool MustUpdatePassword { get; set; } + + /// + /// Gets or sets the audio language preference. + /// + /// + /// Max length = 255. + /// + [MaxLength(255)] + [StringLength(255)] + public string? AudioLanguagePreference { get; set; } + + /// + /// Gets or sets the authentication provider id. + /// + /// + /// Required, Max length = 255. + /// + [MaxLength(255)] + [StringLength(255)] + public string AuthenticationProviderId { get; set; } + + /// + /// Gets or sets the password reset provider id. + /// + /// + /// Required, Max length = 255. + /// + [MaxLength(255)] + [StringLength(255)] + public string PasswordResetProviderId { get; set; } + + /// + /// Gets or sets the invalid login attempt count. + /// + /// + /// Required. + /// + public int InvalidLoginAttemptCount { get; set; } + + /// + /// Gets or sets the last activity date. + /// + public DateTime? LastActivityDate { get; set; } + + /// + /// Gets or sets the last login date. + /// + public DateTime? LastLoginDate { get; set; } + + /// + /// Gets or sets the number of login attempts the user can make before they are locked out. + /// + public int? LoginAttemptsBeforeLockout { get; set; } + + /// + /// Gets or sets the maximum number of active sessions the user can have at once. + /// + public int MaxActiveSessions { get; set; } + + /// + /// Gets or sets the subtitle mode. + /// + /// + /// Required. + /// + public SubtitlePlaybackMode SubtitleMode { get; set; } + + /// + /// Gets or sets a value indicating whether the default audio track should be played. + /// + /// + /// Required. + /// + public bool PlayDefaultAudioTrack { get; set; } + + /// + /// Gets or sets the subtitle language preference. + /// + /// + /// Max length = 255. + /// + [MaxLength(255)] + [StringLength(255)] + public string? SubtitleLanguagePreference { get; set; } + + /// + /// Gets or sets a value indicating whether missing episodes should be displayed. + /// + /// + /// Required. + /// + public bool DisplayMissingEpisodes { get; set; } + + /// + /// Gets or sets a value indicating whether to display the collections view. + /// + /// + /// Required. + /// + public bool DisplayCollectionsView { get; set; } + + /// + /// Gets or sets a value indicating whether the user has a local password. + /// + /// + /// Required. + /// + public bool EnableLocalPassword { get; set; } + + /// + /// Gets or sets a value indicating whether the server should hide played content in "Latest". + /// + /// + /// Required. + /// + public bool HidePlayedInLatest { get; set; } + + /// + /// Gets or sets a value indicating whether to remember audio selections on played content. + /// + /// + /// Required. + /// + public bool RememberAudioSelections { get; set; } + + /// + /// Gets or sets a value indicating whether to remember subtitle selections on played content. + /// + /// + /// Required. + /// + public bool RememberSubtitleSelections { get; set; } + + /// + /// Gets or sets a value indicating whether to enable auto-play for the next episode. + /// + /// + /// Required. + /// + public bool EnableNextEpisodeAutoPlay { get; set; } + + /// + /// Gets or sets a value indicating whether the user should auto-login. + /// + /// + /// Required. + /// + public bool EnableAutoLogin { get; set; } + + /// + /// Gets or sets a value indicating whether the user can change their preferences. + /// + /// + /// Required. + /// + public bool EnableUserPreferenceAccess { get; set; } + + /// + /// Gets or sets the maximum parental age rating. + /// + public int? MaxParentalAgeRating { get; set; } + + /// + /// Gets or sets the remote client bitrate limit. + /// + public int? RemoteClientBitrateLimit { get; set; } + + /// + /// Gets or sets the internal id. + /// This is a temporary stopgap for until the library db is migrated. + /// This corresponds to the value of the index of this user in the library db. + /// + public long InternalId { get; set; } + + /// + /// Gets or sets the user's profile image. Can be null. + /// + // [ForeignKey("UserId")] + public virtual ImageInfo? ProfileImage { get; set; } + + /// + /// Gets the user's display preferences. + /// + public virtual ICollection DisplayPreferences { get; private set; } + + /// + /// Gets or sets the level of sync play permissions this user has. + /// + public SyncPlayUserAccessType SyncPlayAccess { get; set; } + + /// + /// Gets or sets the cast receiver id. + /// + [StringLength(32)] + public string? CastReceiverId { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + /// Gets the list of access schedules this user has. + /// + public virtual ICollection AccessSchedules { get; private set; } + + /// + /// Gets the list of item display preferences. + /// + public virtual ICollection ItemDisplayPreferences { get; private set; } + + /* + /// + /// Gets the list of groups this user is a member of. + /// + public virtual ICollection Groups { get; private set; } + */ + + /// + /// Gets the list of permissions this user has. + /// + [ForeignKey("Permission_Permissions_Guid")] + public virtual ICollection Permissions { get; private set; } + + /* + /// + /// Gets the list of provider mappings this user has. + /// + public virtual ICollection ProviderMappings { get; private set; } + */ + + /// + /// Gets the list of preferences this user has. + /// + [ForeignKey("Preference_Preferences_Guid")] + public virtual ICollection Preferences { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs new file mode 100644 index 000000000..05ab6dd2d --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs @@ -0,0 +1,92 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Jellyfin.Data.Entities; + +/// +/// Provides and related data. +/// +public class UserData +{ + /// + /// Gets or sets the custom data key. + /// + /// The rating. + public required string CustomDataKey { get; set; } + + /// + /// Gets or sets the users 0-10 rating. + /// + /// The rating. + public double? Rating { get; set; } + + /// + /// Gets or sets the playback position ticks. + /// + /// The playback position ticks. + public long PlaybackPositionTicks { get; set; } + + /// + /// Gets or sets the play count. + /// + /// The play count. + public int PlayCount { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is favorite. + /// + /// true if this instance is favorite; otherwise, false. + public bool IsFavorite { get; set; } + + /// + /// Gets or sets the last played date. + /// + /// The last played date. + public DateTime? LastPlayedDate { get; set; } + + /// + /// Gets or sets a value indicating whether this is played. + /// + /// true if played; otherwise, false. + public bool Played { get; set; } + + /// + /// Gets or sets the index of the audio stream. + /// + /// The index of the audio stream. + public int? AudioStreamIndex { get; set; } + + /// + /// Gets or sets the index of the subtitle stream. + /// + /// The index of the subtitle stream. + public int? SubtitleStreamIndex { get; set; } + + /// + /// Gets or sets a value indicating whether the item is liked or not. + /// This should never be serialized. + /// + /// null if [likes] contains no value, true if [likes]; otherwise, false. + public bool? Likes { get; set; } + + /// + /// Gets or sets the key. + /// + /// The key. + public required Guid ItemId { get; set; } + + /// + /// Gets or Sets the BaseItem. + /// + public required BaseItemEntity? Item { get; set; } + + /// + /// Gets or Sets the UserId. + /// + public required Guid UserId { get; set; } + + /// + /// Gets or Sets the User. + /// + public required User? User { get; set; } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ArtKind.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ArtKind.cs new file mode 100644 index 000000000..f7a73848c --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ArtKind.cs @@ -0,0 +1,33 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing types of art. + /// + public enum ArtKind + { + /// + /// Another type of art, not covered by the other members. + /// + Other = 0, + + /// + /// A poster. + /// + Poster = 1, + + /// + /// A banner. + /// + Banner = 2, + + /// + /// A thumbnail. + /// + Thumbnail = 3, + + /// + /// A logo. + /// + Logo = 4 + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ChromecastVersion.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ChromecastVersion.cs new file mode 100644 index 000000000..c9c8a4a62 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ChromecastVersion.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing the version of Chromecast to be used by clients. + /// + public enum ChromecastVersion + { + /// + /// Stable Chromecast version. + /// + Stable = 0, + + /// + /// Unstable Chromecast version. + /// + Unstable = 1 + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/DynamicDayOfWeek.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/DynamicDayOfWeek.cs new file mode 100644 index 000000000..d3d8dd822 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/DynamicDayOfWeek.cs @@ -0,0 +1,58 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum that represents a day of the week, weekdays, weekends, or all days. + /// + public enum DynamicDayOfWeek + { + /// + /// Sunday. + /// + Sunday = 0, + + /// + /// Monday. + /// + Monday = 1, + + /// + /// Tuesday. + /// + Tuesday = 2, + + /// + /// Wednesday. + /// + Wednesday = 3, + + /// + /// Thursday. + /// + Thursday = 4, + + /// + /// Friday. + /// + Friday = 5, + + /// + /// Saturday. + /// + Saturday = 6, + + /// + /// All days of the week. + /// + Everyday = 7, + + /// + /// A week day, or Monday-Friday. + /// + Weekday = 8, + + /// + /// Saturday and Sunday. + /// + Weekend = 9 + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/HomeSectionType.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/HomeSectionType.cs new file mode 100644 index 000000000..62da8c3ff --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/HomeSectionType.cs @@ -0,0 +1,58 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing the different options for the home screen sections. + /// + public enum HomeSectionType + { + /// + /// None. + /// + None = 0, + + /// + /// My Media. + /// + SmallLibraryTiles = 1, + + /// + /// My Media Small. + /// + LibraryButtons = 2, + + /// + /// Active Recordings. + /// + ActiveRecordings = 3, + + /// + /// Continue Watching. + /// + Resume = 4, + + /// + /// Continue Listening. + /// + ResumeAudio = 5, + + /// + /// Latest Media. + /// + LatestMedia = 6, + + /// + /// Next Up. + /// + NextUp = 7, + + /// + /// Live TV. + /// + LiveTv = 8, + + /// + /// Continue Reading. + /// + ResumeBook = 9 + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/IndexingKind.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/IndexingKind.cs new file mode 100644 index 000000000..3967712b0 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/IndexingKind.cs @@ -0,0 +1,23 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing a type of indexing in a user's display preferences. + /// + public enum IndexingKind + { + /// + /// Index by the premiere date. + /// + PremiereDate = 0, + + /// + /// Index by the production year. + /// + ProductionYear = 1, + + /// + /// Index by the community rating. + /// + CommunityRating = 2 + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaFileKind.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaFileKind.cs new file mode 100644 index 000000000..797c26ec2 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaFileKind.cs @@ -0,0 +1,33 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing the type of media file. + /// + public enum MediaFileKind + { + /// + /// The main file. + /// + Main = 0, + + /// + /// A sidecar file. + /// + Sidecar = 1, + + /// + /// An additional part to the main file. + /// + AdditionalPart = 2, + + /// + /// An alternative format to the main file. + /// + AlternativeFormat = 3, + + /// + /// An additional stream for the main file. + /// + AdditionalStream = 4 + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs new file mode 100644 index 000000000..458635450 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs @@ -0,0 +1,39 @@ +using Jellyfin.Data.Entities; + +namespace Jellyfin.Data.Enums; + +/// +/// Defines the types of content an individual represents. +/// +public enum MediaSegmentType +{ + /// + /// Default media type or custom one. + /// + Unknown = 0, + + /// + /// Commercial. + /// + Commercial = 1, + + /// + /// Preview. + /// + Preview = 2, + + /// + /// Recap. + /// + Recap = 3, + + /// + /// Outro. + /// + Outro = 4, + + /// + /// Intro. + /// + Intro = 5 +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PermissionKind.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PermissionKind.cs new file mode 100644 index 000000000..c3d6705c2 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PermissionKind.cs @@ -0,0 +1,128 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// The types of user permissions. + /// + public enum PermissionKind + { + /// + /// Whether the user is an administrator. + /// + IsAdministrator = 0, + + /// + /// Whether the user is hidden. + /// + IsHidden = 1, + + /// + /// Whether the user is disabled. + /// + IsDisabled = 2, + + /// + /// Whether the user can control shared devices. + /// + EnableSharedDeviceControl = 3, + + /// + /// Whether the user can access the server remotely. + /// + EnableRemoteAccess = 4, + + /// + /// Whether the user can manage live tv. + /// + EnableLiveTvManagement = 5, + + /// + /// Whether the user can access live tv. + /// + EnableLiveTvAccess = 6, + + /// + /// Whether the user can play media. + /// + EnableMediaPlayback = 7, + + /// + /// Whether the server should transcode audio for the user if requested. + /// + EnableAudioPlaybackTranscoding = 8, + + /// + /// Whether the server should transcode video for the user if requested. + /// + EnableVideoPlaybackTranscoding = 9, + + /// + /// Whether the user can delete content. + /// + EnableContentDeletion = 10, + + /// + /// Whether the user can download content. + /// + EnableContentDownloading = 11, + + /// + /// Whether to enable sync transcoding for the user. + /// + EnableSyncTranscoding = 12, + + /// + /// Whether the user can do media conversion. + /// + EnableMediaConversion = 13, + + /// + /// Whether the user has access to all devices. + /// + EnableAllDevices = 14, + + /// + /// Whether the user has access to all channels. + /// + EnableAllChannels = 15, + + /// + /// Whether the user has access to all folders. + /// + EnableAllFolders = 16, + + /// + /// Whether to enable public sharing for the user. + /// + EnablePublicSharing = 17, + + /// + /// Whether the user can remotely control other users. + /// + EnableRemoteControlOfOtherUsers = 18, + + /// + /// Whether the user is permitted to do playback remuxing. + /// + EnablePlaybackRemuxing = 19, + + /// + /// Whether the server should force transcoding on remote connections for the user. + /// + ForceRemoteSourceTranscoding = 20, + + /// + /// Whether the user can create, modify and delete collections. + /// + EnableCollectionManagement = 21, + + /// + /// Whether the user can edit subtitles. + /// + EnableSubtitleManagement = 22, + + /// + /// Whether the user can edit lyrics. + /// + EnableLyricManagement = 23, + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PersonRoleType.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PersonRoleType.cs new file mode 100644 index 000000000..1e619f5ee --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PersonRoleType.cs @@ -0,0 +1,68 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing a person's role in a specific media item. + /// + public enum PersonRoleType + { + /// + /// Another role, not covered by the other types. + /// + Other = 0, + + /// + /// The director of the media. + /// + Director = 1, + + /// + /// An artist. + /// + Artist = 2, + + /// + /// The original artist. + /// + OriginalArtist = 3, + + /// + /// An actor. + /// + Actor = 4, + + /// + /// A voice actor. + /// + VoiceActor = 5, + + /// + /// A producer. + /// + Producer = 6, + + /// + /// A remixer. + /// + Remixer = 7, + + /// + /// A conductor. + /// + Conductor = 8, + + /// + /// A composer. + /// + Composer = 9, + + /// + /// An author. + /// + Author = 10, + + /// + /// An editor. + /// + Editor = 11 + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PreferenceKind.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PreferenceKind.cs new file mode 100644 index 000000000..d2b412e45 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PreferenceKind.cs @@ -0,0 +1,73 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// The types of user preferences. + /// + public enum PreferenceKind + { + /// + /// A list of blocked tags. + /// + BlockedTags = 0, + + /// + /// A list of blocked channels. + /// + BlockedChannels = 1, + + /// + /// A list of blocked media folders. + /// + BlockedMediaFolders = 2, + + /// + /// A list of enabled devices. + /// + EnabledDevices = 3, + + /// + /// A list of enabled channels. + /// + EnabledChannels = 4, + + /// + /// A list of enabled folders. + /// + EnabledFolders = 5, + + /// + /// A list of folders to allow content deletion from. + /// + EnableContentDeletionFromFolders = 6, + + /// + /// A list of latest items to exclude. + /// + LatestItemExcludes = 7, + + /// + /// A list of media to exclude. + /// + MyMediaExcludes = 8, + + /// + /// A list of grouped folders. + /// + GroupedFolders = 9, + + /// + /// A list of unrated items to block. + /// + BlockUnratedItems = 10, + + /// + /// A list of ordered views. + /// + OrderedViews = 11, + + /// + /// A list of allowed tags. + /// + AllowedTags = 12 + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ScrollDirection.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ScrollDirection.cs new file mode 100644 index 000000000..29c50e2c4 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ScrollDirection.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing the axis that should be scrolled. + /// + public enum ScrollDirection + { + /// + /// Horizontal scrolling direction. + /// + Horizontal = 0, + + /// + /// Vertical scrolling direction. + /// + Vertical = 1 + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SortOrder.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SortOrder.cs new file mode 100644 index 000000000..4151448e4 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SortOrder.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing the sorting order. + /// + public enum SortOrder + { + /// + /// Sort in increasing order. + /// + Ascending = 0, + + /// + /// Sort in decreasing order. + /// + Descending = 1 + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SubtitlePlaybackMode.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SubtitlePlaybackMode.cs new file mode 100644 index 000000000..79693d321 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SubtitlePlaybackMode.cs @@ -0,0 +1,33 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing a subtitle playback mode. + /// + public enum SubtitlePlaybackMode + { + /// + /// The default subtitle playback mode. + /// + Default = 0, + + /// + /// Always show subtitles. + /// + Always = 1, + + /// + /// Only show forced subtitles. + /// + OnlyForced = 2, + + /// + /// Don't show subtitles. + /// + None = 3, + + /// + /// Only show subtitles when the current audio stream is in a different language. + /// + Smart = 4 + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SyncPlayUserAccessType.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SyncPlayUserAccessType.cs new file mode 100644 index 000000000..030d16fb9 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SyncPlayUserAccessType.cs @@ -0,0 +1,23 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// Enum SyncPlayUserAccessType. + /// + public enum SyncPlayUserAccessType + { + /// + /// User can create groups and join them. + /// + CreateAndJoinGroups = 0, + + /// + /// User can only join already existing groups. + /// + JoinGroups = 1, + + /// + /// SyncPlay is disabled for the user. + /// + None = 2 + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ViewType.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ViewType.cs new file mode 100644 index 000000000..c0fd7d448 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ViewType.cs @@ -0,0 +1,113 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing the type of view for a library or collection. + /// + public enum ViewType + { + /// + /// Shows albums. + /// + Albums = 0, + + /// + /// Shows album artists. + /// + AlbumArtists = 1, + + /// + /// Shows artists. + /// + Artists = 2, + + /// + /// Shows channels. + /// + Channels = 3, + + /// + /// Shows collections. + /// + Collections = 4, + + /// + /// Shows episodes. + /// + Episodes = 5, + + /// + /// Shows favorites. + /// + Favorites = 6, + + /// + /// Shows genres. + /// + Genres = 7, + + /// + /// Shows guide. + /// + Guide = 8, + + /// + /// Shows movies. + /// + Movies = 9, + + /// + /// Shows networks. + /// + Networks = 10, + + /// + /// Shows playlists. + /// + Playlists = 11, + + /// + /// Shows programs. + /// + Programs = 12, + + /// + /// Shows recordings. + /// + Recordings = 13, + + /// + /// Shows schedule. + /// + Schedule = 14, + + /// + /// Shows series. + /// + Series = 15, + + /// + /// Shows shows. + /// + Shows = 16, + + /// + /// Shows songs. + /// + Songs = 17, + + /// + /// Shows songs. + /// + Suggestions = 18, + + /// + /// Shows trailers. + /// + Trailers = 19, + + /// + /// Shows upcoming. + /// + Upcoming = 20 + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs new file mode 100644 index 000000000..64dd03ca4 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; + +namespace Jellyfin.Server.Implementations; + +/// +/// Defines the type and extension points for multi database support. +/// +public interface IJellyfinDatabaseProvider : IAsyncDisposable +{ + /// + /// Initialises jellyfins EFCore database access. + /// + /// The EFCore database options. + void Initialise(DbContextOptionsBuilder options); + + /// + /// Will be invoked when EFCore wants to build its model. + /// + /// The ModelBuilder from EFCore. + void OnModelCreating(ModelBuilder modelBuilder); + + /// + /// If supported this should run any periodic maintaince tasks. + /// + /// The token to abort the operation. + /// A representing the asynchronous operation. + Task RunScheduledOptimisation(CancellationToken cancellationToken); +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs new file mode 100644 index 000000000..a4d9c54af --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Jellyfin.Data.Entities.Libraries; + +namespace Jellyfin.Data.Interfaces +{ + /// + /// An interface abstracting an entity that has artwork. + /// + public interface IHasArtwork + { + /// + /// Gets a collection containing this entity's artwork. + /// + ICollection Artwork { get; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs new file mode 100644 index 000000000..8f19ce04f --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Jellyfin.Data.Entities.Libraries; + +namespace Jellyfin.Data.Interfaces +{ + /// + /// An abstraction representing an entity that has companies. + /// + public interface IHasCompanies + { + /// + /// Gets a collection containing this entity's companies. + /// + ICollection Companies { get; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasConcurrencyToken.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasConcurrencyToken.cs new file mode 100644 index 000000000..2c4091493 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasConcurrencyToken.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Data.Interfaces +{ + /// + /// An interface abstracting an entity that has a concurrency token. + /// + public interface IHasConcurrencyToken + { + /// + /// Gets the version of this row. Acts as a concurrency token. + /// + uint RowVersion { get; } + + /// + /// Called when saving changes to this entity. + /// + void OnSavingChanges(); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs new file mode 100644 index 000000000..6d1eb59f6 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data.Interfaces +{ + /// + /// An abstraction representing an entity that has permissions. + /// + public interface IHasPermissions + { + /// + /// Gets a collection containing this entity's permissions. + /// + ICollection Permissions { get; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs new file mode 100644 index 000000000..3b615893e --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Jellyfin.Data.Entities.Libraries; + +namespace Jellyfin.Data.Interfaces +{ + /// + /// An abstraction representing an entity that has releases. + /// + public interface IHasReleases + { + /// + /// Gets a collection containing this entity's releases. + /// + ICollection Releases { get; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/Jellyfin.Database.Implementations.csproj b/Jellyfin.Database/Jellyfin.Database.Implementations/Jellyfin.Database.Implementations.csproj new file mode 100644 index 000000000..96cea69df --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/Jellyfin.Database.Implementations.csproj @@ -0,0 +1,43 @@ + + + + net9.0 + enable + enable + false + true + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDatabaseProviderKeyAttribute.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDatabaseProviderKeyAttribute.cs new file mode 100644 index 000000000..b3ab3d094 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDatabaseProviderKeyAttribute.cs @@ -0,0 +1,29 @@ +namespace Jellyfin.Server.Implementations; + +/// +/// Defines the key of the database provider. +/// +[System.AttributeUsage(System.AttributeTargets.Class, Inherited = true, AllowMultiple = true)] +public sealed class JellyfinDatabaseProviderKeyAttribute : System.Attribute +{ + // See the attribute guidelines at + // http://go.microsoft.com/fwlink/?LinkId=85236 + private readonly string _databaseProviderKey; + + /// + /// Initializes a new instance of the class. + /// + /// The key on which to identify the annotated provider. + public JellyfinDatabaseProviderKeyAttribute(string databaseProviderKey) + { + this._databaseProviderKey = databaseProviderKey; + } + + /// + /// Gets the key on which to identify the annotated provider. + /// + public string DatabaseProviderKey + { + get { return _databaseProviderKey; } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs new file mode 100644 index 000000000..f22609dd4 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs @@ -0,0 +1,275 @@ +using System; +using System.Linq; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Entities.Security; +using Jellyfin.Data.Interfaces; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Implementations; + +/// +/// +/// Initializes a new instance of the class. +/// +/// The database context options. +/// Logger. +/// The provider for the database engine specific operations. +public class JellyfinDbContext(DbContextOptions options, ILogger logger, IJellyfinDatabaseProvider jellyfinDatabaseProvider) : DbContext(options) +{ + /// + /// Gets the containing the access schedules. + /// + public DbSet AccessSchedules => Set(); + + /// + /// Gets the containing the activity logs. + /// + public DbSet ActivityLogs => Set(); + + /// + /// Gets the containing the API keys. + /// + public DbSet ApiKeys => Set(); + + /// + /// Gets the containing the devices. + /// + public DbSet Devices => Set(); + + /// + /// Gets the containing the device options. + /// + public DbSet DeviceOptions => Set(); + + /// + /// Gets the containing the display preferences. + /// + public DbSet DisplayPreferences => Set(); + + /// + /// Gets the containing the image infos. + /// + public DbSet ImageInfos => Set(); + + /// + /// Gets the containing the item display preferences. + /// + public DbSet ItemDisplayPreferences => Set(); + + /// + /// Gets the containing the custom item display preferences. + /// + public DbSet CustomItemDisplayPreferences => Set(); + + /// + /// Gets the containing the permissions. + /// + public DbSet Permissions => Set(); + + /// + /// Gets the containing the preferences. + /// + public DbSet Preferences => Set(); + + /// + /// Gets the containing the users. + /// + public DbSet Users => Set(); + + /// + /// Gets the containing the trickplay metadata. + /// + public DbSet TrickplayInfos => Set(); + + /// + /// Gets the containing the media segments. + /// + public DbSet MediaSegments => Set(); + + /// + /// Gets the containing the user data. + /// + public DbSet UserData => Set(); + + /// + /// Gets the containing the user data. + /// + public DbSet AncestorIds => Set(); + + /// + /// Gets the containing the user data. + /// + public DbSet AttachmentStreamInfos => Set(); + + /// + /// Gets the containing the user data. + /// + public DbSet BaseItems => Set(); + + /// + /// Gets the containing the user data. + /// + public DbSet Chapters => Set(); + + /// + /// Gets the . + /// + public DbSet ItemValues => Set(); + + /// + /// Gets the . + /// + public DbSet ItemValuesMap => Set(); + + /// + /// Gets the . + /// + public DbSet MediaStreamInfos => Set(); + + /// + /// Gets the . + /// + public DbSet Peoples => Set(); + + /// + /// Gets the . + /// + public DbSet PeopleBaseItemMap => Set(); + + /// + /// Gets the containing the referenced Providers with ids. + /// + public DbSet BaseItemProviders => Set(); + + /// + /// Gets the . + /// + public DbSet BaseItemImageInfos => Set(); + + /// + /// Gets the . + /// + public DbSet BaseItemMetadataFields => Set(); + + /// + /// Gets the . + /// + public DbSet BaseItemTrailerTypes => Set(); + + /*public DbSet Artwork => Set(); + + public DbSet Books => Set(); + + public DbSet BookMetadata => Set(); + + public DbSet Chapters => Set(); + + public DbSet Collections => Set(); + + public DbSet CollectionItems => Set(); + + public DbSet Companies => Set(); + + public DbSet CompanyMetadata => Set(); + + public DbSet CustomItems => Set(); + + public DbSet CustomItemMetadata => Set(); + + public DbSet Episodes => Set(); + + public DbSet EpisodeMetadata => Set(); + + public DbSet Genres => Set(); + + public DbSet Groups => Set(); + + public DbSet Libraries => Set(); + + public DbSet LibraryItems => Set(); + + public DbSet LibraryRoot => Set(); + + public DbSet MediaFiles => Set(); + + public DbSet MediaFileStream => Set(); + + public DbSet Metadata => Set(); + + public DbSet MetadataProviders => Set(); + + public DbSet MetadataProviderIds => Set(); + + public DbSet Movies => Set(); + + public DbSet MovieMetadata => Set(); + + public DbSet MusicAlbums => Set(); + + public DbSet MusicAlbumMetadata => Set(); + + public DbSet People => Set(); + + public DbSet PersonRoles => Set(); + + public DbSet Photo => Set(); + + public DbSet PhotoMetadata => Set(); + + public DbSet ProviderMappings => Set(); + + public DbSet Ratings => Set(); + + /// + /// Repository for global::Jellyfin.Data.Entities.RatingSource - This is the entity to + /// store review ratings, not age ratings. + /// + public DbSet RatingSources => Set(); + + public DbSet Releases => Set(); + + public DbSet Seasons => Set(); + + public DbSet SeasonMetadata => Set(); + + public DbSet Series => Set(); + + public DbSet SeriesMetadata => Set Tracks => Set(); + + public DbSet TrackMetadata => Set();*/ + + /// + public override int SaveChanges() + { + foreach (var saveEntity in ChangeTracker.Entries() + .Where(e => e.State == EntityState.Modified) + .Select(entry => entry.Entity) + .OfType()) + { + saveEntity.OnSavingChanges(); + } + + try + { + return base.SaveChanges(); + } + catch (Exception e) + { + logger.LogError(e, "Error trying to save changes."); + throw; + } + } + + /// + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + jellyfinDatabaseProvider.OnModelCreating(modelBuilder); + base.OnModelCreating(modelBuilder); + + // Configuration for each entity is in it's own class inside 'ModelConfiguration'. + modelBuilder.ApplyConfigurationsFromAssembly(typeof(JellyfinDbContext).Assembly); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs new file mode 100644 index 000000000..9a63ed9f2 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs @@ -0,0 +1,17 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// FluentAPI configuration for the ActivityLog entity. +/// +public class ActivityLogConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasIndex(entity => entity.DateCreated); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs new file mode 100644 index 000000000..8cc817fb8 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs @@ -0,0 +1,21 @@ +using System; +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// AncestorId configuration. +/// +public class AncestorIdConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(e => new { e.ItemId, e.ParentItemId }); + builder.HasIndex(e => e.ParentItemId); + builder.HasOne(e => e.ParentItem).WithMany(e => e.ParentAncestors).HasForeignKey(f => f.ParentItemId); + builder.HasOne(e => e.Item).WithMany(e => e.Children).HasForeignKey(f => f.ItemId); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs new file mode 100644 index 000000000..3f19b6986 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs @@ -0,0 +1,20 @@ +using Jellyfin.Data.Entities.Security; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the ApiKey entity. + /// + public class ApiKeyConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + builder + .HasIndex(entity => entity.AccessToken) + .IsUnique(); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs new file mode 100644 index 000000000..057b6689a --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs @@ -0,0 +1,17 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// FluentAPI configuration for the AttachmentStreamInfo entity. +/// +public class AttachmentStreamInfoConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(e => new { e.ItemId, e.Index }); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs new file mode 100644 index 000000000..08f2a3356 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs @@ -0,0 +1,57 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// Configuration for BaseItem. +/// +public class BaseItemConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(e => e.Id); + // TODO: See rant in entity file. + // builder.HasOne(e => e.Parent).WithMany(e => e.DirectChildren).HasForeignKey(e => e.ParentId); + // builder.HasOne(e => e.TopParent).WithMany(e => e.AllChildren).HasForeignKey(e => e.TopParentId); + // builder.HasOne(e => e.Season).WithMany(e => e.SeasonEpisodes).HasForeignKey(e => e.SeasonId); + // builder.HasOne(e => e.Series).WithMany(e => e.SeriesEpisodes).HasForeignKey(e => e.SeriesId); + builder.HasMany(e => e.Peoples); + builder.HasMany(e => e.UserData); + builder.HasMany(e => e.ItemValues); + builder.HasMany(e => e.MediaStreams); + builder.HasMany(e => e.Chapters); + builder.HasMany(e => e.Provider); + builder.HasMany(e => e.ParentAncestors); + builder.HasMany(e => e.Children); + builder.HasMany(e => e.LockedFields); + builder.HasMany(e => e.TrailerTypes); + builder.HasMany(e => e.Images); + + builder.HasIndex(e => e.Path); + builder.HasIndex(e => e.ParentId); + builder.HasIndex(e => e.PresentationUniqueKey); + builder.HasIndex(e => new { e.Id, e.Type, e.IsFolder, e.IsVirtualItem }); + + // covering index + builder.HasIndex(e => new { e.TopParentId, e.Id }); + // series + builder.HasIndex(e => new { e.Type, e.SeriesPresentationUniqueKey, e.PresentationUniqueKey, e.SortName }); + // series counts + // seriesdateplayed sort order + builder.HasIndex(e => new { e.Type, e.SeriesPresentationUniqueKey, e.IsFolder, e.IsVirtualItem }); + // live tv programs + builder.HasIndex(e => new { e.Type, e.TopParentId, e.StartDate }); + // covering index for getitemvalues + builder.HasIndex(e => new { e.Type, e.TopParentId, e.Id }); + // used by movie suggestions + builder.HasIndex(e => new { e.Type, e.TopParentId, e.PresentationUniqueKey }); + // latest items + builder.HasIndex(e => new { e.Type, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey, e.DateCreated }); + builder.HasIndex(e => new { e.IsFolder, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey, e.DateCreated }); + // resume + builder.HasIndex(e => new { e.MediaType, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey }); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs new file mode 100644 index 000000000..b4c6511bf --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs @@ -0,0 +1,18 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// Provides configuration for the BaseItemMetadataField entity. +/// +public class BaseItemMetadataFieldConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(e => new { e.Id, e.ItemId }); + builder.HasOne(e => e.Item); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs new file mode 100644 index 000000000..d15049a1f --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs @@ -0,0 +1,20 @@ +using System; +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// BaseItemProvider configuration. +/// +public class BaseItemProviderConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(e => new { e.ItemId, e.ProviderId }); + builder.HasOne(e => e.Item); + builder.HasIndex(e => new { e.ProviderId, e.ProviderValue, e.ItemId }); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs new file mode 100644 index 000000000..e9564b854 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs @@ -0,0 +1,18 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// Provides configuration for the BaseItemMetadataField entity. +/// +public class BaseItemTrailerTypeConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(e => new { e.Id, e.ItemId }); + builder.HasOne(e => e.Item); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs new file mode 100644 index 000000000..5a84f7750 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs @@ -0,0 +1,19 @@ +using System; +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// Chapter configuration. +/// +public class ChapterConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(e => new { e.ItemId, e.ChapterIndex }); + builder.HasOne(e => e.Item); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs new file mode 100644 index 000000000..779aec986 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs @@ -0,0 +1,20 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the CustomItemDisplayPreferences entity. + /// + public class CustomItemDisplayPreferencesConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + builder + .HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client, entity.Key }) + .IsUnique(); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs new file mode 100644 index 000000000..a750b65c0 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs @@ -0,0 +1,28 @@ +using Jellyfin.Data.Entities.Security; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the Device entity. + /// + public class DeviceConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + builder + .HasIndex(entity => new { entity.DeviceId, entity.DateLastActivity }); + + builder + .HasIndex(entity => new { entity.AccessToken, entity.DateLastActivity }); + + builder + .HasIndex(entity => new { entity.UserId, entity.DeviceId }); + + builder + .HasIndex(entity => entity.DeviceId); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs new file mode 100644 index 000000000..038afd752 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs @@ -0,0 +1,20 @@ +using Jellyfin.Data.Entities.Security; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the DeviceOptions entity. + /// + public class DeviceOptionsConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + builder + .HasIndex(entity => entity.DeviceId) + .IsUnique(); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs new file mode 100644 index 000000000..9b437861b --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs @@ -0,0 +1,25 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the DisplayPreferencesConfiguration entity. + /// + public class DisplayPreferencesConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + builder + .HasMany(d => d.HomeSections) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + builder + .HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client }) + .IsUnique(); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs new file mode 100644 index 000000000..abeeb09c9 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs @@ -0,0 +1,19 @@ +using System; +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// itemvalues Configuration. +/// +public class ItemValuesConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(e => e.ItemValueId); + builder.HasIndex(e => new { e.Type, e.CleanValue }).IsUnique(); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs new file mode 100644 index 000000000..9c22b114c --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs @@ -0,0 +1,20 @@ +using System; +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// itemvalues Configuration. +/// +public class ItemValuesMapConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(e => new { e.ItemValueId, e.ItemId }); + builder.HasOne(e => e.Item); + builder.HasOne(e => e.ItemValue); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs new file mode 100644 index 000000000..7e572f9a3 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs @@ -0,0 +1,22 @@ +using System; +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// People configuration. +/// +public class MediaStreamInfoConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(e => new { e.ItemId, e.StreamIndex }); + builder.HasIndex(e => e.StreamIndex); + builder.HasIndex(e => e.StreamType); + builder.HasIndex(e => new { e.StreamIndex, e.StreamType }); + builder.HasIndex(e => new { e.StreamIndex, e.StreamType, e.Language }); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs new file mode 100644 index 000000000..cdaee9161 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs @@ -0,0 +1,22 @@ +using System; +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// People configuration. +/// +public class PeopleBaseItemMapConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(e => new { e.ItemId, e.PeopleId }); + builder.HasIndex(e => new { e.ItemId, e.SortOrder }); + builder.HasIndex(e => new { e.ItemId, e.ListOrder }); + builder.HasOne(e => e.Item); + builder.HasOne(e => e.People); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs new file mode 100644 index 000000000..f3cccb13f --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs @@ -0,0 +1,20 @@ +using System; +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// People configuration. +/// +public class PeopleConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(e => e.Id); + builder.HasIndex(e => e.Name); + builder.HasMany(e => e.BaseItems); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs new file mode 100644 index 000000000..240e284c0 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs @@ -0,0 +1,24 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the Permission entity. + /// + public class PermissionConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + // Used to get a user's permissions or a specific permission for a user. + // Also prevents multiple values being created for a user. + // Filtered over non-null user ids for when other entities (groups, API keys) get permissions + builder + .HasIndex(p => new { p.UserId, p.Kind }) + .HasFilter("[UserId] IS NOT NULL") + .IsUnique(); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs new file mode 100644 index 000000000..49c869c6a --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs @@ -0,0 +1,21 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the Permission entity. + /// + public class PreferenceConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + builder + .HasIndex(p => new { p.UserId, p.Kind }) + .HasFilter("[UserId] IS NOT NULL") + .IsUnique(); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs new file mode 100644 index 000000000..dc1c17e5e --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs @@ -0,0 +1,18 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the TrickplayInfo entity. + /// + public class TrickplayInfoConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(info => new { info.ItemId, info.Width }); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs new file mode 100644 index 000000000..a369cf656 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs @@ -0,0 +1,56 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the User entity. + /// + public class UserConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + builder + .Property(user => user.Username) + .UseCollation("NOCASE"); + + builder + .HasOne(u => u.ProfileImage) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + builder + .HasMany(u => u.Permissions) + .WithOne() + .HasForeignKey(p => p.UserId) + .OnDelete(DeleteBehavior.Cascade); + + builder + .HasMany(u => u.Preferences) + .WithOne() + .HasForeignKey(p => p.UserId) + .OnDelete(DeleteBehavior.Cascade); + + builder + .HasMany(u => u.AccessSchedules) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + builder + .HasMany(u => u.DisplayPreferences) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + builder + .HasMany(u => u.ItemDisplayPreferences) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + builder + .HasIndex(entity => entity.Username) + .IsUnique(); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs new file mode 100644 index 000000000..7bbb28d43 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs @@ -0,0 +1,23 @@ +using System; +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration; + +/// +/// FluentAPI configuration for the UserData entity. +/// +public class UserDataConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(d => new { d.ItemId, d.UserId, d.CustomDataKey }); + builder.HasIndex(d => new { d.ItemId, d.UserId, d.Played }); + builder.HasIndex(d => new { d.ItemId, d.UserId, d.PlaybackPositionTicks }); + builder.HasIndex(d => new { d.ItemId, d.UserId, d.IsFavorite }); + builder.HasIndex(d => new { d.ItemId, d.UserId, d.LastPlayedDate }); + builder.HasOne(e => e.Item); + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Jellyfin.Database.Providers.PgSql.csproj b/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Jellyfin.Database.Providers.PgSql.csproj new file mode 100644 index 000000000..ae1497403 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Jellyfin.Database.Providers.PgSql.csproj @@ -0,0 +1,51 @@ + + + + net9.0 + enable + enable + false + true + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Jellyfin.Database.Providers.SqLite.csproj b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Jellyfin.Database.Providers.SqLite.csproj new file mode 100644 index 000000000..0f0427539 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Jellyfin.Database.Providers.SqLite.csproj @@ -0,0 +1,51 @@ + + + + net9.0 + enable + enable + false + true + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200514181226_AddActivityLog.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200514181226_AddActivityLog.Designer.cs new file mode 100644 index 000000000..80fe784dd --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200514181226_AddActivityLog.Designer.cs @@ -0,0 +1,72 @@ +#pragma warning disable CS1591 + +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20200514181226_AddActivityLog")] + partial class AddActivityLog + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "3.1.3"); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Overview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ActivityLogs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200514181226_AddActivityLog.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200514181226_AddActivityLog.cs new file mode 100644 index 000000000..002e5296e --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200514181226_AddActivityLog.cs @@ -0,0 +1,46 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1601 + +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class AddActivityLog : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "jellyfin"); + + migrationBuilder.CreateTable( + name: "ActivityLogs", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(maxLength: 512, nullable: false), + Overview = table.Column(maxLength: 512, nullable: true), + ShortOverview = table.Column(maxLength: 512, nullable: true), + Type = table.Column(maxLength: 256, nullable: false), + UserId = table.Column(nullable: false), + ItemId = table.Column(maxLength: 256, nullable: true), + DateCreated = table.Column(nullable: false), + LogSeverity = table.Column(nullable: false), + RowVersion = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ActivityLogs", x => x.Id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ActivityLogs", + schema: "jellyfin"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200613202153_AddUsers.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200613202153_AddUsers.Designer.cs new file mode 100644 index 000000000..7aa4479b3 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200613202153_AddUsers.Designer.cs @@ -0,0 +1,312 @@ +#pragma warning disable CS1591 + +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20200613202153_AddUsers")] + partial class AddUsers + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "3.1.4"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Overview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Permission_Permissions_Guid"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.HasKey("Id"); + + b.HasIndex("Preference_Preferences_Guid"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EasyPassword") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("Permission_Permissions_Guid"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("Preference_Preferences_Guid"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200613202153_AddUsers.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200613202153_AddUsers.cs new file mode 100644 index 000000000..706a97ba2 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200613202153_AddUsers.cs @@ -0,0 +1,197 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1601 + +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class AddUsers : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Users", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false), + Username = table.Column(maxLength: 255, nullable: false), + Password = table.Column(maxLength: 65535, nullable: true), + EasyPassword = table.Column(maxLength: 65535, nullable: true), + MustUpdatePassword = table.Column(nullable: false), + AudioLanguagePreference = table.Column(maxLength: 255, nullable: true), + AuthenticationProviderId = table.Column(maxLength: 255, nullable: false), + PasswordResetProviderId = table.Column(maxLength: 255, nullable: false), + InvalidLoginAttemptCount = table.Column(nullable: false), + LastActivityDate = table.Column(nullable: true), + LastLoginDate = table.Column(nullable: true), + LoginAttemptsBeforeLockout = table.Column(nullable: true), + SubtitleMode = table.Column(nullable: false), + PlayDefaultAudioTrack = table.Column(nullable: false), + SubtitleLanguagePreference = table.Column(maxLength: 255, nullable: true), + DisplayMissingEpisodes = table.Column(nullable: false), + DisplayCollectionsView = table.Column(nullable: false), + EnableLocalPassword = table.Column(nullable: false), + HidePlayedInLatest = table.Column(nullable: false), + RememberAudioSelections = table.Column(nullable: false), + RememberSubtitleSelections = table.Column(nullable: false), + EnableNextEpisodeAutoPlay = table.Column(nullable: false), + EnableAutoLogin = table.Column(nullable: false), + EnableUserPreferenceAccess = table.Column(nullable: false), + MaxParentalAgeRating = table.Column(nullable: true), + RemoteClientBitrateLimit = table.Column(nullable: true), + InternalId = table.Column(nullable: false), + SyncPlayAccess = table.Column(nullable: false), + RowVersion = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AccessSchedules", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(nullable: false), + DayOfWeek = table.Column(nullable: false), + StartHour = table.Column(nullable: false), + EndHour = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AccessSchedules", x => x.Id); + table.ForeignKey( + name: "FK_AccessSchedules_Users_UserId", + column: x => x.UserId, + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ImageInfos", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(nullable: true), + Path = table.Column(maxLength: 512, nullable: false), + LastModified = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ImageInfos", x => x.Id); + table.ForeignKey( + name: "FK_ImageInfos_Users_UserId", + column: x => x.UserId, + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Permissions", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Kind = table.Column(nullable: false), + Value = table.Column(nullable: false), + RowVersion = table.Column(nullable: false), + Permission_Permissions_Guid = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Permissions", x => x.Id); + table.ForeignKey( + name: "FK_Permissions_Users_Permission_Permissions_Guid", + column: x => x.Permission_Permissions_Guid, + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Preferences", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Kind = table.Column(nullable: false), + Value = table.Column(maxLength: 65535, nullable: false), + RowVersion = table.Column(nullable: false), + Preference_Preferences_Guid = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Preferences", x => x.Id); + table.ForeignKey( + name: "FK_Preferences_Users_Preference_Preferences_Guid", + column: x => x.Preference_Preferences_Guid, + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_AccessSchedules_UserId", + schema: "jellyfin", + table: "AccessSchedules", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_ImageInfos_UserId", + schema: "jellyfin", + table: "ImageInfos", + column: "UserId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Permissions_Permission_Permissions_Guid", + schema: "jellyfin", + table: "Permissions", + column: "Permission_Permissions_Guid"); + + migrationBuilder.CreateIndex( + name: "IX_Preferences_Preference_Preferences_Guid", + schema: "jellyfin", + table: "Preferences", + column: "Preference_Preferences_Guid"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AccessSchedules", + schema: "jellyfin"); + + migrationBuilder.DropTable( + name: "ImageInfos", + schema: "jellyfin"); + + migrationBuilder.DropTable( + name: "Permissions", + schema: "jellyfin"); + + migrationBuilder.DropTable( + name: "Preferences", + schema: "jellyfin"); + + migrationBuilder.DropTable( + name: "Users", + schema: "jellyfin"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200728005145_AddDisplayPreferences.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200728005145_AddDisplayPreferences.Designer.cs new file mode 100644 index 000000000..3860c851d --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200728005145_AddDisplayPreferences.Designer.cs @@ -0,0 +1,459 @@ +#pragma warning disable CS1591 + +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20200728005145_AddDisplayPreferences")] + partial class AddDisplayPreferences + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "3.1.6"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Overview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("DashboardTheme") + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(64); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Permission_Permissions_Guid"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.HasKey("Id"); + + b.HasIndex("Preference_Preferences_Guid"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EasyPassword") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("DisplayPreferences") + .HasForeignKey("Jellyfin.Data.Entities.DisplayPreferences", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("Permission_Permissions_Guid"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("Preference_Preferences_Guid"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200728005145_AddDisplayPreferences.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200728005145_AddDisplayPreferences.cs new file mode 100644 index 000000000..8cd551642 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200728005145_AddDisplayPreferences.cs @@ -0,0 +1,132 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1601 + +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class AddDisplayPreferences : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DisplayPreferences", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(nullable: false), + Client = table.Column(maxLength: 32, nullable: false), + ShowSidebar = table.Column(nullable: false), + ShowBackdrop = table.Column(nullable: false), + ScrollDirection = table.Column(nullable: false), + IndexBy = table.Column(nullable: true), + SkipForwardLength = table.Column(nullable: false), + SkipBackwardLength = table.Column(nullable: false), + ChromecastVersion = table.Column(nullable: false), + EnableNextVideoInfoOverlay = table.Column(nullable: false), + DashboardTheme = table.Column(maxLength: 32, nullable: true), + TvHome = table.Column(maxLength: 32, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DisplayPreferences", x => x.Id); + table.ForeignKey( + name: "FK_DisplayPreferences_Users_UserId", + column: x => x.UserId, + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ItemDisplayPreferences", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(nullable: false), + ItemId = table.Column(nullable: false), + Client = table.Column(maxLength: 32, nullable: false), + ViewType = table.Column(nullable: false), + RememberIndexing = table.Column(nullable: false), + IndexBy = table.Column(nullable: true), + RememberSorting = table.Column(nullable: false), + SortBy = table.Column(maxLength: 64, nullable: false), + SortOrder = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ItemDisplayPreferences", x => x.Id); + table.ForeignKey( + name: "FK_ItemDisplayPreferences_Users_UserId", + column: x => x.UserId, + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "HomeSection", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DisplayPreferencesId = table.Column(nullable: false), + Order = table.Column(nullable: false), + Type = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_HomeSection", x => x.Id); + table.ForeignKey( + name: "FK_HomeSection_DisplayPreferences_DisplayPreferencesId", + column: x => x.DisplayPreferencesId, + principalSchema: "jellyfin", + principalTable: "DisplayPreferences", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_DisplayPreferences_UserId", + schema: "jellyfin", + table: "DisplayPreferences", + column: "UserId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_HomeSection_DisplayPreferencesId", + schema: "jellyfin", + table: "HomeSection", + column: "DisplayPreferencesId"); + + migrationBuilder.CreateIndex( + name: "IX_ItemDisplayPreferences_UserId", + schema: "jellyfin", + table: "ItemDisplayPreferences", + column: "UserId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "HomeSection", + schema: "jellyfin"); + + migrationBuilder.DropTable( + name: "ItemDisplayPreferences", + schema: "jellyfin"); + + migrationBuilder.DropTable( + name: "DisplayPreferences", + schema: "jellyfin"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs new file mode 100644 index 000000000..1134f7aa4 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs @@ -0,0 +1,461 @@ +#pragma warning disable CS1591 + +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20200905220533_FixDisplayPreferencesIndex")] + partial class FixDisplayPreferencesIndex + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "3.1.7"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Overview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("DashboardTheme") + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("UserId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(64); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Permission_Permissions_Guid"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.HasKey("Id"); + + b.HasIndex("Preference_Preferences_Guid"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EasyPassword") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("DisplayPreferences") + .HasForeignKey("Jellyfin.Data.Entities.DisplayPreferences", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("Permission_Permissions_Guid"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("Preference_Preferences_Guid"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200905220533_FixDisplayPreferencesIndex.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200905220533_FixDisplayPreferencesIndex.cs new file mode 100644 index 000000000..91d2b190d --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20200905220533_FixDisplayPreferencesIndex.cs @@ -0,0 +1,51 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1601 + +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class FixDisplayPreferencesIndex : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_DisplayPreferences_UserId", + schema: "jellyfin", + table: "DisplayPreferences"); + + migrationBuilder.CreateIndex( + name: "IX_DisplayPreferences_UserId", + schema: "jellyfin", + table: "DisplayPreferences", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_DisplayPreferences_UserId_Client", + schema: "jellyfin", + table: "DisplayPreferences", + columns: new[] { "UserId", "Client" }, + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_DisplayPreferences_UserId", + schema: "jellyfin", + table: "DisplayPreferences"); + + migrationBuilder.DropIndex( + name: "IX_DisplayPreferences_UserId_Client", + schema: "jellyfin", + table: "DisplayPreferences"); + + migrationBuilder.CreateIndex( + name: "IX_DisplayPreferences_UserId", + schema: "jellyfin", + table: "DisplayPreferences", + column: "UserId", + unique: true); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs new file mode 100644 index 000000000..607310caa --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs @@ -0,0 +1,464 @@ +#pragma warning disable CS1591 + +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20201004171403_AddMaxActiveSessions")] + partial class AddMaxActiveSessions + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "3.1.8"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Overview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("DashboardTheme") + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("UserId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(64); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Permission_Permissions_Guid"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.HasKey("Id"); + + b.HasIndex("Preference_Preferences_Guid"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EasyPassword") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("DisplayPreferences") + .HasForeignKey("Jellyfin.Data.Entities.DisplayPreferences", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("Permission_Permissions_Guid"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("Preference_Preferences_Guid"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201004171403_AddMaxActiveSessions.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201004171403_AddMaxActiveSessions.cs new file mode 100644 index 000000000..e37b4e696 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201004171403_AddMaxActiveSessions.cs @@ -0,0 +1,28 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1601 + +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class AddMaxActiveSessions : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "MaxActiveSessions", + schema: "jellyfin", + table: "Users", + nullable: false, + defaultValue: 0); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "MaxActiveSessions", + schema: "jellyfin", + table: "Users"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs new file mode 100644 index 000000000..02c3fc753 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs @@ -0,0 +1,522 @@ +#pragma warning disable CS1591 +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20201204223655_AddCustomDisplayPreferences")] + partial class AddCustomDisplayPreferences + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "5.0.0"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Permission_Permissions_Guid"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Preference_Preferences_Guid"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EasyPassword") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("DisplayPreferences") + .HasForeignKey("Jellyfin.Data.Entities.DisplayPreferences", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("Permission_Permissions_Guid"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("Preference_Preferences_Guid"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences") + .IsRequired(); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201204223655_AddCustomDisplayPreferences.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201204223655_AddCustomDisplayPreferences.cs new file mode 100644 index 000000000..ce2b21d0c --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20201204223655_AddCustomDisplayPreferences.cs @@ -0,0 +1,108 @@ +#pragma warning disable CS1591 +// +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class AddCustomDisplayPreferences : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_DisplayPreferences_UserId_Client", + schema: "jellyfin", + table: "DisplayPreferences"); + + migrationBuilder.AlterColumn( + name: "MaxActiveSessions", + schema: "jellyfin", + table: "Users", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AddColumn( + name: "ItemId", + schema: "jellyfin", + table: "DisplayPreferences", + type: "TEXT", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); + + migrationBuilder.CreateTable( + name: "CustomItemDisplayPreferences", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(type: "TEXT", nullable: false), + ItemId = table.Column(type: "TEXT", nullable: false), + Client = table.Column(type: "TEXT", maxLength: 32, nullable: false), + Key = table.Column(type: "TEXT", nullable: false), + Value = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CustomItemDisplayPreferences", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_DisplayPreferences_UserId_ItemId_Client", + schema: "jellyfin", + table: "DisplayPreferences", + columns: new[] { "UserId", "ItemId", "Client" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_CustomItemDisplayPreferences_UserId", + schema: "jellyfin", + table: "CustomItemDisplayPreferences", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_CustomItemDisplayPreferences_UserId_ItemId_Client_Key", + schema: "jellyfin", + table: "CustomItemDisplayPreferences", + columns: new[] { "UserId", "ItemId", "Client", "Key" }, + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CustomItemDisplayPreferences", + schema: "jellyfin"); + + migrationBuilder.DropIndex( + name: "IX_DisplayPreferences_UserId_ItemId_Client", + schema: "jellyfin", + table: "DisplayPreferences"); + + migrationBuilder.DropColumn( + name: "ItemId", + schema: "jellyfin", + table: "DisplayPreferences"); + + migrationBuilder.AlterColumn( + name: "MaxActiveSessions", + schema: "jellyfin", + table: "Users", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.CreateIndex( + name: "IX_DisplayPreferences_UserId_Client", + schema: "jellyfin", + table: "DisplayPreferences", + columns: new[] { "UserId", "Client" }, + unique: true); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs new file mode 100644 index 000000000..1cfd7112c --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs @@ -0,0 +1,535 @@ +#pragma warning disable CS1591 + +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20210320181425_AddIndexesAndCollations")] + partial class AddIndexesAndCollations + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "5.0.3"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EasyPassword") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210320181425_AddIndexesAndCollations.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210320181425_AddIndexesAndCollations.cs new file mode 100644 index 000000000..3acd5e7b5 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210320181425_AddIndexesAndCollations.cs @@ -0,0 +1,240 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1601 + +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class AddIndexesAndCollations : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ImageInfos_Users_UserId", + schema: "jellyfin", + table: "ImageInfos"); + + migrationBuilder.DropForeignKey( + name: "FK_Permissions_Users_Permission_Permissions_Guid", + schema: "jellyfin", + table: "Permissions"); + + migrationBuilder.DropForeignKey( + name: "FK_Preferences_Users_Preference_Preferences_Guid", + schema: "jellyfin", + table: "Preferences"); + + migrationBuilder.DropIndex( + name: "IX_Preferences_Preference_Preferences_Guid", + schema: "jellyfin", + table: "Preferences"); + + migrationBuilder.DropIndex( + name: "IX_Permissions_Permission_Permissions_Guid", + schema: "jellyfin", + table: "Permissions"); + + migrationBuilder.DropIndex( + name: "IX_DisplayPreferences_UserId", + schema: "jellyfin", + table: "DisplayPreferences"); + + migrationBuilder.DropIndex( + name: "IX_CustomItemDisplayPreferences_UserId", + schema: "jellyfin", + table: "CustomItemDisplayPreferences"); + + migrationBuilder.AlterColumn( + name: "Username", + schema: "jellyfin", + table: "Users", + type: "TEXT", + maxLength: 255, + nullable: false, + collation: "NOCASE", + oldClrType: typeof(string), + oldType: "TEXT", + oldMaxLength: 255); + + migrationBuilder.AddColumn( + name: "UserId", + schema: "jellyfin", + table: "Preferences", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "UserId", + schema: "jellyfin", + table: "Permissions", + type: "TEXT", + nullable: true); + + migrationBuilder.Sql("UPDATE Preferences SET UserId = Preference_Preferences_Guid"); + migrationBuilder.Sql("UPDATE Permissions SET UserId = Permission_Permissions_Guid"); + + migrationBuilder.CreateIndex( + name: "IX_Users_Username", + schema: "jellyfin", + table: "Users", + column: "Username", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Preferences_UserId_Kind", + schema: "jellyfin", + table: "Preferences", + columns: new[] { "UserId", "Kind" }, + unique: true, + filter: "[UserId] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_Permissions_UserId_Kind", + schema: "jellyfin", + table: "Permissions", + columns: new[] { "UserId", "Kind" }, + unique: true, + filter: "[UserId] IS NOT NULL"); + + migrationBuilder.AddForeignKey( + name: "FK_ImageInfos_Users_UserId", + schema: "jellyfin", + table: "ImageInfos", + column: "UserId", + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Permissions_Users_UserId", + schema: "jellyfin", + table: "Permissions", + column: "UserId", + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Preferences_Users_UserId", + schema: "jellyfin", + table: "Preferences", + column: "UserId", + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ImageInfos_Users_UserId", + schema: "jellyfin", + table: "ImageInfos"); + + migrationBuilder.DropForeignKey( + name: "FK_Permissions_Users_UserId", + schema: "jellyfin", + table: "Permissions"); + + migrationBuilder.DropForeignKey( + name: "FK_Preferences_Users_UserId", + schema: "jellyfin", + table: "Preferences"); + + migrationBuilder.DropIndex( + name: "IX_Users_Username", + schema: "jellyfin", + table: "Users"); + + migrationBuilder.DropIndex( + name: "IX_Preferences_UserId_Kind", + schema: "jellyfin", + table: "Preferences"); + + migrationBuilder.DropIndex( + name: "IX_Permissions_UserId_Kind", + schema: "jellyfin", + table: "Permissions"); + + migrationBuilder.DropColumn( + name: "UserId", + schema: "jellyfin", + table: "Preferences"); + + migrationBuilder.DropColumn( + name: "UserId", + schema: "jellyfin", + table: "Permissions"); + + migrationBuilder.AlterColumn( + name: "Username", + schema: "jellyfin", + table: "Users", + type: "TEXT", + maxLength: 255, + nullable: false, + oldClrType: typeof(string), + oldType: "TEXT", + oldMaxLength: 255, + oldCollation: "NOCASE"); + + migrationBuilder.CreateIndex( + name: "IX_Preferences_Preference_Preferences_Guid", + schema: "jellyfin", + table: "Preferences", + column: "Preference_Preferences_Guid"); + + migrationBuilder.CreateIndex( + name: "IX_Permissions_Permission_Permissions_Guid", + schema: "jellyfin", + table: "Permissions", + column: "Permission_Permissions_Guid"); + + migrationBuilder.CreateIndex( + name: "IX_DisplayPreferences_UserId", + schema: "jellyfin", + table: "DisplayPreferences", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_CustomItemDisplayPreferences_UserId", + schema: "jellyfin", + table: "CustomItemDisplayPreferences", + column: "UserId"); + + migrationBuilder.AddForeignKey( + name: "FK_ImageInfos_Users_UserId", + schema: "jellyfin", + table: "ImageInfos", + column: "UserId", + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_Permissions_Users_Permission_Permissions_Guid", + schema: "jellyfin", + table: "Permissions", + column: "Permission_Permissions_Guid", + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_Preferences_Users_Preference_Preferences_Guid", + schema: "jellyfin", + table: "Preferences", + column: "Preference_Preferences_Guid", + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs new file mode 100644 index 000000000..ecf7af495 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs @@ -0,0 +1,520 @@ +#pragma warning disable CS1591 +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20210407110544_NullableCustomPrefValue")] + partial class NullableCustomPrefValue + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "5.0.3"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Permission_Permissions_Guid"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Preference_Preferences_Guid"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EasyPassword") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("Permission_Permissions_Guid"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("Preference_Preferences_Guid"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210407110544_NullableCustomPrefValue.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210407110544_NullableCustomPrefValue.cs new file mode 100644 index 000000000..a6b169a61 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210407110544_NullableCustomPrefValue.cs @@ -0,0 +1,35 @@ +#pragma warning disable CS1591 +// +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class NullableCustomPrefValue : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Value", + schema: "jellyfin", + table: "CustomItemDisplayPreferences", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Value", + schema: "jellyfin", + table: "CustomItemDisplayPreferences", + type: "TEXT", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210814002109_AddDevices.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210814002109_AddDevices.Designer.cs new file mode 100644 index 000000000..dccba6f77 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210814002109_AddDevices.Designer.cs @@ -0,0 +1,653 @@ +#pragma warning disable CS1591 + +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20210814002109_AddDevices")] + partial class AddDevices + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "5.0.7"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EasyPassword") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210814002109_AddDevices.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210814002109_AddDevices.cs new file mode 100644 index 000000000..bf90044cb --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20210814002109_AddDevices.cs @@ -0,0 +1,128 @@ +#pragma warning disable CS1591, SA1601 + +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class AddDevices : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ApiKeys", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DateCreated = table.Column(type: "TEXT", nullable: false), + DateLastActivity = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 64, nullable: false), + AccessToken = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiKeys", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "DeviceOptions", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DeviceId = table.Column(type: "TEXT", nullable: false), + CustomName = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DeviceOptions", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Devices", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(type: "TEXT", nullable: false), + AccessToken = table.Column(type: "TEXT", nullable: false), + AppName = table.Column(type: "TEXT", maxLength: 64, nullable: false), + AppVersion = table.Column(type: "TEXT", maxLength: 32, nullable: false), + DeviceName = table.Column(type: "TEXT", maxLength: 64, nullable: false), + DeviceId = table.Column(type: "TEXT", maxLength: 256, nullable: false), + IsActive = table.Column(type: "INTEGER", nullable: false), + DateCreated = table.Column(type: "TEXT", nullable: false), + DateModified = table.Column(type: "TEXT", nullable: false), + DateLastActivity = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Devices", x => x.Id); + table.ForeignKey( + name: "FK_Devices_Users_UserId", + column: x => x.UserId, + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ApiKeys_AccessToken", + schema: "jellyfin", + table: "ApiKeys", + column: "AccessToken", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_DeviceOptions_DeviceId", + schema: "jellyfin", + table: "DeviceOptions", + column: "DeviceId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Devices_AccessToken_DateLastActivity", + schema: "jellyfin", + table: "Devices", + columns: new[] { "AccessToken", "DateLastActivity" }); + + migrationBuilder.CreateIndex( + name: "IX_Devices_DeviceId", + schema: "jellyfin", + table: "Devices", + column: "DeviceId"); + + migrationBuilder.CreateIndex( + name: "IX_Devices_DeviceId_DateLastActivity", + schema: "jellyfin", + table: "Devices", + columns: new[] { "DeviceId", "DateLastActivity" }); + + migrationBuilder.CreateIndex( + name: "IX_Devices_UserId_DeviceId", + schema: "jellyfin", + table: "Devices", + columns: new[] { "UserId", "DeviceId" }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ApiKeys", + schema: "jellyfin"); + + migrationBuilder.DropTable( + name: "DeviceOptions", + schema: "jellyfin"); + + migrationBuilder.DropTable( + name: "Devices", + schema: "jellyfin"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs new file mode 100644 index 000000000..e821c106e --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs @@ -0,0 +1,657 @@ +#pragma warning disable CS1591 + +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20221022080052_AddIndexActivityLogsDateCreated")] + partial class AddIndexActivityLogsDateCreated + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "6.0.9"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules", "jellyfin"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs", "jellyfin"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences", "jellyfin"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences", "jellyfin"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection", "jellyfin"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos", "jellyfin"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences", "jellyfin"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions", "jellyfin"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences", "jellyfin"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys", "jellyfin"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices", "jellyfin"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions", "jellyfin"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EasyPassword") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users", "jellyfin"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.cs new file mode 100644 index 000000000..9d5d7632b --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.cs @@ -0,0 +1,28 @@ +#pragma warning disable CS1591, SA1601 + +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class AddIndexActivityLogsDateCreated : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateIndex( + name: "IX_ActivityLogs_DateCreated", + schema: "jellyfin", + table: "ActivityLogs", + column: "DateCreated"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_ActivityLogs_DateCreated", + schema: "jellyfin", + table: "ActivityLogs"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230526173516_RemoveEasyPassword.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230526173516_RemoveEasyPassword.Designer.cs new file mode 100644 index 000000000..360fa0376 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230526173516_RemoveEasyPassword.Designer.cs @@ -0,0 +1,650 @@ +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20230526173516_RemoveEasyPassword")] + partial class RemoveEasyPassword + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.5"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230526173516_RemoveEasyPassword.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230526173516_RemoveEasyPassword.cs new file mode 100644 index 000000000..354d91c38 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230526173516_RemoveEasyPassword.cs @@ -0,0 +1,164 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class RemoveEasyPassword : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "EasyPassword", + schema: "jellyfin", + table: "Users"); + + migrationBuilder.RenameTable( + name: "Users", + schema: "jellyfin", + newName: "Users"); + + migrationBuilder.RenameTable( + name: "Preferences", + schema: "jellyfin", + newName: "Preferences"); + + migrationBuilder.RenameTable( + name: "Permissions", + schema: "jellyfin", + newName: "Permissions"); + + migrationBuilder.RenameTable( + name: "ItemDisplayPreferences", + schema: "jellyfin", + newName: "ItemDisplayPreferences"); + + migrationBuilder.RenameTable( + name: "ImageInfos", + schema: "jellyfin", + newName: "ImageInfos"); + + migrationBuilder.RenameTable( + name: "HomeSection", + schema: "jellyfin", + newName: "HomeSection"); + + migrationBuilder.RenameTable( + name: "DisplayPreferences", + schema: "jellyfin", + newName: "DisplayPreferences"); + + migrationBuilder.RenameTable( + name: "Devices", + schema: "jellyfin", + newName: "Devices"); + + migrationBuilder.RenameTable( + name: "DeviceOptions", + schema: "jellyfin", + newName: "DeviceOptions"); + + migrationBuilder.RenameTable( + name: "CustomItemDisplayPreferences", + schema: "jellyfin", + newName: "CustomItemDisplayPreferences"); + + migrationBuilder.RenameTable( + name: "ApiKeys", + schema: "jellyfin", + newName: "ApiKeys"); + + migrationBuilder.RenameTable( + name: "ActivityLogs", + schema: "jellyfin", + newName: "ActivityLogs"); + + migrationBuilder.RenameTable( + name: "AccessSchedules", + schema: "jellyfin", + newName: "AccessSchedules"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "jellyfin"); + + migrationBuilder.RenameTable( + name: "Users", + newName: "Users", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "Preferences", + newName: "Preferences", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "Permissions", + newName: "Permissions", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "ItemDisplayPreferences", + newName: "ItemDisplayPreferences", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "ImageInfos", + newName: "ImageInfos", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "HomeSection", + newName: "HomeSection", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "DisplayPreferences", + newName: "DisplayPreferences", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "Devices", + newName: "Devices", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "DeviceOptions", + newName: "DeviceOptions", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "CustomItemDisplayPreferences", + newName: "CustomItemDisplayPreferences", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "ApiKeys", + newName: "ApiKeys", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "ActivityLogs", + newName: "ActivityLogs", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "AccessSchedules", + newName: "AccessSchedules", + newSchema: "jellyfin"); + + migrationBuilder.AddColumn( + name: "EasyPassword", + schema: "jellyfin", + table: "Users", + type: "TEXT", + maxLength: 65535, + nullable: true); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230626233818_AddTrickplayInfos.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230626233818_AddTrickplayInfos.Designer.cs new file mode 100644 index 000000000..17d33845f --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230626233818_AddTrickplayInfos.Designer.cs @@ -0,0 +1,681 @@ +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20230626233818_AddTrickplayInfos")] + partial class AddTrickplayInfos + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.7"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230626233818_AddTrickplayInfos.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230626233818_AddTrickplayInfos.cs new file mode 100644 index 000000000..85f1b5b7d --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230626233818_AddTrickplayInfos.cs @@ -0,0 +1,40 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class AddTrickplayInfos : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "TrickplayInfos", + columns: table => new + { + ItemId = table.Column(type: "TEXT", nullable: false), + Width = table.Column(type: "INTEGER", nullable: false), + Height = table.Column(type: "INTEGER", nullable: false), + TileWidth = table.Column(type: "INTEGER", nullable: false), + TileHeight = table.Column(type: "INTEGER", nullable: false), + ThumbnailCount = table.Column(type: "INTEGER", nullable: false), + Interval = table.Column(type: "INTEGER", nullable: false), + Bandwidth = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TrickplayInfos", x => new { x.ItemId, x.Width }); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "TrickplayInfos"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230923170422_UserCastReceiver.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230923170422_UserCastReceiver.Designer.cs new file mode 100644 index 000000000..4c0917669 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230923170422_UserCastReceiver.Designer.cs @@ -0,0 +1,654 @@ +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20230923170422_UserCastReceiver")] + partial class UserCastReceiver + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.11"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230923170422_UserCastReceiver.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230923170422_UserCastReceiver.cs new file mode 100644 index 000000000..5919e4665 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20230923170422_UserCastReceiver.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class UserCastReceiver : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CastReceiverId", + table: "Users", + type: "TEXT", + maxLength: 32, + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CastReceiverId", + table: "Users"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240729140605_AddMediaSegments.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240729140605_AddMediaSegments.Designer.cs new file mode 100644 index 000000000..35a3cdad2 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240729140605_AddMediaSegments.Designer.cs @@ -0,0 +1,708 @@ +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20240729140605_AddMediaSegments")] + partial class AddMediaSegments + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.7"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EndTicks") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("StartTicks") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240729140605_AddMediaSegments.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240729140605_AddMediaSegments.cs new file mode 100644 index 000000000..18164d999 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240729140605_AddMediaSegments.cs @@ -0,0 +1,38 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class AddMediaSegments : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "MediaSegments", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + ItemId = table.Column(type: "TEXT", nullable: false), + Type = table.Column(type: "INTEGER", nullable: false), + EndTicks = table.Column(type: "INTEGER", nullable: false), + StartTicks = table.Column(type: "INTEGER", nullable: false), + SegmentProviderId = table.Column(type: "TEXT", nullable: false), + }, + constraints: table => + { + table.PrimaryKey("PK_MediaSegments", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "MediaSegments"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs new file mode 100644 index 000000000..8dba31a67 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs @@ -0,0 +1,712 @@ +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20240928082930_MarkSegmentProviderIdNonNullable")] + partial class MarkSegmentProviderIdNonNullable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.8"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EndTicks") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartTicks") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.cs new file mode 100644 index 000000000..55b90a54d --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class MarkSegmentProviderIdNonNullable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "SegmentProviderId", + table: "MediaSegments", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "SegmentProviderId", + table: "MediaSegments", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241020103111_LibraryDbMigration.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241020103111_LibraryDbMigration.Designer.cs new file mode 100644 index 000000000..27745f601 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241020103111_LibraryDbMigration.Designer.cs @@ -0,0 +1,1607 @@ +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20241020103111_LibraryDbMigration")] + partial class LibraryDbMigration + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ParentItemId") + .HasColumnType("TEXT"); + + b.Property("BaseItemEntityId") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("BaseItemEntityId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("Filename") + .HasColumnType("TEXT"); + + b.Property("MimeType") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Album") + .HasColumnType("TEXT"); + + b.Property("AlbumArtists") + .HasColumnType("TEXT"); + + b.Property("Artists") + .HasColumnType("TEXT"); + + b.Property("Audio") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("TEXT"); + + b.Property("CleanName") + .HasColumnType("TEXT"); + + b.Property("CommunityRating") + .HasColumnType("REAL"); + + b.Property("CriticRating") + .HasColumnType("REAL"); + + b.Property("CustomRating") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastMediaAdded") + .HasColumnType("TEXT"); + + b.Property("DateLastRefreshed") + .HasColumnType("TEXT"); + + b.Property("DateLastSaved") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EpisodeTitle") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasColumnType("TEXT"); + + b.Property("ExternalSeriesId") + .HasColumnType("TEXT"); + + b.Property("ExternalServiceId") + .HasColumnType("TEXT"); + + b.Property("ExtraIds") + .HasColumnType("TEXT"); + + b.Property("ExtraType") + .HasColumnType("INTEGER"); + + b.Property("ForcedSortName") + .HasColumnType("TEXT"); + + b.Property("Genres") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IndexNumber") + .HasColumnType("INTEGER"); + + b.Property("InheritedParentalRatingValue") + .HasColumnType("INTEGER"); + + b.Property("IsFolder") + .HasColumnType("INTEGER"); + + b.Property("IsInMixedFolder") + .HasColumnType("INTEGER"); + + b.Property("IsLocked") + .HasColumnType("INTEGER"); + + b.Property("IsMovie") + .HasColumnType("INTEGER"); + + b.Property("IsRepeat") + .HasColumnType("INTEGER"); + + b.Property("IsSeries") + .HasColumnType("INTEGER"); + + b.Property("IsVirtualItem") + .HasColumnType("INTEGER"); + + b.Property("LUFS") + .HasColumnType("REAL"); + + b.Property("MediaType") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizationGain") + .HasColumnType("REAL"); + + b.Property("OfficialRating") + .HasColumnType("TEXT"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("ParentIndexNumber") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataCountryCode") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataLanguage") + .HasColumnType("TEXT"); + + b.Property("PremiereDate") + .HasColumnType("TEXT"); + + b.Property("PresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("PrimaryVersionId") + .HasColumnType("TEXT"); + + b.Property("ProductionLocations") + .HasColumnType("TEXT"); + + b.Property("ProductionYear") + .HasColumnType("INTEGER"); + + b.Property("RunTimeTicks") + .HasColumnType("INTEGER"); + + b.Property("SeasonId") + .HasColumnType("TEXT"); + + b.Property("SeasonName") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("TEXT"); + + b.Property("SeriesName") + .HasColumnType("TEXT"); + + b.Property("SeriesPresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("ShowId") + .HasColumnType("TEXT"); + + b.Property("Size") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("Studios") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Tags") + .HasColumnType("TEXT"); + + b.Property("TopParentId") + .HasColumnType("TEXT"); + + b.Property("TotalBitrate") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnratedType") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Blurhash") + .HasColumnType("BLOB"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("ImageType") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("ProviderValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ChapterIndex") + .HasColumnType("INTEGER"); + + b.Property("ImageDateModified") + .HasColumnType("TEXT"); + + b.Property("ImagePath") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("StartPositionTicks") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Property("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CleanValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue"); + + b.ToTable("ItemValues"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.Property("ItemValueId") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EndTicks") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartTicks") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("StreamIndex") + .HasColumnType("INTEGER"); + + b.Property("AspectRatio") + .HasColumnType("TEXT"); + + b.Property("AverageFrameRate") + .HasColumnType("REAL"); + + b.Property("BitDepth") + .HasColumnType("INTEGER"); + + b.Property("BitRate") + .HasColumnType("INTEGER"); + + b.Property("BlPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("ChannelLayout") + .HasColumnType("TEXT"); + + b.Property("Channels") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTimeBase") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ColorPrimaries") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ColorSpace") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ColorTransfer") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DvBlSignalCompatibilityId") + .HasColumnType("INTEGER"); + + b.Property("DvLevel") + .HasColumnType("INTEGER"); + + b.Property("DvProfile") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMajor") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMinor") + .HasColumnType("INTEGER"); + + b.Property("ElPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IsAnamorphic") + .HasColumnType("INTEGER"); + + b.Property("IsAvc") + .HasColumnType("INTEGER"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("IsExternal") + .HasColumnType("INTEGER"); + + b.Property("IsForced") + .HasColumnType("INTEGER"); + + b.Property("IsHearingImpaired") + .HasColumnType("INTEGER"); + + b.Property("IsInterlaced") + .HasColumnType("INTEGER"); + + b.Property("KeyFrames") + .HasColumnType("TEXT"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("REAL"); + + b.Property("NalLengthSize") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PixelFormat") + .HasColumnType("TEXT"); + + b.Property("Profile") + .HasColumnType("TEXT"); + + b.Property("RealFrameRate") + .HasColumnType("REAL"); + + b.Property("RefFrames") + .HasColumnType("INTEGER"); + + b.Property("Rotation") + .HasColumnType("INTEGER"); + + b.Property("RpuPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("SampleRate") + .HasColumnType("INTEGER"); + + b.Property("StreamType") + .HasColumnType("INTEGER"); + + b.Property("TimeBase") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PersonType") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("PeopleId") + .HasColumnType("TEXT"); + + b.Property("ListOrder") + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("AudioStreamIndex") + .HasColumnType("INTEGER"); + + b.Property("IsFavorite") + .HasColumnType("INTEGER"); + + b.Property("LastPlayedDate") + .HasColumnType("TEXT"); + + b.Property("Likes") + .HasColumnType("INTEGER"); + + b.Property("PlayCount") + .HasColumnType("INTEGER"); + + b.Property("PlaybackPositionTicks") + .HasColumnType("INTEGER"); + + b.Property("Played") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("REAL"); + + b.Property("SubtitleStreamIndex") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "UserId"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", null) + .WithMany("AncestorIds") + .HasForeignKey("BaseItemEntityId"); + + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") + .WithMany() + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Navigation("AncestorIds"); + + b.Navigation("Chapters"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241020103111_LibraryDbMigration.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241020103111_LibraryDbMigration.cs new file mode 100644 index 000000000..8cc7fb452 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241020103111_LibraryDbMigration.cs @@ -0,0 +1,639 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class LibraryDbMigration : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "BaseItems", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Type = table.Column(type: "TEXT", nullable: false), + Data = table.Column(type: "TEXT", nullable: true), + Path = table.Column(type: "TEXT", nullable: true), + StartDate = table.Column(type: "TEXT", nullable: false), + EndDate = table.Column(type: "TEXT", nullable: false), + ChannelId = table.Column(type: "TEXT", nullable: true), + IsMovie = table.Column(type: "INTEGER", nullable: false), + CommunityRating = table.Column(type: "REAL", nullable: true), + CustomRating = table.Column(type: "TEXT", nullable: true), + IndexNumber = table.Column(type: "INTEGER", nullable: true), + IsLocked = table.Column(type: "INTEGER", nullable: false), + Name = table.Column(type: "TEXT", nullable: true), + OfficialRating = table.Column(type: "TEXT", nullable: true), + MediaType = table.Column(type: "TEXT", nullable: true), + Overview = table.Column(type: "TEXT", nullable: true), + ParentIndexNumber = table.Column(type: "INTEGER", nullable: true), + PremiereDate = table.Column(type: "TEXT", nullable: true), + ProductionYear = table.Column(type: "INTEGER", nullable: true), + Genres = table.Column(type: "TEXT", nullable: true), + SortName = table.Column(type: "TEXT", nullable: true), + ForcedSortName = table.Column(type: "TEXT", nullable: true), + RunTimeTicks = table.Column(type: "INTEGER", nullable: true), + DateCreated = table.Column(type: "TEXT", nullable: true), + DateModified = table.Column(type: "TEXT", nullable: true), + IsSeries = table.Column(type: "INTEGER", nullable: false), + EpisodeTitle = table.Column(type: "TEXT", nullable: true), + IsRepeat = table.Column(type: "INTEGER", nullable: false), + PreferredMetadataLanguage = table.Column(type: "TEXT", nullable: true), + PreferredMetadataCountryCode = table.Column(type: "TEXT", nullable: true), + DateLastRefreshed = table.Column(type: "TEXT", nullable: true), + DateLastSaved = table.Column(type: "TEXT", nullable: true), + IsInMixedFolder = table.Column(type: "INTEGER", nullable: false), + Studios = table.Column(type: "TEXT", nullable: true), + ExternalServiceId = table.Column(type: "TEXT", nullable: true), + Tags = table.Column(type: "TEXT", nullable: true), + IsFolder = table.Column(type: "INTEGER", nullable: false), + InheritedParentalRatingValue = table.Column(type: "INTEGER", nullable: true), + UnratedType = table.Column(type: "TEXT", nullable: true), + CriticRating = table.Column(type: "REAL", nullable: true), + CleanName = table.Column(type: "TEXT", nullable: true), + PresentationUniqueKey = table.Column(type: "TEXT", nullable: true), + OriginalTitle = table.Column(type: "TEXT", nullable: true), + PrimaryVersionId = table.Column(type: "TEXT", nullable: true), + DateLastMediaAdded = table.Column(type: "TEXT", nullable: true), + Album = table.Column(type: "TEXT", nullable: true), + LUFS = table.Column(type: "REAL", nullable: true), + NormalizationGain = table.Column(type: "REAL", nullable: true), + IsVirtualItem = table.Column(type: "INTEGER", nullable: false), + SeriesName = table.Column(type: "TEXT", nullable: true), + SeasonName = table.Column(type: "TEXT", nullable: true), + ExternalSeriesId = table.Column(type: "TEXT", nullable: true), + Tagline = table.Column(type: "TEXT", nullable: true), + ProductionLocations = table.Column(type: "TEXT", nullable: true), + ExtraIds = table.Column(type: "TEXT", nullable: true), + TotalBitrate = table.Column(type: "INTEGER", nullable: true), + ExtraType = table.Column(type: "INTEGER", nullable: true), + Artists = table.Column(type: "TEXT", nullable: true), + AlbumArtists = table.Column(type: "TEXT", nullable: true), + ExternalId = table.Column(type: "TEXT", nullable: true), + SeriesPresentationUniqueKey = table.Column(type: "TEXT", nullable: true), + ShowId = table.Column(type: "TEXT", nullable: true), + OwnerId = table.Column(type: "TEXT", nullable: true), + Width = table.Column(type: "INTEGER", nullable: true), + Height = table.Column(type: "INTEGER", nullable: true), + Size = table.Column(type: "INTEGER", nullable: true), + Audio = table.Column(type: "INTEGER", nullable: true), + ParentId = table.Column(type: "TEXT", nullable: true), + TopParentId = table.Column(type: "TEXT", nullable: true), + SeasonId = table.Column(type: "TEXT", nullable: true), + SeriesId = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItems", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ItemValues", + columns: table => new + { + ItemValueId = table.Column(type: "TEXT", nullable: false), + Type = table.Column(type: "INTEGER", nullable: false), + Value = table.Column(type: "TEXT", nullable: false), + CleanValue = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ItemValues", x => x.ItemValueId); + }); + + migrationBuilder.CreateTable( + name: "Peoples", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", nullable: false), + PersonType = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Peoples", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AncestorIds", + columns: table => new + { + ParentItemId = table.Column(type: "TEXT", nullable: false), + ItemId = table.Column(type: "TEXT", nullable: false), + BaseItemEntityId = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AncestorIds", x => new { x.ItemId, x.ParentItemId }); + table.ForeignKey( + name: "FK_AncestorIds_BaseItems_BaseItemEntityId", + column: x => x.BaseItemEntityId, + principalTable: "BaseItems", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_AncestorIds_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AncestorIds_BaseItems_ParentItemId", + column: x => x.ParentItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AttachmentStreamInfos", + columns: table => new + { + ItemId = table.Column(type: "TEXT", nullable: false), + Index = table.Column(type: "INTEGER", nullable: false), + Codec = table.Column(type: "TEXT", nullable: false), + CodecTag = table.Column(type: "TEXT", nullable: true), + Comment = table.Column(type: "TEXT", nullable: true), + Filename = table.Column(type: "TEXT", nullable: true), + MimeType = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AttachmentStreamInfos", x => new { x.ItemId, x.Index }); + table.ForeignKey( + name: "FK_AttachmentStreamInfos_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BaseItemImageInfos", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Path = table.Column(type: "TEXT", nullable: false), + DateModified = table.Column(type: "TEXT", nullable: false), + ImageType = table.Column(type: "INTEGER", nullable: false), + Width = table.Column(type: "INTEGER", nullable: false), + Height = table.Column(type: "INTEGER", nullable: false), + Blurhash = table.Column(type: "BLOB", nullable: true), + ItemId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItemImageInfos", x => x.Id); + table.ForeignKey( + name: "FK_BaseItemImageInfos_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BaseItemMetadataFields", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false), + ItemId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItemMetadataFields", x => new { x.Id, x.ItemId }); + table.ForeignKey( + name: "FK_BaseItemMetadataFields_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BaseItemProviders", + columns: table => new + { + ItemId = table.Column(type: "TEXT", nullable: false), + ProviderId = table.Column(type: "TEXT", nullable: false), + ProviderValue = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItemProviders", x => new { x.ItemId, x.ProviderId }); + table.ForeignKey( + name: "FK_BaseItemProviders_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BaseItemTrailerTypes", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false), + ItemId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItemTrailerTypes", x => new { x.Id, x.ItemId }); + table.ForeignKey( + name: "FK_BaseItemTrailerTypes_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Chapters", + columns: table => new + { + ItemId = table.Column(type: "TEXT", nullable: false), + ChapterIndex = table.Column(type: "INTEGER", nullable: false), + StartPositionTicks = table.Column(type: "INTEGER", nullable: false), + Name = table.Column(type: "TEXT", nullable: true), + ImagePath = table.Column(type: "TEXT", nullable: true), + ImageDateModified = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Chapters", x => new { x.ItemId, x.ChapterIndex }); + table.ForeignKey( + name: "FK_Chapters_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "MediaStreamInfos", + columns: table => new + { + ItemId = table.Column(type: "TEXT", nullable: false), + StreamIndex = table.Column(type: "INTEGER", nullable: false), + StreamType = table.Column(type: "INTEGER", nullable: true), + Codec = table.Column(type: "TEXT", nullable: true), + Language = table.Column(type: "TEXT", nullable: true), + ChannelLayout = table.Column(type: "TEXT", nullable: true), + Profile = table.Column(type: "TEXT", nullable: true), + AspectRatio = table.Column(type: "TEXT", nullable: true), + Path = table.Column(type: "TEXT", nullable: true), + IsInterlaced = table.Column(type: "INTEGER", nullable: false), + BitRate = table.Column(type: "INTEGER", nullable: false), + Channels = table.Column(type: "INTEGER", nullable: false), + SampleRate = table.Column(type: "INTEGER", nullable: false), + IsDefault = table.Column(type: "INTEGER", nullable: false), + IsForced = table.Column(type: "INTEGER", nullable: false), + IsExternal = table.Column(type: "INTEGER", nullable: false), + Height = table.Column(type: "INTEGER", nullable: false), + Width = table.Column(type: "INTEGER", nullable: false), + AverageFrameRate = table.Column(type: "REAL", nullable: false), + RealFrameRate = table.Column(type: "REAL", nullable: false), + Level = table.Column(type: "REAL", nullable: false), + PixelFormat = table.Column(type: "TEXT", nullable: true), + BitDepth = table.Column(type: "INTEGER", nullable: false), + IsAnamorphic = table.Column(type: "INTEGER", nullable: false), + RefFrames = table.Column(type: "INTEGER", nullable: false), + CodecTag = table.Column(type: "TEXT", nullable: false), + Comment = table.Column(type: "TEXT", nullable: false), + NalLengthSize = table.Column(type: "TEXT", nullable: false), + IsAvc = table.Column(type: "INTEGER", nullable: false), + Title = table.Column(type: "TEXT", nullable: false), + TimeBase = table.Column(type: "TEXT", nullable: false), + CodecTimeBase = table.Column(type: "TEXT", nullable: false), + ColorPrimaries = table.Column(type: "TEXT", nullable: false), + ColorSpace = table.Column(type: "TEXT", nullable: false), + ColorTransfer = table.Column(type: "TEXT", nullable: false), + DvVersionMajor = table.Column(type: "INTEGER", nullable: false), + DvVersionMinor = table.Column(type: "INTEGER", nullable: false), + DvProfile = table.Column(type: "INTEGER", nullable: false), + DvLevel = table.Column(type: "INTEGER", nullable: false), + RpuPresentFlag = table.Column(type: "INTEGER", nullable: false), + ElPresentFlag = table.Column(type: "INTEGER", nullable: false), + BlPresentFlag = table.Column(type: "INTEGER", nullable: false), + DvBlSignalCompatibilityId = table.Column(type: "INTEGER", nullable: false), + IsHearingImpaired = table.Column(type: "INTEGER", nullable: false), + Rotation = table.Column(type: "INTEGER", nullable: false), + KeyFrames = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_MediaStreamInfos", x => new { x.ItemId, x.StreamIndex }); + table.ForeignKey( + name: "FK_MediaStreamInfos_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "UserData", + columns: table => new + { + ItemId = table.Column(type: "TEXT", nullable: false), + UserId = table.Column(type: "TEXT", nullable: false), + Rating = table.Column(type: "REAL", nullable: true), + PlaybackPositionTicks = table.Column(type: "INTEGER", nullable: false), + PlayCount = table.Column(type: "INTEGER", nullable: false), + IsFavorite = table.Column(type: "INTEGER", nullable: false), + LastPlayedDate = table.Column(type: "TEXT", nullable: true), + Played = table.Column(type: "INTEGER", nullable: false), + AudioStreamIndex = table.Column(type: "INTEGER", nullable: true), + SubtitleStreamIndex = table.Column(type: "INTEGER", nullable: true), + Likes = table.Column(type: "INTEGER", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_UserData", x => new { x.ItemId, x.UserId }); + table.ForeignKey( + name: "FK_UserData_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_UserData_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ItemValuesMap", + columns: table => new + { + ItemId = table.Column(type: "TEXT", nullable: false), + ItemValueId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ItemValuesMap", x => new { x.ItemValueId, x.ItemId }); + table.ForeignKey( + name: "FK_ItemValuesMap_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ItemValuesMap_ItemValues_ItemValueId", + column: x => x.ItemValueId, + principalTable: "ItemValues", + principalColumn: "ItemValueId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "PeopleBaseItemMap", + columns: table => new + { + ItemId = table.Column(type: "TEXT", nullable: false), + PeopleId = table.Column(type: "TEXT", nullable: false), + SortOrder = table.Column(type: "INTEGER", nullable: true), + ListOrder = table.Column(type: "INTEGER", nullable: true), + Role = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_PeopleBaseItemMap", x => new { x.ItemId, x.PeopleId }); + table.ForeignKey( + name: "FK_PeopleBaseItemMap_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_PeopleBaseItemMap_Peoples_PeopleId", + column: x => x.PeopleId, + principalTable: "Peoples", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AncestorIds_BaseItemEntityId", + table: "AncestorIds", + column: "BaseItemEntityId"); + + migrationBuilder.CreateIndex( + name: "IX_AncestorIds_ParentItemId", + table: "AncestorIds", + column: "ParentItemId"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItemImageInfos_ItemId", + table: "BaseItemImageInfos", + column: "ItemId"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItemMetadataFields_ItemId", + table: "BaseItemMetadataFields", + column: "ItemId"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItemProviders_ProviderId_ProviderValue_ItemId", + table: "BaseItemProviders", + columns: new[] { "ProviderId", "ProviderValue", "ItemId" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Id_Type_IsFolder_IsVirtualItem", + table: "BaseItems", + columns: new[] { "Id", "Type", "IsFolder", "IsVirtualItem" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_IsFolder_TopParentId_IsVirtualItem_PresentationUniqueKey_DateCreated", + table: "BaseItems", + columns: new[] { "IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_MediaType_TopParentId_IsVirtualItem_PresentationUniqueKey", + table: "BaseItems", + columns: new[] { "MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_ParentId", + table: "BaseItems", + column: "ParentId"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Path", + table: "BaseItems", + column: "Path"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_PresentationUniqueKey", + table: "BaseItems", + column: "PresentationUniqueKey"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_TopParentId_Id", + table: "BaseItems", + columns: new[] { "TopParentId", "Id" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_SeriesPresentationUniqueKey_IsFolder_IsVirtualItem", + table: "BaseItems", + columns: new[] { "Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_SeriesPresentationUniqueKey_PresentationUniqueKey_SortName", + table: "BaseItems", + columns: new[] { "Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_TopParentId_Id", + table: "BaseItems", + columns: new[] { "Type", "TopParentId", "Id" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_TopParentId_IsVirtualItem_PresentationUniqueKey_DateCreated", + table: "BaseItems", + columns: new[] { "Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_TopParentId_PresentationUniqueKey", + table: "BaseItems", + columns: new[] { "Type", "TopParentId", "PresentationUniqueKey" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_TopParentId_StartDate", + table: "BaseItems", + columns: new[] { "Type", "TopParentId", "StartDate" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItemTrailerTypes_ItemId", + table: "BaseItemTrailerTypes", + column: "ItemId"); + + migrationBuilder.CreateIndex( + name: "IX_ItemValues_Type_CleanValue", + table: "ItemValues", + columns: new[] { "Type", "CleanValue" }); + + migrationBuilder.CreateIndex( + name: "IX_ItemValuesMap_ItemId", + table: "ItemValuesMap", + column: "ItemId"); + + migrationBuilder.CreateIndex( + name: "IX_MediaStreamInfos_StreamIndex", + table: "MediaStreamInfos", + column: "StreamIndex"); + + migrationBuilder.CreateIndex( + name: "IX_MediaStreamInfos_StreamIndex_StreamType", + table: "MediaStreamInfos", + columns: new[] { "StreamIndex", "StreamType" }); + + migrationBuilder.CreateIndex( + name: "IX_MediaStreamInfos_StreamIndex_StreamType_Language", + table: "MediaStreamInfos", + columns: new[] { "StreamIndex", "StreamType", "Language" }); + + migrationBuilder.CreateIndex( + name: "IX_MediaStreamInfos_StreamType", + table: "MediaStreamInfos", + column: "StreamType"); + + migrationBuilder.CreateIndex( + name: "IX_PeopleBaseItemMap_ItemId_ListOrder", + table: "PeopleBaseItemMap", + columns: new[] { "ItemId", "ListOrder" }); + + migrationBuilder.CreateIndex( + name: "IX_PeopleBaseItemMap_ItemId_SortOrder", + table: "PeopleBaseItemMap", + columns: new[] { "ItemId", "SortOrder" }); + + migrationBuilder.CreateIndex( + name: "IX_PeopleBaseItemMap_PeopleId", + table: "PeopleBaseItemMap", + column: "PeopleId"); + + migrationBuilder.CreateIndex( + name: "IX_Peoples_Name", + table: "Peoples", + column: "Name"); + + migrationBuilder.CreateIndex( + name: "IX_UserData_ItemId_UserId_IsFavorite", + table: "UserData", + columns: new[] { "ItemId", "UserId", "IsFavorite" }); + + migrationBuilder.CreateIndex( + name: "IX_UserData_ItemId_UserId_LastPlayedDate", + table: "UserData", + columns: new[] { "ItemId", "UserId", "LastPlayedDate" }); + + migrationBuilder.CreateIndex( + name: "IX_UserData_ItemId_UserId_PlaybackPositionTicks", + table: "UserData", + columns: new[] { "ItemId", "UserId", "PlaybackPositionTicks" }); + + migrationBuilder.CreateIndex( + name: "IX_UserData_ItemId_UserId_Played", + table: "UserData", + columns: new[] { "ItemId", "UserId", "Played" }); + + migrationBuilder.CreateIndex( + name: "IX_UserData_UserId", + table: "UserData", + column: "UserId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AncestorIds"); + + migrationBuilder.DropTable( + name: "AttachmentStreamInfos"); + + migrationBuilder.DropTable( + name: "BaseItemImageInfos"); + + migrationBuilder.DropTable( + name: "BaseItemMetadataFields"); + + migrationBuilder.DropTable( + name: "BaseItemProviders"); + + migrationBuilder.DropTable( + name: "BaseItemTrailerTypes"); + + migrationBuilder.DropTable( + name: "Chapters"); + + migrationBuilder.DropTable( + name: "ItemValuesMap"); + + migrationBuilder.DropTable( + name: "MediaStreamInfos"); + + migrationBuilder.DropTable( + name: "PeopleBaseItemMap"); + + migrationBuilder.DropTable( + name: "UserData"); + + migrationBuilder.DropTable( + name: "ItemValues"); + + migrationBuilder.DropTable( + name: "Peoples"); + + migrationBuilder.DropTable( + name: "BaseItems"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111131257_AddedCustomDataKey.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111131257_AddedCustomDataKey.Designer.cs new file mode 100644 index 000000000..1fbf21492 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111131257_AddedCustomDataKey.Designer.cs @@ -0,0 +1,1610 @@ +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20241111131257_AddedCustomDataKey")] + partial class AddedCustomDataKey + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ParentItemId") + .HasColumnType("TEXT"); + + b.Property("BaseItemEntityId") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("BaseItemEntityId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("Filename") + .HasColumnType("TEXT"); + + b.Property("MimeType") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Album") + .HasColumnType("TEXT"); + + b.Property("AlbumArtists") + .HasColumnType("TEXT"); + + b.Property("Artists") + .HasColumnType("TEXT"); + + b.Property("Audio") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("TEXT"); + + b.Property("CleanName") + .HasColumnType("TEXT"); + + b.Property("CommunityRating") + .HasColumnType("REAL"); + + b.Property("CriticRating") + .HasColumnType("REAL"); + + b.Property("CustomRating") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastMediaAdded") + .HasColumnType("TEXT"); + + b.Property("DateLastRefreshed") + .HasColumnType("TEXT"); + + b.Property("DateLastSaved") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EpisodeTitle") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasColumnType("TEXT"); + + b.Property("ExternalSeriesId") + .HasColumnType("TEXT"); + + b.Property("ExternalServiceId") + .HasColumnType("TEXT"); + + b.Property("ExtraIds") + .HasColumnType("TEXT"); + + b.Property("ExtraType") + .HasColumnType("INTEGER"); + + b.Property("ForcedSortName") + .HasColumnType("TEXT"); + + b.Property("Genres") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IndexNumber") + .HasColumnType("INTEGER"); + + b.Property("InheritedParentalRatingValue") + .HasColumnType("INTEGER"); + + b.Property("IsFolder") + .HasColumnType("INTEGER"); + + b.Property("IsInMixedFolder") + .HasColumnType("INTEGER"); + + b.Property("IsLocked") + .HasColumnType("INTEGER"); + + b.Property("IsMovie") + .HasColumnType("INTEGER"); + + b.Property("IsRepeat") + .HasColumnType("INTEGER"); + + b.Property("IsSeries") + .HasColumnType("INTEGER"); + + b.Property("IsVirtualItem") + .HasColumnType("INTEGER"); + + b.Property("LUFS") + .HasColumnType("REAL"); + + b.Property("MediaType") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizationGain") + .HasColumnType("REAL"); + + b.Property("OfficialRating") + .HasColumnType("TEXT"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("ParentIndexNumber") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataCountryCode") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataLanguage") + .HasColumnType("TEXT"); + + b.Property("PremiereDate") + .HasColumnType("TEXT"); + + b.Property("PresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("PrimaryVersionId") + .HasColumnType("TEXT"); + + b.Property("ProductionLocations") + .HasColumnType("TEXT"); + + b.Property("ProductionYear") + .HasColumnType("INTEGER"); + + b.Property("RunTimeTicks") + .HasColumnType("INTEGER"); + + b.Property("SeasonId") + .HasColumnType("TEXT"); + + b.Property("SeasonName") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("TEXT"); + + b.Property("SeriesName") + .HasColumnType("TEXT"); + + b.Property("SeriesPresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("ShowId") + .HasColumnType("TEXT"); + + b.Property("Size") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("Studios") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Tags") + .HasColumnType("TEXT"); + + b.Property("TopParentId") + .HasColumnType("TEXT"); + + b.Property("TotalBitrate") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnratedType") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Blurhash") + .HasColumnType("BLOB"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("ImageType") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("ProviderValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ChapterIndex") + .HasColumnType("INTEGER"); + + b.Property("ImageDateModified") + .HasColumnType("TEXT"); + + b.Property("ImagePath") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("StartPositionTicks") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Property("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CleanValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue"); + + b.ToTable("ItemValues"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.Property("ItemValueId") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EndTicks") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartTicks") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("StreamIndex") + .HasColumnType("INTEGER"); + + b.Property("AspectRatio") + .HasColumnType("TEXT"); + + b.Property("AverageFrameRate") + .HasColumnType("REAL"); + + b.Property("BitDepth") + .HasColumnType("INTEGER"); + + b.Property("BitRate") + .HasColumnType("INTEGER"); + + b.Property("BlPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("ChannelLayout") + .HasColumnType("TEXT"); + + b.Property("Channels") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTimeBase") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ColorPrimaries") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ColorSpace") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ColorTransfer") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DvBlSignalCompatibilityId") + .HasColumnType("INTEGER"); + + b.Property("DvLevel") + .HasColumnType("INTEGER"); + + b.Property("DvProfile") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMajor") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMinor") + .HasColumnType("INTEGER"); + + b.Property("ElPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IsAnamorphic") + .HasColumnType("INTEGER"); + + b.Property("IsAvc") + .HasColumnType("INTEGER"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("IsExternal") + .HasColumnType("INTEGER"); + + b.Property("IsForced") + .HasColumnType("INTEGER"); + + b.Property("IsHearingImpaired") + .HasColumnType("INTEGER"); + + b.Property("IsInterlaced") + .HasColumnType("INTEGER"); + + b.Property("KeyFrames") + .HasColumnType("TEXT"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("REAL"); + + b.Property("NalLengthSize") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PixelFormat") + .HasColumnType("TEXT"); + + b.Property("Profile") + .HasColumnType("TEXT"); + + b.Property("RealFrameRate") + .HasColumnType("REAL"); + + b.Property("RefFrames") + .HasColumnType("INTEGER"); + + b.Property("Rotation") + .HasColumnType("INTEGER"); + + b.Property("RpuPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("SampleRate") + .HasColumnType("INTEGER"); + + b.Property("StreamType") + .HasColumnType("INTEGER"); + + b.Property("TimeBase") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PersonType") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("PeopleId") + .HasColumnType("TEXT"); + + b.Property("ListOrder") + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("AudioStreamIndex") + .HasColumnType("INTEGER"); + + b.Property("CustomDataKey") + .HasColumnType("TEXT"); + + b.Property("IsFavorite") + .HasColumnType("INTEGER"); + + b.Property("LastPlayedDate") + .HasColumnType("TEXT"); + + b.Property("Likes") + .HasColumnType("INTEGER"); + + b.Property("PlayCount") + .HasColumnType("INTEGER"); + + b.Property("PlaybackPositionTicks") + .HasColumnType("INTEGER"); + + b.Property("Played") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("REAL"); + + b.Property("SubtitleStreamIndex") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "UserId"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", null) + .WithMany("AncestorIds") + .HasForeignKey("BaseItemEntityId"); + + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") + .WithMany() + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Navigation("AncestorIds"); + + b.Navigation("Chapters"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111131257_AddedCustomDataKey.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111131257_AddedCustomDataKey.cs new file mode 100644 index 000000000..ac78019ed --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111131257_AddedCustomDataKey.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class AddedCustomDataKey : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CustomDataKey", + table: "UserData", + type: "TEXT", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CustomDataKey", + table: "UserData"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs new file mode 100644 index 000000000..bac6fd5b5 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs @@ -0,0 +1,1610 @@ +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20241111135439_AddedCustomDataKeyKey")] + partial class AddedCustomDataKeyKey + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ParentItemId") + .HasColumnType("TEXT"); + + b.Property("BaseItemEntityId") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("BaseItemEntityId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("Filename") + .HasColumnType("TEXT"); + + b.Property("MimeType") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Album") + .HasColumnType("TEXT"); + + b.Property("AlbumArtists") + .HasColumnType("TEXT"); + + b.Property("Artists") + .HasColumnType("TEXT"); + + b.Property("Audio") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("TEXT"); + + b.Property("CleanName") + .HasColumnType("TEXT"); + + b.Property("CommunityRating") + .HasColumnType("REAL"); + + b.Property("CriticRating") + .HasColumnType("REAL"); + + b.Property("CustomRating") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastMediaAdded") + .HasColumnType("TEXT"); + + b.Property("DateLastRefreshed") + .HasColumnType("TEXT"); + + b.Property("DateLastSaved") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EpisodeTitle") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasColumnType("TEXT"); + + b.Property("ExternalSeriesId") + .HasColumnType("TEXT"); + + b.Property("ExternalServiceId") + .HasColumnType("TEXT"); + + b.Property("ExtraIds") + .HasColumnType("TEXT"); + + b.Property("ExtraType") + .HasColumnType("INTEGER"); + + b.Property("ForcedSortName") + .HasColumnType("TEXT"); + + b.Property("Genres") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IndexNumber") + .HasColumnType("INTEGER"); + + b.Property("InheritedParentalRatingValue") + .HasColumnType("INTEGER"); + + b.Property("IsFolder") + .HasColumnType("INTEGER"); + + b.Property("IsInMixedFolder") + .HasColumnType("INTEGER"); + + b.Property("IsLocked") + .HasColumnType("INTEGER"); + + b.Property("IsMovie") + .HasColumnType("INTEGER"); + + b.Property("IsRepeat") + .HasColumnType("INTEGER"); + + b.Property("IsSeries") + .HasColumnType("INTEGER"); + + b.Property("IsVirtualItem") + .HasColumnType("INTEGER"); + + b.Property("LUFS") + .HasColumnType("REAL"); + + b.Property("MediaType") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizationGain") + .HasColumnType("REAL"); + + b.Property("OfficialRating") + .HasColumnType("TEXT"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("ParentIndexNumber") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataCountryCode") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataLanguage") + .HasColumnType("TEXT"); + + b.Property("PremiereDate") + .HasColumnType("TEXT"); + + b.Property("PresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("PrimaryVersionId") + .HasColumnType("TEXT"); + + b.Property("ProductionLocations") + .HasColumnType("TEXT"); + + b.Property("ProductionYear") + .HasColumnType("INTEGER"); + + b.Property("RunTimeTicks") + .HasColumnType("INTEGER"); + + b.Property("SeasonId") + .HasColumnType("TEXT"); + + b.Property("SeasonName") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("TEXT"); + + b.Property("SeriesName") + .HasColumnType("TEXT"); + + b.Property("SeriesPresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("ShowId") + .HasColumnType("TEXT"); + + b.Property("Size") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("Studios") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Tags") + .HasColumnType("TEXT"); + + b.Property("TopParentId") + .HasColumnType("TEXT"); + + b.Property("TotalBitrate") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnratedType") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Blurhash") + .HasColumnType("BLOB"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("ImageType") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("ProviderValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ChapterIndex") + .HasColumnType("INTEGER"); + + b.Property("ImageDateModified") + .HasColumnType("TEXT"); + + b.Property("ImagePath") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("StartPositionTicks") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Property("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CleanValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue"); + + b.ToTable("ItemValues"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.Property("ItemValueId") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EndTicks") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartTicks") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("StreamIndex") + .HasColumnType("INTEGER"); + + b.Property("AspectRatio") + .HasColumnType("TEXT"); + + b.Property("AverageFrameRate") + .HasColumnType("REAL"); + + b.Property("BitDepth") + .HasColumnType("INTEGER"); + + b.Property("BitRate") + .HasColumnType("INTEGER"); + + b.Property("BlPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("ChannelLayout") + .HasColumnType("TEXT"); + + b.Property("Channels") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTimeBase") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ColorPrimaries") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ColorSpace") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ColorTransfer") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DvBlSignalCompatibilityId") + .HasColumnType("INTEGER"); + + b.Property("DvLevel") + .HasColumnType("INTEGER"); + + b.Property("DvProfile") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMajor") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMinor") + .HasColumnType("INTEGER"); + + b.Property("ElPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IsAnamorphic") + .HasColumnType("INTEGER"); + + b.Property("IsAvc") + .HasColumnType("INTEGER"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("IsExternal") + .HasColumnType("INTEGER"); + + b.Property("IsForced") + .HasColumnType("INTEGER"); + + b.Property("IsHearingImpaired") + .HasColumnType("INTEGER"); + + b.Property("IsInterlaced") + .HasColumnType("INTEGER"); + + b.Property("KeyFrames") + .HasColumnType("TEXT"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("REAL"); + + b.Property("NalLengthSize") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PixelFormat") + .HasColumnType("TEXT"); + + b.Property("Profile") + .HasColumnType("TEXT"); + + b.Property("RealFrameRate") + .HasColumnType("REAL"); + + b.Property("RefFrames") + .HasColumnType("INTEGER"); + + b.Property("Rotation") + .HasColumnType("INTEGER"); + + b.Property("RpuPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("SampleRate") + .HasColumnType("INTEGER"); + + b.Property("StreamType") + .HasColumnType("INTEGER"); + + b.Property("TimeBase") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PersonType") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("PeopleId") + .HasColumnType("TEXT"); + + b.Property("ListOrder") + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("CustomDataKey") + .HasColumnType("TEXT"); + + b.Property("AudioStreamIndex") + .HasColumnType("INTEGER"); + + b.Property("IsFavorite") + .HasColumnType("INTEGER"); + + b.Property("LastPlayedDate") + .HasColumnType("TEXT"); + + b.Property("Likes") + .HasColumnType("INTEGER"); + + b.Property("PlayCount") + .HasColumnType("INTEGER"); + + b.Property("PlaybackPositionTicks") + .HasColumnType("INTEGER"); + + b.Property("Played") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("REAL"); + + b.Property("SubtitleStreamIndex") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "UserId", "CustomDataKey"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", null) + .WithMany("AncestorIds") + .HasForeignKey("BaseItemEntityId"); + + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") + .WithMany() + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Navigation("AncestorIds"); + + b.Navigation("Chapters"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111135439_AddedCustomDataKeyKey.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111135439_AddedCustomDataKeyKey.cs new file mode 100644 index 000000000..4558d7c49 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241111135439_AddedCustomDataKeyKey.cs @@ -0,0 +1,54 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class AddedCustomDataKeyKey : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropPrimaryKey( + name: "PK_UserData", + table: "UserData"); + + migrationBuilder.AlterColumn( + name: "CustomDataKey", + table: "UserData", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AddPrimaryKey( + name: "PK_UserData", + table: "UserData", + columns: new[] { "ItemId", "UserId", "CustomDataKey" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropPrimaryKey( + name: "PK_UserData", + table: "UserData"); + + migrationBuilder.AlterColumn( + name: "CustomDataKey", + table: "UserData", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AddPrimaryKey( + name: "PK_UserData", + table: "UserData", + columns: new[] { "ItemId", "UserId" }); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs new file mode 100644 index 000000000..ad622d44c --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs @@ -0,0 +1,1603 @@ +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20241112152323_FixAncestorIdConfig")] + partial class FixAncestorIdConfig + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ParentItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("Filename") + .HasColumnType("TEXT"); + + b.Property("MimeType") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Album") + .HasColumnType("TEXT"); + + b.Property("AlbumArtists") + .HasColumnType("TEXT"); + + b.Property("Artists") + .HasColumnType("TEXT"); + + b.Property("Audio") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("TEXT"); + + b.Property("CleanName") + .HasColumnType("TEXT"); + + b.Property("CommunityRating") + .HasColumnType("REAL"); + + b.Property("CriticRating") + .HasColumnType("REAL"); + + b.Property("CustomRating") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastMediaAdded") + .HasColumnType("TEXT"); + + b.Property("DateLastRefreshed") + .HasColumnType("TEXT"); + + b.Property("DateLastSaved") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EpisodeTitle") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasColumnType("TEXT"); + + b.Property("ExternalSeriesId") + .HasColumnType("TEXT"); + + b.Property("ExternalServiceId") + .HasColumnType("TEXT"); + + b.Property("ExtraIds") + .HasColumnType("TEXT"); + + b.Property("ExtraType") + .HasColumnType("INTEGER"); + + b.Property("ForcedSortName") + .HasColumnType("TEXT"); + + b.Property("Genres") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IndexNumber") + .HasColumnType("INTEGER"); + + b.Property("InheritedParentalRatingValue") + .HasColumnType("INTEGER"); + + b.Property("IsFolder") + .HasColumnType("INTEGER"); + + b.Property("IsInMixedFolder") + .HasColumnType("INTEGER"); + + b.Property("IsLocked") + .HasColumnType("INTEGER"); + + b.Property("IsMovie") + .HasColumnType("INTEGER"); + + b.Property("IsRepeat") + .HasColumnType("INTEGER"); + + b.Property("IsSeries") + .HasColumnType("INTEGER"); + + b.Property("IsVirtualItem") + .HasColumnType("INTEGER"); + + b.Property("LUFS") + .HasColumnType("REAL"); + + b.Property("MediaType") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizationGain") + .HasColumnType("REAL"); + + b.Property("OfficialRating") + .HasColumnType("TEXT"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("ParentIndexNumber") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataCountryCode") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataLanguage") + .HasColumnType("TEXT"); + + b.Property("PremiereDate") + .HasColumnType("TEXT"); + + b.Property("PresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("PrimaryVersionId") + .HasColumnType("TEXT"); + + b.Property("ProductionLocations") + .HasColumnType("TEXT"); + + b.Property("ProductionYear") + .HasColumnType("INTEGER"); + + b.Property("RunTimeTicks") + .HasColumnType("INTEGER"); + + b.Property("SeasonId") + .HasColumnType("TEXT"); + + b.Property("SeasonName") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("TEXT"); + + b.Property("SeriesName") + .HasColumnType("TEXT"); + + b.Property("SeriesPresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("ShowId") + .HasColumnType("TEXT"); + + b.Property("Size") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("Studios") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Tags") + .HasColumnType("TEXT"); + + b.Property("TopParentId") + .HasColumnType("TEXT"); + + b.Property("TotalBitrate") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnratedType") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Blurhash") + .HasColumnType("BLOB"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("ImageType") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("ProviderValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ChapterIndex") + .HasColumnType("INTEGER"); + + b.Property("ImageDateModified") + .HasColumnType("TEXT"); + + b.Property("ImagePath") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("StartPositionTicks") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Property("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CleanValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue"); + + b.ToTable("ItemValues"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.Property("ItemValueId") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EndTicks") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartTicks") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("StreamIndex") + .HasColumnType("INTEGER"); + + b.Property("AspectRatio") + .HasColumnType("TEXT"); + + b.Property("AverageFrameRate") + .HasColumnType("REAL"); + + b.Property("BitDepth") + .HasColumnType("INTEGER"); + + b.Property("BitRate") + .HasColumnType("INTEGER"); + + b.Property("BlPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("ChannelLayout") + .HasColumnType("TEXT"); + + b.Property("Channels") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTimeBase") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ColorPrimaries") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ColorSpace") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ColorTransfer") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DvBlSignalCompatibilityId") + .HasColumnType("INTEGER"); + + b.Property("DvLevel") + .HasColumnType("INTEGER"); + + b.Property("DvProfile") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMajor") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMinor") + .HasColumnType("INTEGER"); + + b.Property("ElPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IsAnamorphic") + .HasColumnType("INTEGER"); + + b.Property("IsAvc") + .HasColumnType("INTEGER"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("IsExternal") + .HasColumnType("INTEGER"); + + b.Property("IsForced") + .HasColumnType("INTEGER"); + + b.Property("IsHearingImpaired") + .HasColumnType("INTEGER"); + + b.Property("IsInterlaced") + .HasColumnType("INTEGER"); + + b.Property("KeyFrames") + .HasColumnType("TEXT"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("REAL"); + + b.Property("NalLengthSize") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PixelFormat") + .HasColumnType("TEXT"); + + b.Property("Profile") + .HasColumnType("TEXT"); + + b.Property("RealFrameRate") + .HasColumnType("REAL"); + + b.Property("RefFrames") + .HasColumnType("INTEGER"); + + b.Property("Rotation") + .HasColumnType("INTEGER"); + + b.Property("RpuPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("SampleRate") + .HasColumnType("INTEGER"); + + b.Property("StreamType") + .HasColumnType("INTEGER"); + + b.Property("TimeBase") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PersonType") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("PeopleId") + .HasColumnType("TEXT"); + + b.Property("ListOrder") + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("CustomDataKey") + .HasColumnType("TEXT"); + + b.Property("AudioStreamIndex") + .HasColumnType("INTEGER"); + + b.Property("IsFavorite") + .HasColumnType("INTEGER"); + + b.Property("LastPlayedDate") + .HasColumnType("TEXT"); + + b.Property("Likes") + .HasColumnType("INTEGER"); + + b.Property("PlayCount") + .HasColumnType("INTEGER"); + + b.Property("PlaybackPositionTicks") + .HasColumnType("INTEGER"); + + b.Property("Played") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("REAL"); + + b.Property("SubtitleStreamIndex") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "UserId", "CustomDataKey"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Children") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") + .WithMany("ParentAncestors") + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Navigation("Chapters"); + + b.Navigation("Children"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("ParentAncestors"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112152323_FixAncestorIdConfig.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112152323_FixAncestorIdConfig.cs new file mode 100644 index 000000000..70e81f367 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112152323_FixAncestorIdConfig.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class FixAncestorIdConfig : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_AncestorIds_BaseItems_BaseItemEntityId", + table: "AncestorIds"); + + migrationBuilder.DropIndex( + name: "IX_AncestorIds_BaseItemEntityId", + table: "AncestorIds"); + + migrationBuilder.DropColumn( + name: "BaseItemEntityId", + table: "AncestorIds"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "BaseItemEntityId", + table: "AncestorIds", + type: "TEXT", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_AncestorIds_BaseItemEntityId", + table: "AncestorIds", + column: "BaseItemEntityId"); + + migrationBuilder.AddForeignKey( + name: "FK_AncestorIds_BaseItems_BaseItemEntityId", + table: "AncestorIds", + column: "BaseItemEntityId", + principalTable: "BaseItems", + principalColumn: "Id"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112232041_fixMediaStreams.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112232041_fixMediaStreams.Designer.cs new file mode 100644 index 000000000..dc4c8212b --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112232041_fixMediaStreams.Designer.cs @@ -0,0 +1,1600 @@ +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20241112232041_FixMediaStreams")] + partial class FixMediaStreams + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ParentItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("Filename") + .HasColumnType("TEXT"); + + b.Property("MimeType") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Album") + .HasColumnType("TEXT"); + + b.Property("AlbumArtists") + .HasColumnType("TEXT"); + + b.Property("Artists") + .HasColumnType("TEXT"); + + b.Property("Audio") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("TEXT"); + + b.Property("CleanName") + .HasColumnType("TEXT"); + + b.Property("CommunityRating") + .HasColumnType("REAL"); + + b.Property("CriticRating") + .HasColumnType("REAL"); + + b.Property("CustomRating") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastMediaAdded") + .HasColumnType("TEXT"); + + b.Property("DateLastRefreshed") + .HasColumnType("TEXT"); + + b.Property("DateLastSaved") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EpisodeTitle") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasColumnType("TEXT"); + + b.Property("ExternalSeriesId") + .HasColumnType("TEXT"); + + b.Property("ExternalServiceId") + .HasColumnType("TEXT"); + + b.Property("ExtraIds") + .HasColumnType("TEXT"); + + b.Property("ExtraType") + .HasColumnType("INTEGER"); + + b.Property("ForcedSortName") + .HasColumnType("TEXT"); + + b.Property("Genres") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IndexNumber") + .HasColumnType("INTEGER"); + + b.Property("InheritedParentalRatingValue") + .HasColumnType("INTEGER"); + + b.Property("IsFolder") + .HasColumnType("INTEGER"); + + b.Property("IsInMixedFolder") + .HasColumnType("INTEGER"); + + b.Property("IsLocked") + .HasColumnType("INTEGER"); + + b.Property("IsMovie") + .HasColumnType("INTEGER"); + + b.Property("IsRepeat") + .HasColumnType("INTEGER"); + + b.Property("IsSeries") + .HasColumnType("INTEGER"); + + b.Property("IsVirtualItem") + .HasColumnType("INTEGER"); + + b.Property("LUFS") + .HasColumnType("REAL"); + + b.Property("MediaType") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizationGain") + .HasColumnType("REAL"); + + b.Property("OfficialRating") + .HasColumnType("TEXT"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("ParentIndexNumber") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataCountryCode") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataLanguage") + .HasColumnType("TEXT"); + + b.Property("PremiereDate") + .HasColumnType("TEXT"); + + b.Property("PresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("PrimaryVersionId") + .HasColumnType("TEXT"); + + b.Property("ProductionLocations") + .HasColumnType("TEXT"); + + b.Property("ProductionYear") + .HasColumnType("INTEGER"); + + b.Property("RunTimeTicks") + .HasColumnType("INTEGER"); + + b.Property("SeasonId") + .HasColumnType("TEXT"); + + b.Property("SeasonName") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("TEXT"); + + b.Property("SeriesName") + .HasColumnType("TEXT"); + + b.Property("SeriesPresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("ShowId") + .HasColumnType("TEXT"); + + b.Property("Size") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("Studios") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Tags") + .HasColumnType("TEXT"); + + b.Property("TopParentId") + .HasColumnType("TEXT"); + + b.Property("TotalBitrate") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnratedType") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Blurhash") + .HasColumnType("BLOB"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("ImageType") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("ProviderValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ChapterIndex") + .HasColumnType("INTEGER"); + + b.Property("ImageDateModified") + .HasColumnType("TEXT"); + + b.Property("ImagePath") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("StartPositionTicks") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Property("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CleanValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue"); + + b.ToTable("ItemValues"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.Property("ItemValueId") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EndTicks") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartTicks") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("StreamIndex") + .HasColumnType("INTEGER"); + + b.Property("AspectRatio") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AverageFrameRate") + .HasColumnType("REAL"); + + b.Property("BitDepth") + .HasColumnType("INTEGER"); + + b.Property("BitRate") + .HasColumnType("INTEGER"); + + b.Property("BlPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("ChannelLayout") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Channels") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("CodecTimeBase") + .HasColumnType("TEXT"); + + b.Property("ColorPrimaries") + .HasColumnType("TEXT"); + + b.Property("ColorSpace") + .HasColumnType("TEXT"); + + b.Property("ColorTransfer") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("DvBlSignalCompatibilityId") + .HasColumnType("INTEGER"); + + b.Property("DvLevel") + .HasColumnType("INTEGER"); + + b.Property("DvProfile") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMajor") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMinor") + .HasColumnType("INTEGER"); + + b.Property("ElPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IsAnamorphic") + .HasColumnType("INTEGER"); + + b.Property("IsAvc") + .HasColumnType("INTEGER"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("IsExternal") + .HasColumnType("INTEGER"); + + b.Property("IsForced") + .HasColumnType("INTEGER"); + + b.Property("IsHearingImpaired") + .HasColumnType("INTEGER"); + + b.Property("IsInterlaced") + .HasColumnType("INTEGER"); + + b.Property("KeyFrames") + .HasColumnType("TEXT"); + + b.Property("Language") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("REAL"); + + b.Property("NalLengthSize") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PixelFormat") + .HasColumnType("TEXT"); + + b.Property("Profile") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RealFrameRate") + .HasColumnType("REAL"); + + b.Property("RefFrames") + .HasColumnType("INTEGER"); + + b.Property("Rotation") + .HasColumnType("INTEGER"); + + b.Property("RpuPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("SampleRate") + .HasColumnType("INTEGER"); + + b.Property("StreamType") + .HasColumnType("INTEGER"); + + b.Property("TimeBase") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PersonType") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("PeopleId") + .HasColumnType("TEXT"); + + b.Property("ListOrder") + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("CustomDataKey") + .HasColumnType("TEXT"); + + b.Property("AudioStreamIndex") + .HasColumnType("INTEGER"); + + b.Property("IsFavorite") + .HasColumnType("INTEGER"); + + b.Property("LastPlayedDate") + .HasColumnType("TEXT"); + + b.Property("Likes") + .HasColumnType("INTEGER"); + + b.Property("PlayCount") + .HasColumnType("INTEGER"); + + b.Property("PlaybackPositionTicks") + .HasColumnType("INTEGER"); + + b.Property("Played") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("REAL"); + + b.Property("SubtitleStreamIndex") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "UserId", "CustomDataKey"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Children") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") + .WithMany("ParentAncestors") + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Navigation("Chapters"); + + b.Navigation("Children"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("ParentAncestors"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112232041_fixMediaStreams.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112232041_fixMediaStreams.cs new file mode 100644 index 000000000..d57ea81b3 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112232041_fixMediaStreams.cs @@ -0,0 +1,702 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class FixMediaStreams : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Width", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "Title", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "TimeBase", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "StreamType", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "SampleRate", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "RpuPresentFlag", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "Rotation", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "RefFrames", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "RealFrameRate", + table: "MediaStreamInfos", + type: "REAL", + nullable: true, + oldClrType: typeof(float), + oldType: "REAL"); + + migrationBuilder.AlterColumn( + name: "Profile", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Path", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "NalLengthSize", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "Level", + table: "MediaStreamInfos", + type: "REAL", + nullable: true, + oldClrType: typeof(float), + oldType: "REAL"); + + migrationBuilder.AlterColumn( + name: "Language", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "IsHearingImpaired", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(bool), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "IsAvc", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(bool), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "IsAnamorphic", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(bool), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "Height", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "ElPresentFlag", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "DvVersionMinor", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "DvVersionMajor", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "DvProfile", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "DvLevel", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "DvBlSignalCompatibilityId", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "Comment", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "ColorTransfer", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "ColorSpace", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "ColorPrimaries", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "CodecTimeBase", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "CodecTag", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "Codec", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Channels", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "ChannelLayout", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "BlPresentFlag", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "BitRate", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "BitDepth", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "AverageFrameRate", + table: "MediaStreamInfos", + type: "REAL", + nullable: true, + oldClrType: typeof(float), + oldType: "REAL"); + + migrationBuilder.AlterColumn( + name: "AspectRatio", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Width", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Title", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "TimeBase", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "StreamType", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "SampleRate", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "RpuPresentFlag", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Rotation", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "RefFrames", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "RealFrameRate", + table: "MediaStreamInfos", + type: "REAL", + nullable: false, + defaultValue: 0f, + oldClrType: typeof(float), + oldType: "REAL", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Profile", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "Path", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "NalLengthSize", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Level", + table: "MediaStreamInfos", + type: "REAL", + nullable: false, + defaultValue: 0f, + oldClrType: typeof(float), + oldType: "REAL", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Language", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "IsHearingImpaired", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: false, + oldClrType: typeof(bool), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "IsAvc", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: false, + oldClrType: typeof(bool), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "IsAnamorphic", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: false, + oldClrType: typeof(bool), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Height", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ElPresentFlag", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "DvVersionMinor", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "DvVersionMajor", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "DvProfile", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "DvLevel", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "DvBlSignalCompatibilityId", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Comment", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ColorTransfer", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ColorSpace", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ColorPrimaries", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "CodecTimeBase", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "CodecTag", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Codec", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "Channels", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ChannelLayout", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "BlPresentFlag", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "BitRate", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "BitDepth", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "AverageFrameRate", + table: "MediaStreamInfos", + type: "REAL", + nullable: false, + defaultValue: 0f, + oldClrType: typeof(float), + oldType: "REAL", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "AspectRatio", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112234144_FixMediaStreams2.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112234144_FixMediaStreams2.Designer.cs new file mode 100644 index 000000000..5714120b5 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112234144_FixMediaStreams2.Designer.cs @@ -0,0 +1,1594 @@ +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20241112234144_FixMediaStreams2")] + partial class FixMediaStreams2 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ParentItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("Filename") + .HasColumnType("TEXT"); + + b.Property("MimeType") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Album") + .HasColumnType("TEXT"); + + b.Property("AlbumArtists") + .HasColumnType("TEXT"); + + b.Property("Artists") + .HasColumnType("TEXT"); + + b.Property("Audio") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("TEXT"); + + b.Property("CleanName") + .HasColumnType("TEXT"); + + b.Property("CommunityRating") + .HasColumnType("REAL"); + + b.Property("CriticRating") + .HasColumnType("REAL"); + + b.Property("CustomRating") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastMediaAdded") + .HasColumnType("TEXT"); + + b.Property("DateLastRefreshed") + .HasColumnType("TEXT"); + + b.Property("DateLastSaved") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EpisodeTitle") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasColumnType("TEXT"); + + b.Property("ExternalSeriesId") + .HasColumnType("TEXT"); + + b.Property("ExternalServiceId") + .HasColumnType("TEXT"); + + b.Property("ExtraIds") + .HasColumnType("TEXT"); + + b.Property("ExtraType") + .HasColumnType("INTEGER"); + + b.Property("ForcedSortName") + .HasColumnType("TEXT"); + + b.Property("Genres") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IndexNumber") + .HasColumnType("INTEGER"); + + b.Property("InheritedParentalRatingValue") + .HasColumnType("INTEGER"); + + b.Property("IsFolder") + .HasColumnType("INTEGER"); + + b.Property("IsInMixedFolder") + .HasColumnType("INTEGER"); + + b.Property("IsLocked") + .HasColumnType("INTEGER"); + + b.Property("IsMovie") + .HasColumnType("INTEGER"); + + b.Property("IsRepeat") + .HasColumnType("INTEGER"); + + b.Property("IsSeries") + .HasColumnType("INTEGER"); + + b.Property("IsVirtualItem") + .HasColumnType("INTEGER"); + + b.Property("LUFS") + .HasColumnType("REAL"); + + b.Property("MediaType") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizationGain") + .HasColumnType("REAL"); + + b.Property("OfficialRating") + .HasColumnType("TEXT"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("ParentIndexNumber") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataCountryCode") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataLanguage") + .HasColumnType("TEXT"); + + b.Property("PremiereDate") + .HasColumnType("TEXT"); + + b.Property("PresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("PrimaryVersionId") + .HasColumnType("TEXT"); + + b.Property("ProductionLocations") + .HasColumnType("TEXT"); + + b.Property("ProductionYear") + .HasColumnType("INTEGER"); + + b.Property("RunTimeTicks") + .HasColumnType("INTEGER"); + + b.Property("SeasonId") + .HasColumnType("TEXT"); + + b.Property("SeasonName") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("TEXT"); + + b.Property("SeriesName") + .HasColumnType("TEXT"); + + b.Property("SeriesPresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("ShowId") + .HasColumnType("TEXT"); + + b.Property("Size") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("Studios") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Tags") + .HasColumnType("TEXT"); + + b.Property("TopParentId") + .HasColumnType("TEXT"); + + b.Property("TotalBitrate") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnratedType") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Blurhash") + .HasColumnType("BLOB"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("ImageType") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("ProviderValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ChapterIndex") + .HasColumnType("INTEGER"); + + b.Property("ImageDateModified") + .HasColumnType("TEXT"); + + b.Property("ImagePath") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("StartPositionTicks") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Property("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CleanValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue"); + + b.ToTable("ItemValues"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.Property("ItemValueId") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EndTicks") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartTicks") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("StreamIndex") + .HasColumnType("INTEGER"); + + b.Property("AspectRatio") + .HasColumnType("TEXT"); + + b.Property("AverageFrameRate") + .HasColumnType("REAL"); + + b.Property("BitDepth") + .HasColumnType("INTEGER"); + + b.Property("BitRate") + .HasColumnType("INTEGER"); + + b.Property("BlPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("ChannelLayout") + .HasColumnType("TEXT"); + + b.Property("Channels") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("CodecTimeBase") + .HasColumnType("TEXT"); + + b.Property("ColorPrimaries") + .HasColumnType("TEXT"); + + b.Property("ColorSpace") + .HasColumnType("TEXT"); + + b.Property("ColorTransfer") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("DvBlSignalCompatibilityId") + .HasColumnType("INTEGER"); + + b.Property("DvLevel") + .HasColumnType("INTEGER"); + + b.Property("DvProfile") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMajor") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMinor") + .HasColumnType("INTEGER"); + + b.Property("ElPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IsAnamorphic") + .HasColumnType("INTEGER"); + + b.Property("IsAvc") + .HasColumnType("INTEGER"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("IsExternal") + .HasColumnType("INTEGER"); + + b.Property("IsForced") + .HasColumnType("INTEGER"); + + b.Property("IsHearingImpaired") + .HasColumnType("INTEGER"); + + b.Property("IsInterlaced") + .HasColumnType("INTEGER"); + + b.Property("KeyFrames") + .HasColumnType("TEXT"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("REAL"); + + b.Property("NalLengthSize") + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PixelFormat") + .HasColumnType("TEXT"); + + b.Property("Profile") + .HasColumnType("TEXT"); + + b.Property("RealFrameRate") + .HasColumnType("REAL"); + + b.Property("RefFrames") + .HasColumnType("INTEGER"); + + b.Property("Rotation") + .HasColumnType("INTEGER"); + + b.Property("RpuPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("SampleRate") + .HasColumnType("INTEGER"); + + b.Property("StreamType") + .HasColumnType("INTEGER"); + + b.Property("TimeBase") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PersonType") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("PeopleId") + .HasColumnType("TEXT"); + + b.Property("ListOrder") + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("CustomDataKey") + .HasColumnType("TEXT"); + + b.Property("AudioStreamIndex") + .HasColumnType("INTEGER"); + + b.Property("IsFavorite") + .HasColumnType("INTEGER"); + + b.Property("LastPlayedDate") + .HasColumnType("TEXT"); + + b.Property("Likes") + .HasColumnType("INTEGER"); + + b.Property("PlayCount") + .HasColumnType("INTEGER"); + + b.Property("PlaybackPositionTicks") + .HasColumnType("INTEGER"); + + b.Property("Played") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("REAL"); + + b.Property("SubtitleStreamIndex") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "UserId", "CustomDataKey"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Children") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") + .WithMany("ParentAncestors") + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Navigation("Chapters"); + + b.Navigation("Children"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("ParentAncestors"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112234144_FixMediaStreams2.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112234144_FixMediaStreams2.cs new file mode 100644 index 000000000..78611b9e4 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241112234144_FixMediaStreams2.cs @@ -0,0 +1,144 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class FixMediaStreams2 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Profile", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "Path", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "Language", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "IsInterlaced", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true, + oldClrType: typeof(bool), + oldType: "INTEGER"); + + migrationBuilder.AlterColumn( + name: "Codec", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "ChannelLayout", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "AspectRatio", + table: "MediaStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Profile", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Path", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Language", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "IsInterlaced", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: false, + defaultValue: false, + oldClrType: typeof(bool), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Codec", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ChannelLayout", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "AspectRatio", + table: "MediaStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs new file mode 100644 index 000000000..855f02fd3 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs @@ -0,0 +1,1595 @@ +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20241113133548_EnforceUniqueItemValue")] + partial class EnforceUniqueItemValue + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ParentItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("Filename") + .HasColumnType("TEXT"); + + b.Property("MimeType") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Album") + .HasColumnType("TEXT"); + + b.Property("AlbumArtists") + .HasColumnType("TEXT"); + + b.Property("Artists") + .HasColumnType("TEXT"); + + b.Property("Audio") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("TEXT"); + + b.Property("CleanName") + .HasColumnType("TEXT"); + + b.Property("CommunityRating") + .HasColumnType("REAL"); + + b.Property("CriticRating") + .HasColumnType("REAL"); + + b.Property("CustomRating") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastMediaAdded") + .HasColumnType("TEXT"); + + b.Property("DateLastRefreshed") + .HasColumnType("TEXT"); + + b.Property("DateLastSaved") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EpisodeTitle") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasColumnType("TEXT"); + + b.Property("ExternalSeriesId") + .HasColumnType("TEXT"); + + b.Property("ExternalServiceId") + .HasColumnType("TEXT"); + + b.Property("ExtraIds") + .HasColumnType("TEXT"); + + b.Property("ExtraType") + .HasColumnType("INTEGER"); + + b.Property("ForcedSortName") + .HasColumnType("TEXT"); + + b.Property("Genres") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IndexNumber") + .HasColumnType("INTEGER"); + + b.Property("InheritedParentalRatingValue") + .HasColumnType("INTEGER"); + + b.Property("IsFolder") + .HasColumnType("INTEGER"); + + b.Property("IsInMixedFolder") + .HasColumnType("INTEGER"); + + b.Property("IsLocked") + .HasColumnType("INTEGER"); + + b.Property("IsMovie") + .HasColumnType("INTEGER"); + + b.Property("IsRepeat") + .HasColumnType("INTEGER"); + + b.Property("IsSeries") + .HasColumnType("INTEGER"); + + b.Property("IsVirtualItem") + .HasColumnType("INTEGER"); + + b.Property("LUFS") + .HasColumnType("REAL"); + + b.Property("MediaType") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizationGain") + .HasColumnType("REAL"); + + b.Property("OfficialRating") + .HasColumnType("TEXT"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("ParentIndexNumber") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataCountryCode") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataLanguage") + .HasColumnType("TEXT"); + + b.Property("PremiereDate") + .HasColumnType("TEXT"); + + b.Property("PresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("PrimaryVersionId") + .HasColumnType("TEXT"); + + b.Property("ProductionLocations") + .HasColumnType("TEXT"); + + b.Property("ProductionYear") + .HasColumnType("INTEGER"); + + b.Property("RunTimeTicks") + .HasColumnType("INTEGER"); + + b.Property("SeasonId") + .HasColumnType("TEXT"); + + b.Property("SeasonName") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("TEXT"); + + b.Property("SeriesName") + .HasColumnType("TEXT"); + + b.Property("SeriesPresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("ShowId") + .HasColumnType("TEXT"); + + b.Property("Size") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("Studios") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Tags") + .HasColumnType("TEXT"); + + b.Property("TopParentId") + .HasColumnType("TEXT"); + + b.Property("TotalBitrate") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnratedType") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Blurhash") + .HasColumnType("BLOB"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("ImageType") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("ProviderValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ChapterIndex") + .HasColumnType("INTEGER"); + + b.Property("ImageDateModified") + .HasColumnType("TEXT"); + + b.Property("ImagePath") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("StartPositionTicks") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Property("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CleanValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue") + .IsUnique(); + + b.ToTable("ItemValues"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.Property("ItemValueId") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EndTicks") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartTicks") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("StreamIndex") + .HasColumnType("INTEGER"); + + b.Property("AspectRatio") + .HasColumnType("TEXT"); + + b.Property("AverageFrameRate") + .HasColumnType("REAL"); + + b.Property("BitDepth") + .HasColumnType("INTEGER"); + + b.Property("BitRate") + .HasColumnType("INTEGER"); + + b.Property("BlPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("ChannelLayout") + .HasColumnType("TEXT"); + + b.Property("Channels") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("CodecTimeBase") + .HasColumnType("TEXT"); + + b.Property("ColorPrimaries") + .HasColumnType("TEXT"); + + b.Property("ColorSpace") + .HasColumnType("TEXT"); + + b.Property("ColorTransfer") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("DvBlSignalCompatibilityId") + .HasColumnType("INTEGER"); + + b.Property("DvLevel") + .HasColumnType("INTEGER"); + + b.Property("DvProfile") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMajor") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMinor") + .HasColumnType("INTEGER"); + + b.Property("ElPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IsAnamorphic") + .HasColumnType("INTEGER"); + + b.Property("IsAvc") + .HasColumnType("INTEGER"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("IsExternal") + .HasColumnType("INTEGER"); + + b.Property("IsForced") + .HasColumnType("INTEGER"); + + b.Property("IsHearingImpaired") + .HasColumnType("INTEGER"); + + b.Property("IsInterlaced") + .HasColumnType("INTEGER"); + + b.Property("KeyFrames") + .HasColumnType("TEXT"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("REAL"); + + b.Property("NalLengthSize") + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PixelFormat") + .HasColumnType("TEXT"); + + b.Property("Profile") + .HasColumnType("TEXT"); + + b.Property("RealFrameRate") + .HasColumnType("REAL"); + + b.Property("RefFrames") + .HasColumnType("INTEGER"); + + b.Property("Rotation") + .HasColumnType("INTEGER"); + + b.Property("RpuPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("SampleRate") + .HasColumnType("INTEGER"); + + b.Property("StreamType") + .HasColumnType("INTEGER"); + + b.Property("TimeBase") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PersonType") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("PeopleId") + .HasColumnType("TEXT"); + + b.Property("ListOrder") + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("CustomDataKey") + .HasColumnType("TEXT"); + + b.Property("AudioStreamIndex") + .HasColumnType("INTEGER"); + + b.Property("IsFavorite") + .HasColumnType("INTEGER"); + + b.Property("LastPlayedDate") + .HasColumnType("TEXT"); + + b.Property("Likes") + .HasColumnType("INTEGER"); + + b.Property("PlayCount") + .HasColumnType("INTEGER"); + + b.Property("PlaybackPositionTicks") + .HasColumnType("INTEGER"); + + b.Property("Played") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("REAL"); + + b.Property("SubtitleStreamIndex") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "UserId", "CustomDataKey"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Children") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") + .WithMany("ParentAncestors") + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Navigation("Chapters"); + + b.Navigation("Children"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("ParentAncestors"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241113133548_EnforceUniqueItemValue.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241113133548_EnforceUniqueItemValue.cs new file mode 100644 index 000000000..d1b06ceae --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/20241113133548_EnforceUniqueItemValue.cs @@ -0,0 +1,37 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class EnforceUniqueItemValue : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_ItemValues_Type_CleanValue", + table: "ItemValues"); + + migrationBuilder.CreateIndex( + name: "IX_ItemValues_Type_CleanValue", + table: "ItemValues", + columns: new[] { "Type", "CleanValue" }, + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_ItemValues_Type_CleanValue", + table: "ItemValues"); + + migrationBuilder.CreateIndex( + name: "IX_ItemValues_Type_CleanValue", + table: "ItemValues", + columns: new[] { "Type", "CleanValue" }); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/DesignTimeJellyfinDbFactory.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/DesignTimeJellyfinDbFactory.cs new file mode 100644 index 000000000..942af284a --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/DesignTimeJellyfinDbFactory.cs @@ -0,0 +1,25 @@ +using Jellyfin.Database.Providers.SqLite; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + /// The design time factory for . + /// This is only used for the creation of migrations and not during runtime. + /// + internal sealed class DesignTimeJellyfinDbFactory : IDesignTimeDbContextFactory + { + public JellyfinDbContext CreateDbContext(string[] args) + { + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.UseSqlite("Data Source=jellyfin.db"); + + return new JellyfinDbContext( + optionsBuilder.Options, + NullLogger.Instance, + new SqliteDatabaseProvider(null!, null!, NullLogger.Instance)); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/JellyfinDbModelSnapshot.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/JellyfinDbModelSnapshot.cs new file mode 100644 index 000000000..e75760d80 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/JellyfinDbModelSnapshot.cs @@ -0,0 +1,1592 @@ +// +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + partial class JellyfinDbModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ParentItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("Filename") + .HasColumnType("TEXT"); + + b.Property("MimeType") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Album") + .HasColumnType("TEXT"); + + b.Property("AlbumArtists") + .HasColumnType("TEXT"); + + b.Property("Artists") + .HasColumnType("TEXT"); + + b.Property("Audio") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("TEXT"); + + b.Property("CleanName") + .HasColumnType("TEXT"); + + b.Property("CommunityRating") + .HasColumnType("REAL"); + + b.Property("CriticRating") + .HasColumnType("REAL"); + + b.Property("CustomRating") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastMediaAdded") + .HasColumnType("TEXT"); + + b.Property("DateLastRefreshed") + .HasColumnType("TEXT"); + + b.Property("DateLastSaved") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EpisodeTitle") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasColumnType("TEXT"); + + b.Property("ExternalSeriesId") + .HasColumnType("TEXT"); + + b.Property("ExternalServiceId") + .HasColumnType("TEXT"); + + b.Property("ExtraIds") + .HasColumnType("TEXT"); + + b.Property("ExtraType") + .HasColumnType("INTEGER"); + + b.Property("ForcedSortName") + .HasColumnType("TEXT"); + + b.Property("Genres") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IndexNumber") + .HasColumnType("INTEGER"); + + b.Property("InheritedParentalRatingValue") + .HasColumnType("INTEGER"); + + b.Property("IsFolder") + .HasColumnType("INTEGER"); + + b.Property("IsInMixedFolder") + .HasColumnType("INTEGER"); + + b.Property("IsLocked") + .HasColumnType("INTEGER"); + + b.Property("IsMovie") + .HasColumnType("INTEGER"); + + b.Property("IsRepeat") + .HasColumnType("INTEGER"); + + b.Property("IsSeries") + .HasColumnType("INTEGER"); + + b.Property("IsVirtualItem") + .HasColumnType("INTEGER"); + + b.Property("LUFS") + .HasColumnType("REAL"); + + b.Property("MediaType") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizationGain") + .HasColumnType("REAL"); + + b.Property("OfficialRating") + .HasColumnType("TEXT"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("ParentIndexNumber") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataCountryCode") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataLanguage") + .HasColumnType("TEXT"); + + b.Property("PremiereDate") + .HasColumnType("TEXT"); + + b.Property("PresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("PrimaryVersionId") + .HasColumnType("TEXT"); + + b.Property("ProductionLocations") + .HasColumnType("TEXT"); + + b.Property("ProductionYear") + .HasColumnType("INTEGER"); + + b.Property("RunTimeTicks") + .HasColumnType("INTEGER"); + + b.Property("SeasonId") + .HasColumnType("TEXT"); + + b.Property("SeasonName") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("TEXT"); + + b.Property("SeriesName") + .HasColumnType("TEXT"); + + b.Property("SeriesPresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("ShowId") + .HasColumnType("TEXT"); + + b.Property("Size") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("Studios") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Tags") + .HasColumnType("TEXT"); + + b.Property("TopParentId") + .HasColumnType("TEXT"); + + b.Property("TotalBitrate") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnratedType") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Blurhash") + .HasColumnType("BLOB"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("ImageType") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("ProviderValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ChapterIndex") + .HasColumnType("INTEGER"); + + b.Property("ImageDateModified") + .HasColumnType("TEXT"); + + b.Property("ImagePath") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("StartPositionTicks") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Property("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CleanValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue") + .IsUnique(); + + b.ToTable("ItemValues"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.Property("ItemValueId") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EndTicks") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartTicks") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("StreamIndex") + .HasColumnType("INTEGER"); + + b.Property("AspectRatio") + .HasColumnType("TEXT"); + + b.Property("AverageFrameRate") + .HasColumnType("REAL"); + + b.Property("BitDepth") + .HasColumnType("INTEGER"); + + b.Property("BitRate") + .HasColumnType("INTEGER"); + + b.Property("BlPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("ChannelLayout") + .HasColumnType("TEXT"); + + b.Property("Channels") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("CodecTimeBase") + .HasColumnType("TEXT"); + + b.Property("ColorPrimaries") + .HasColumnType("TEXT"); + + b.Property("ColorSpace") + .HasColumnType("TEXT"); + + b.Property("ColorTransfer") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("DvBlSignalCompatibilityId") + .HasColumnType("INTEGER"); + + b.Property("DvLevel") + .HasColumnType("INTEGER"); + + b.Property("DvProfile") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMajor") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMinor") + .HasColumnType("INTEGER"); + + b.Property("ElPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IsAnamorphic") + .HasColumnType("INTEGER"); + + b.Property("IsAvc") + .HasColumnType("INTEGER"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("IsExternal") + .HasColumnType("INTEGER"); + + b.Property("IsForced") + .HasColumnType("INTEGER"); + + b.Property("IsHearingImpaired") + .HasColumnType("INTEGER"); + + b.Property("IsInterlaced") + .HasColumnType("INTEGER"); + + b.Property("KeyFrames") + .HasColumnType("TEXT"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("REAL"); + + b.Property("NalLengthSize") + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PixelFormat") + .HasColumnType("TEXT"); + + b.Property("Profile") + .HasColumnType("TEXT"); + + b.Property("RealFrameRate") + .HasColumnType("REAL"); + + b.Property("RefFrames") + .HasColumnType("INTEGER"); + + b.Property("Rotation") + .HasColumnType("INTEGER"); + + b.Property("RpuPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("SampleRate") + .HasColumnType("INTEGER"); + + b.Property("StreamType") + .HasColumnType("INTEGER"); + + b.Property("TimeBase") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PersonType") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("PeopleId") + .HasColumnType("TEXT"); + + b.Property("ListOrder") + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("CustomDataKey") + .HasColumnType("TEXT"); + + b.Property("AudioStreamIndex") + .HasColumnType("INTEGER"); + + b.Property("IsFavorite") + .HasColumnType("INTEGER"); + + b.Property("LastPlayedDate") + .HasColumnType("TEXT"); + + b.Property("Likes") + .HasColumnType("INTEGER"); + + b.Property("PlayCount") + .HasColumnType("INTEGER"); + + b.Property("PlaybackPositionTicks") + .HasColumnType("INTEGER"); + + b.Property("Played") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("REAL"); + + b.Property("SubtitleStreamIndex") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "UserId", "CustomDataKey"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Children") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") + .WithMany("ParentAncestors") + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Navigation("Chapters"); + + b.Navigation("Children"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("ParentAncestors"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/SqliteDatabaseProvider.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/SqliteDatabaseProvider.cs new file mode 100644 index 000000000..8bc025a0b --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/SqliteDatabaseProvider.cs @@ -0,0 +1,78 @@ +using System; +using Jellyfin.Server.Implementations; +using MediaBrowser.Common.Configuration; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Database.Providers.SqLite; + +/// +/// Configures jellyfin to use an SqLite database. +/// +public sealed class SqliteDatabaseProvider : IJellyfinDatabaseProvider +{ + private readonly IApplicationPaths _applicationPaths; + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + /// The Db context to interact with the database. + /// Service to construct the fallback when the old data path configuration is used. + /// A logger. + public SqliteDatabaseProvider(IDbContextFactory dbContextFactory, IApplicationPaths applicationPaths, ILogger logger) + { + DbContextFactory = dbContextFactory; + _applicationPaths = applicationPaths; + _logger = logger; + } + + private IDbContextFactory DbContextFactory { get; } + + /// + public void Initialise(DbContextOptionsBuilder options) + { + options.UseSqlite( + $"Filename={Path.Combine(_applicationPaths.DataPath, "jellyfin.db")};Pooling=false", + sqLiteOptions => sqLiteOptions.MigrationsAssembly(GetType().Assembly)); + } + + /// + public async Task RunScheduledOptimisation(CancellationToken cancellationToken) + { + var context = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); + await using (context.ConfigureAwait(false)) + { + if (context.Database.IsSqlite()) + { + await context.Database.ExecuteSqlRawAsync("PRAGMA optimize", cancellationToken).ConfigureAwait(false); + await context.Database.ExecuteSqlRawAsync("VACUUM", cancellationToken).ConfigureAwait(false); + _logger.LogInformation("jellyfin.db optimized successfully!"); + } + else + { + _logger.LogInformation("This database doesn't support optimization"); + } + } + } + + /// + public void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.SetDefaultDateTimeKind(DateTimeKind.Utc); + } + + /// + public async ValueTask DisposeAsync() + { + // Run before disposing the application + var context = await DbContextFactory.CreateDbContextAsync().ConfigureAwait(false); + await using (context.ConfigureAwait(false)) + { + await context.Database.ExecuteSqlRawAsync("PRAGMA optimize").ConfigureAwait(false); + } + + SqliteConnection.ClearAllPools(); + } +} diff --git a/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationFactory.cs b/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationFactory.cs new file mode 100644 index 000000000..26d32f417 --- /dev/null +++ b/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationFactory.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using MediaBrowser.Common.Configuration; + +namespace Jellyfin.Server.Implementations.DatabaseConfiguration; + +/// +/// Factory for constructing a database configuration. +/// +public class DatabaseConfigurationFactory : IConfigurationFactory +{ + /// + public IEnumerable GetConfigurations() + { + yield return new DatabaseConfigurationStore(); + } +} diff --git a/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs b/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs new file mode 100644 index 000000000..af2ede701 --- /dev/null +++ b/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs @@ -0,0 +1,14 @@ +using System; + +namespace Jellyfin.Server.Implementations.DatabaseConfiguration; + +/// +/// Options to configure jellyfins managed database. +/// +public class DatabaseConfigurationOptions +{ + /// + /// Gets or Sets the type of database jellyfin should use. + /// + public required string DatabaseType { get; set; } +} diff --git a/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationStore.cs b/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationStore.cs new file mode 100644 index 000000000..180561fc8 --- /dev/null +++ b/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationStore.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using MediaBrowser.Common.Configuration; + +namespace Jellyfin.Server.Implementations.DatabaseConfiguration; + +/// +/// A configuration that stores database related settings. +/// +public class DatabaseConfigurationStore : ConfigurationStore +{ + /// + /// The name of the configuration in the storage. + /// + public const string StoreKey = "database"; + + /// + /// Initializes a new instance of the class. + /// + public DatabaseConfigurationStore() + { + ConfigurationType = typeof(DatabaseConfigurationOptions); + Key = StoreKey; + } +} diff --git a/Jellyfin.Server.Implementations/Devices/DeviceManager.cs b/Jellyfin.Server.Implementations/Devices/DeviceManager.cs index d3bff2936..1b4048b8e 100644 --- a/Jellyfin.Server.Implementations/Devices/DeviceManager.cs +++ b/Jellyfin.Server.Implementations/Devices/DeviceManager.cs @@ -3,6 +3,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Dtos; using Jellyfin.Data.Entities; using Jellyfin.Data.Entities.Security; diff --git a/Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs b/Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs index 7eee26059..e48f4ce10 100644 --- a/Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs +++ b/Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs @@ -1,8 +1,14 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Reflection; +using Jellyfin.Server.Implementations.DatabaseConfiguration; using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Configuration; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; +using JellyfinDbProviderFactory = System.Func; namespace Jellyfin.Server.Implementations.Extensions; @@ -11,17 +17,59 @@ namespace Jellyfin.Server.Implementations.Extensions; /// public static class ServiceCollectionExtensions { + private static IDictionary GetSupportedDbProviders() + { + var items = new Dictionary(); + foreach (var providerType in AppDomain + .CurrentDomain + .GetAssemblies() + .SelectMany(f => f.GetTypes()) + .Where(e => e.IsClass && typeof(IJellyfinDatabaseProvider).IsAssignableFrom(e))) + { + var keyAttribute = providerType.GetCustomAttribute(); + if (keyAttribute is null || string.IsNullOrWhiteSpace(keyAttribute.DatabaseProviderKey)) + { + continue; + } + + var provider = providerType; + items[keyAttribute.DatabaseProviderKey] = (services) => (IJellyfinDatabaseProvider)ActivatorUtilities.CreateInstance(services, providerType); + } + + return items; + } + /// /// Adds the interface to the service collection with second level caching enabled. /// /// An instance of the interface. + /// The server configuration manager. /// The updated service collection. - public static IServiceCollection AddJellyfinDbContext(this IServiceCollection serviceCollection) + public static IServiceCollection AddJellyfinDbContext(this IServiceCollection serviceCollection, IServerConfigurationManager configurationManager) { + var efCoreConfiguration = configurationManager.GetConfiguration("database"); + var providers = GetSupportedDbProviders(); + JellyfinDbProviderFactory? providerFactory = null; + + if (efCoreConfiguration is null) + { + // when nothing is setup via new Database configuration, fallback to SqLite with default settings. + efCoreConfiguration = new DatabaseConfigurationOptions() + { + DatabaseType = "SqLite", + }; + } + else if (!providers.TryGetValue(efCoreConfiguration.DatabaseType, out providerFactory!)) + { + throw new InvalidOperationException($"Jellyfin cannot find the database provider of type '{efCoreConfiguration.DatabaseType}'. Supported types are {string.Join(", ", providers.Keys)}"); + } + + serviceCollection.AddSingleton(providerFactory!); + serviceCollection.AddPooledDbContextFactory((serviceProvider, opt) => { - var applicationPaths = serviceProvider.GetRequiredService(); - opt.UseSqlite($"Filename={Path.Combine(applicationPaths.DataPath, "jellyfin.db")};Pooling=false"); + var provider = serviceProvider.GetRequiredService(); + provider.Initialise(opt); }); return serviceCollection; diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index 31cf24fb2..cf3c79276 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -28,22 +28,14 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/Jellyfin.Server.Implementations/JellyfinDbContext.cs b/Jellyfin.Server.Implementations/JellyfinDbContext.cs deleted file mode 100644 index becfd81a4..000000000 --- a/Jellyfin.Server.Implementations/JellyfinDbContext.cs +++ /dev/null @@ -1,274 +0,0 @@ -using System; -using System.Linq; -using Jellyfin.Data.Entities; -using Jellyfin.Data.Entities.Security; -using Jellyfin.Data.Interfaces; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; - -namespace Jellyfin.Server.Implementations; - -/// -/// -/// Initializes a new instance of the class. -/// -/// The database context options. -/// Logger. -public class JellyfinDbContext(DbContextOptions options, ILogger logger) : DbContext(options) -{ - /// - /// Gets the containing the access schedules. - /// - public DbSet AccessSchedules => Set(); - - /// - /// Gets the containing the activity logs. - /// - public DbSet ActivityLogs => Set(); - - /// - /// Gets the containing the API keys. - /// - public DbSet ApiKeys => Set(); - - /// - /// Gets the containing the devices. - /// - public DbSet Devices => Set(); - - /// - /// Gets the containing the device options. - /// - public DbSet DeviceOptions => Set(); - - /// - /// Gets the containing the display preferences. - /// - public DbSet DisplayPreferences => Set(); - - /// - /// Gets the containing the image infos. - /// - public DbSet ImageInfos => Set(); - - /// - /// Gets the containing the item display preferences. - /// - public DbSet ItemDisplayPreferences => Set(); - - /// - /// Gets the containing the custom item display preferences. - /// - public DbSet CustomItemDisplayPreferences => Set(); - - /// - /// Gets the containing the permissions. - /// - public DbSet Permissions => Set(); - - /// - /// Gets the containing the preferences. - /// - public DbSet Preferences => Set(); - - /// - /// Gets the containing the users. - /// - public DbSet Users => Set(); - - /// - /// Gets the containing the trickplay metadata. - /// - public DbSet TrickplayInfos => Set(); - - /// - /// Gets the containing the media segments. - /// - public DbSet MediaSegments => Set(); - - /// - /// Gets the containing the user data. - /// - public DbSet UserData => Set(); - - /// - /// Gets the containing the user data. - /// - public DbSet AncestorIds => Set(); - - /// - /// Gets the containing the user data. - /// - public DbSet AttachmentStreamInfos => Set(); - - /// - /// Gets the containing the user data. - /// - public DbSet BaseItems => Set(); - - /// - /// Gets the containing the user data. - /// - public DbSet Chapters => Set(); - - /// - /// Gets the . - /// - public DbSet ItemValues => Set(); - - /// - /// Gets the . - /// - public DbSet ItemValuesMap => Set(); - - /// - /// Gets the . - /// - public DbSet MediaStreamInfos => Set(); - - /// - /// Gets the . - /// - public DbSet Peoples => Set(); - - /// - /// Gets the . - /// - public DbSet PeopleBaseItemMap => Set(); - - /// - /// Gets the containing the referenced Providers with ids. - /// - public DbSet BaseItemProviders => Set(); - - /// - /// Gets the . - /// - public DbSet BaseItemImageInfos => Set(); - - /// - /// Gets the . - /// - public DbSet BaseItemMetadataFields => Set(); - - /// - /// Gets the . - /// - public DbSet BaseItemTrailerTypes => Set(); - - /*public DbSet Artwork => Set(); - - public DbSet Books => Set(); - - public DbSet BookMetadata => Set(); - - public DbSet Chapters => Set(); - - public DbSet Collections => Set(); - - public DbSet CollectionItems => Set(); - - public DbSet Companies => Set(); - - public DbSet CompanyMetadata => Set(); - - public DbSet CustomItems => Set(); - - public DbSet CustomItemMetadata => Set(); - - public DbSet Episodes => Set(); - - public DbSet EpisodeMetadata => Set(); - - public DbSet Genres => Set(); - - public DbSet Groups => Set(); - - public DbSet Libraries => Set(); - - public DbSet LibraryItems => Set(); - - public DbSet LibraryRoot => Set(); - - public DbSet MediaFiles => Set(); - - public DbSet MediaFileStream => Set(); - - public DbSet Metadata => Set(); - - public DbSet MetadataProviders => Set(); - - public DbSet MetadataProviderIds => Set(); - - public DbSet Movies => Set(); - - public DbSet MovieMetadata => Set(); - - public DbSet MusicAlbums => Set(); - - public DbSet MusicAlbumMetadata => Set(); - - public DbSet People => Set(); - - public DbSet PersonRoles => Set(); - - public DbSet Photo => Set(); - - public DbSet PhotoMetadata => Set(); - - public DbSet ProviderMappings => Set(); - - public DbSet Ratings => Set(); - - /// - /// Repository for global::Jellyfin.Data.Entities.RatingSource - This is the entity to - /// store review ratings, not age ratings. - /// - public DbSet RatingSources => Set(); - - public DbSet Releases => Set(); - - public DbSet Seasons => Set(); - - public DbSet SeasonMetadata => Set(); - - public DbSet Series => Set(); - - public DbSet SeriesMetadata => Set Tracks => Set(); - - public DbSet TrackMetadata => Set();*/ - - /// - public override int SaveChanges() - { - foreach (var saveEntity in ChangeTracker.Entries() - .Where(e => e.State == EntityState.Modified) - .Select(entry => entry.Entity) - .OfType()) - { - saveEntity.OnSavingChanges(); - } - - try - { - return base.SaveChanges(); - } - catch (Exception e) - { - logger.LogError(e, "Error trying to save changes."); - throw; - } - } - - /// - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.SetDefaultDateTimeKind(DateTimeKind.Utc); - base.OnModelCreating(modelBuilder); - - // Configuration for each entity is in it's own class inside 'ModelConfiguration'. - modelBuilder.ApplyConfigurationsFromAssembly(typeof(JellyfinDbContext).Assembly); - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20200514181226_AddActivityLog.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20200514181226_AddActivityLog.Designer.cs deleted file mode 100644 index 80fe784dd..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20200514181226_AddActivityLog.Designer.cs +++ /dev/null @@ -1,72 +0,0 @@ -#pragma warning disable CS1591 - -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20200514181226_AddActivityLog")] - partial class AddActivityLog - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "3.1.3"); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Overview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("ActivityLogs"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20200514181226_AddActivityLog.cs b/Jellyfin.Server.Implementations/Migrations/20200514181226_AddActivityLog.cs deleted file mode 100644 index 002e5296e..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20200514181226_AddActivityLog.cs +++ /dev/null @@ -1,46 +0,0 @@ -#pragma warning disable CS1591 -#pragma warning disable SA1601 - -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Jellyfin.Server.Implementations.Migrations -{ - public partial class AddActivityLog : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.EnsureSchema( - name: "jellyfin"); - - migrationBuilder.CreateTable( - name: "ActivityLogs", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Name = table.Column(maxLength: 512, nullable: false), - Overview = table.Column(maxLength: 512, nullable: true), - ShortOverview = table.Column(maxLength: 512, nullable: true), - Type = table.Column(maxLength: 256, nullable: false), - UserId = table.Column(nullable: false), - ItemId = table.Column(maxLength: 256, nullable: true), - DateCreated = table.Column(nullable: false), - LogSeverity = table.Column(nullable: false), - RowVersion = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_ActivityLogs", x => x.Id); - }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "ActivityLogs", - schema: "jellyfin"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20200613202153_AddUsers.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20200613202153_AddUsers.Designer.cs deleted file mode 100644 index 7aa4479b3..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20200613202153_AddUsers.Designer.cs +++ /dev/null @@ -1,312 +0,0 @@ -#pragma warning disable CS1591 - -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20200613202153_AddUsers")] - partial class AddUsers - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "3.1.4"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Overview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("Permission_Permissions_Guid"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.HasKey("Id"); - - b.HasIndex("Preference_Preferences_Guid"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EasyPassword") - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.HasKey("Id"); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("Permission_Permissions_Guid"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("Preference_Preferences_Guid"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20200613202153_AddUsers.cs b/Jellyfin.Server.Implementations/Migrations/20200613202153_AddUsers.cs deleted file mode 100644 index 706a97ba2..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20200613202153_AddUsers.cs +++ /dev/null @@ -1,197 +0,0 @@ -#pragma warning disable CS1591 -#pragma warning disable SA1601 - -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Jellyfin.Server.Implementations.Migrations -{ - public partial class AddUsers : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Users", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(nullable: false), - Username = table.Column(maxLength: 255, nullable: false), - Password = table.Column(maxLength: 65535, nullable: true), - EasyPassword = table.Column(maxLength: 65535, nullable: true), - MustUpdatePassword = table.Column(nullable: false), - AudioLanguagePreference = table.Column(maxLength: 255, nullable: true), - AuthenticationProviderId = table.Column(maxLength: 255, nullable: false), - PasswordResetProviderId = table.Column(maxLength: 255, nullable: false), - InvalidLoginAttemptCount = table.Column(nullable: false), - LastActivityDate = table.Column(nullable: true), - LastLoginDate = table.Column(nullable: true), - LoginAttemptsBeforeLockout = table.Column(nullable: true), - SubtitleMode = table.Column(nullable: false), - PlayDefaultAudioTrack = table.Column(nullable: false), - SubtitleLanguagePreference = table.Column(maxLength: 255, nullable: true), - DisplayMissingEpisodes = table.Column(nullable: false), - DisplayCollectionsView = table.Column(nullable: false), - EnableLocalPassword = table.Column(nullable: false), - HidePlayedInLatest = table.Column(nullable: false), - RememberAudioSelections = table.Column(nullable: false), - RememberSubtitleSelections = table.Column(nullable: false), - EnableNextEpisodeAutoPlay = table.Column(nullable: false), - EnableAutoLogin = table.Column(nullable: false), - EnableUserPreferenceAccess = table.Column(nullable: false), - MaxParentalAgeRating = table.Column(nullable: true), - RemoteClientBitrateLimit = table.Column(nullable: true), - InternalId = table.Column(nullable: false), - SyncPlayAccess = table.Column(nullable: false), - RowVersion = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Users", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AccessSchedules", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - UserId = table.Column(nullable: false), - DayOfWeek = table.Column(nullable: false), - StartHour = table.Column(nullable: false), - EndHour = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AccessSchedules", x => x.Id); - table.ForeignKey( - name: "FK_AccessSchedules_Users_UserId", - column: x => x.UserId, - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "ImageInfos", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - UserId = table.Column(nullable: true), - Path = table.Column(maxLength: 512, nullable: false), - LastModified = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_ImageInfos", x => x.Id); - table.ForeignKey( - name: "FK_ImageInfos_Users_UserId", - column: x => x.UserId, - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "Permissions", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Kind = table.Column(nullable: false), - Value = table.Column(nullable: false), - RowVersion = table.Column(nullable: false), - Permission_Permissions_Guid = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Permissions", x => x.Id); - table.ForeignKey( - name: "FK_Permissions_Users_Permission_Permissions_Guid", - column: x => x.Permission_Permissions_Guid, - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "Preferences", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Kind = table.Column(nullable: false), - Value = table.Column(maxLength: 65535, nullable: false), - RowVersion = table.Column(nullable: false), - Preference_Preferences_Guid = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Preferences", x => x.Id); - table.ForeignKey( - name: "FK_Preferences_Users_Preference_Preferences_Guid", - column: x => x.Preference_Preferences_Guid, - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateIndex( - name: "IX_AccessSchedules_UserId", - schema: "jellyfin", - table: "AccessSchedules", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_ImageInfos_UserId", - schema: "jellyfin", - table: "ImageInfos", - column: "UserId", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Permissions_Permission_Permissions_Guid", - schema: "jellyfin", - table: "Permissions", - column: "Permission_Permissions_Guid"); - - migrationBuilder.CreateIndex( - name: "IX_Preferences_Preference_Preferences_Guid", - schema: "jellyfin", - table: "Preferences", - column: "Preference_Preferences_Guid"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "AccessSchedules", - schema: "jellyfin"); - - migrationBuilder.DropTable( - name: "ImageInfos", - schema: "jellyfin"); - - migrationBuilder.DropTable( - name: "Permissions", - schema: "jellyfin"); - - migrationBuilder.DropTable( - name: "Preferences", - schema: "jellyfin"); - - migrationBuilder.DropTable( - name: "Users", - schema: "jellyfin"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.Designer.cs deleted file mode 100644 index 3860c851d..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.Designer.cs +++ /dev/null @@ -1,459 +0,0 @@ -#pragma warning disable CS1591 - -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20200728005145_AddDisplayPreferences")] - partial class AddDisplayPreferences - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "3.1.6"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Overview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(32); - - b.Property("DashboardTheme") - .HasColumnType("TEXT") - .HasMaxLength(32); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasColumnType("TEXT") - .HasMaxLength(32); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(32); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(64); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("Permission_Permissions_Guid"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.HasKey("Id"); - - b.HasIndex("Preference_Preferences_Guid"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EasyPassword") - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.HasKey("Id"); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("DisplayPreferences") - .HasForeignKey("Jellyfin.Data.Entities.DisplayPreferences", "UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("Permission_Permissions_Guid"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("Preference_Preferences_Guid"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.cs b/Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.cs deleted file mode 100644 index 8cd551642..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.cs +++ /dev/null @@ -1,132 +0,0 @@ -#pragma warning disable CS1591 -#pragma warning disable SA1601 - -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Jellyfin.Server.Implementations.Migrations -{ - public partial class AddDisplayPreferences : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "DisplayPreferences", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - UserId = table.Column(nullable: false), - Client = table.Column(maxLength: 32, nullable: false), - ShowSidebar = table.Column(nullable: false), - ShowBackdrop = table.Column(nullable: false), - ScrollDirection = table.Column(nullable: false), - IndexBy = table.Column(nullable: true), - SkipForwardLength = table.Column(nullable: false), - SkipBackwardLength = table.Column(nullable: false), - ChromecastVersion = table.Column(nullable: false), - EnableNextVideoInfoOverlay = table.Column(nullable: false), - DashboardTheme = table.Column(maxLength: 32, nullable: true), - TvHome = table.Column(maxLength: 32, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_DisplayPreferences", x => x.Id); - table.ForeignKey( - name: "FK_DisplayPreferences_Users_UserId", - column: x => x.UserId, - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "ItemDisplayPreferences", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - UserId = table.Column(nullable: false), - ItemId = table.Column(nullable: false), - Client = table.Column(maxLength: 32, nullable: false), - ViewType = table.Column(nullable: false), - RememberIndexing = table.Column(nullable: false), - IndexBy = table.Column(nullable: true), - RememberSorting = table.Column(nullable: false), - SortBy = table.Column(maxLength: 64, nullable: false), - SortOrder = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_ItemDisplayPreferences", x => x.Id); - table.ForeignKey( - name: "FK_ItemDisplayPreferences_Users_UserId", - column: x => x.UserId, - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "HomeSection", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - DisplayPreferencesId = table.Column(nullable: false), - Order = table.Column(nullable: false), - Type = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_HomeSection", x => x.Id); - table.ForeignKey( - name: "FK_HomeSection_DisplayPreferences_DisplayPreferencesId", - column: x => x.DisplayPreferencesId, - principalSchema: "jellyfin", - principalTable: "DisplayPreferences", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_DisplayPreferences_UserId", - schema: "jellyfin", - table: "DisplayPreferences", - column: "UserId", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_HomeSection_DisplayPreferencesId", - schema: "jellyfin", - table: "HomeSection", - column: "DisplayPreferencesId"); - - migrationBuilder.CreateIndex( - name: "IX_ItemDisplayPreferences_UserId", - schema: "jellyfin", - table: "ItemDisplayPreferences", - column: "UserId"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "HomeSection", - schema: "jellyfin"); - - migrationBuilder.DropTable( - name: "ItemDisplayPreferences", - schema: "jellyfin"); - - migrationBuilder.DropTable( - name: "DisplayPreferences", - schema: "jellyfin"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs deleted file mode 100644 index 1134f7aa4..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs +++ /dev/null @@ -1,461 +0,0 @@ -#pragma warning disable CS1591 - -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20200905220533_FixDisplayPreferencesIndex")] - partial class FixDisplayPreferencesIndex - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "3.1.7"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Overview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(32); - - b.Property("DashboardTheme") - .HasColumnType("TEXT") - .HasMaxLength(32); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasColumnType("TEXT") - .HasMaxLength(32); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.HasIndex("UserId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(32); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(64); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("Permission_Permissions_Guid"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.HasKey("Id"); - - b.HasIndex("Preference_Preferences_Guid"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EasyPassword") - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.HasKey("Id"); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("DisplayPreferences") - .HasForeignKey("Jellyfin.Data.Entities.DisplayPreferences", "UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("Permission_Permissions_Guid"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("Preference_Preferences_Guid"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.cs b/Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.cs deleted file mode 100644 index 91d2b190d..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.cs +++ /dev/null @@ -1,51 +0,0 @@ -#pragma warning disable CS1591 -#pragma warning disable SA1601 - -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Jellyfin.Server.Implementations.Migrations -{ - public partial class FixDisplayPreferencesIndex : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_DisplayPreferences_UserId", - schema: "jellyfin", - table: "DisplayPreferences"); - - migrationBuilder.CreateIndex( - name: "IX_DisplayPreferences_UserId", - schema: "jellyfin", - table: "DisplayPreferences", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_DisplayPreferences_UserId_Client", - schema: "jellyfin", - table: "DisplayPreferences", - columns: new[] { "UserId", "Client" }, - unique: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_DisplayPreferences_UserId", - schema: "jellyfin", - table: "DisplayPreferences"); - - migrationBuilder.DropIndex( - name: "IX_DisplayPreferences_UserId_Client", - schema: "jellyfin", - table: "DisplayPreferences"); - - migrationBuilder.CreateIndex( - name: "IX_DisplayPreferences_UserId", - schema: "jellyfin", - table: "DisplayPreferences", - column: "UserId", - unique: true); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs deleted file mode 100644 index 607310caa..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs +++ /dev/null @@ -1,464 +0,0 @@ -#pragma warning disable CS1591 - -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20201004171403_AddMaxActiveSessions")] - partial class AddMaxActiveSessions - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "3.1.8"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Overview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(32); - - b.Property("DashboardTheme") - .HasColumnType("TEXT") - .HasMaxLength(32); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasColumnType("TEXT") - .HasMaxLength(32); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.HasIndex("UserId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(32); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(64); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("Permission_Permissions_Guid"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.HasKey("Id"); - - b.HasIndex("Preference_Preferences_Guid"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EasyPassword") - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.HasKey("Id"); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("DisplayPreferences") - .HasForeignKey("Jellyfin.Data.Entities.DisplayPreferences", "UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("Permission_Permissions_Guid"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("Preference_Preferences_Guid"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.cs b/Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.cs deleted file mode 100644 index e37b4e696..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.cs +++ /dev/null @@ -1,28 +0,0 @@ -#pragma warning disable CS1591 -#pragma warning disable SA1601 - -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Jellyfin.Server.Implementations.Migrations -{ - public partial class AddMaxActiveSessions : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "MaxActiveSessions", - schema: "jellyfin", - table: "Users", - nullable: false, - defaultValue: 0); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "MaxActiveSessions", - schema: "jellyfin", - table: "Users"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs deleted file mode 100644 index 02c3fc753..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs +++ /dev/null @@ -1,522 +0,0 @@ -#pragma warning disable CS1591 -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20201204223655_AddCustomDisplayPreferences")] - partial class AddCustomDisplayPreferences - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "5.0.0"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("Permission_Permissions_Guid"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("Preference_Preferences_Guid"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EasyPassword") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("DisplayPreferences") - .HasForeignKey("Jellyfin.Data.Entities.DisplayPreferences", "UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("Permission_Permissions_Guid"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("Preference_Preferences_Guid"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences") - .IsRequired(); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20201204223655_AddCustomDisplayPreferences.cs b/Jellyfin.Server.Implementations/Migrations/20201204223655_AddCustomDisplayPreferences.cs deleted file mode 100644 index ce2b21d0c..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20201204223655_AddCustomDisplayPreferences.cs +++ /dev/null @@ -1,108 +0,0 @@ -#pragma warning disable CS1591 -// -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Jellyfin.Server.Implementations.Migrations -{ - public partial class AddCustomDisplayPreferences : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_DisplayPreferences_UserId_Client", - schema: "jellyfin", - table: "DisplayPreferences"); - - migrationBuilder.AlterColumn( - name: "MaxActiveSessions", - schema: "jellyfin", - table: "Users", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AddColumn( - name: "ItemId", - schema: "jellyfin", - table: "DisplayPreferences", - type: "TEXT", - nullable: false, - defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); - - migrationBuilder.CreateTable( - name: "CustomItemDisplayPreferences", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - UserId = table.Column(type: "TEXT", nullable: false), - ItemId = table.Column(type: "TEXT", nullable: false), - Client = table.Column(type: "TEXT", maxLength: 32, nullable: false), - Key = table.Column(type: "TEXT", nullable: false), - Value = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_CustomItemDisplayPreferences", x => x.Id); - }); - - migrationBuilder.CreateIndex( - name: "IX_DisplayPreferences_UserId_ItemId_Client", - schema: "jellyfin", - table: "DisplayPreferences", - columns: new[] { "UserId", "ItemId", "Client" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_CustomItemDisplayPreferences_UserId", - schema: "jellyfin", - table: "CustomItemDisplayPreferences", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_CustomItemDisplayPreferences_UserId_ItemId_Client_Key", - schema: "jellyfin", - table: "CustomItemDisplayPreferences", - columns: new[] { "UserId", "ItemId", "Client", "Key" }, - unique: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "CustomItemDisplayPreferences", - schema: "jellyfin"); - - migrationBuilder.DropIndex( - name: "IX_DisplayPreferences_UserId_ItemId_Client", - schema: "jellyfin", - table: "DisplayPreferences"); - - migrationBuilder.DropColumn( - name: "ItemId", - schema: "jellyfin", - table: "DisplayPreferences"); - - migrationBuilder.AlterColumn( - name: "MaxActiveSessions", - schema: "jellyfin", - table: "Users", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.CreateIndex( - name: "IX_DisplayPreferences_UserId_Client", - schema: "jellyfin", - table: "DisplayPreferences", - columns: new[] { "UserId", "Client" }, - unique: true); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs deleted file mode 100644 index 1cfd7112c..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs +++ /dev/null @@ -1,535 +0,0 @@ -#pragma warning disable CS1591 - -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20210320181425_AddIndexesAndCollations")] - partial class AddIndexesAndCollations - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "5.0.3"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EasyPassword") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.cs b/Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.cs deleted file mode 100644 index 3acd5e7b5..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.cs +++ /dev/null @@ -1,240 +0,0 @@ -#pragma warning disable CS1591 -#pragma warning disable SA1601 - -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Jellyfin.Server.Implementations.Migrations -{ - public partial class AddIndexesAndCollations : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_ImageInfos_Users_UserId", - schema: "jellyfin", - table: "ImageInfos"); - - migrationBuilder.DropForeignKey( - name: "FK_Permissions_Users_Permission_Permissions_Guid", - schema: "jellyfin", - table: "Permissions"); - - migrationBuilder.DropForeignKey( - name: "FK_Preferences_Users_Preference_Preferences_Guid", - schema: "jellyfin", - table: "Preferences"); - - migrationBuilder.DropIndex( - name: "IX_Preferences_Preference_Preferences_Guid", - schema: "jellyfin", - table: "Preferences"); - - migrationBuilder.DropIndex( - name: "IX_Permissions_Permission_Permissions_Guid", - schema: "jellyfin", - table: "Permissions"); - - migrationBuilder.DropIndex( - name: "IX_DisplayPreferences_UserId", - schema: "jellyfin", - table: "DisplayPreferences"); - - migrationBuilder.DropIndex( - name: "IX_CustomItemDisplayPreferences_UserId", - schema: "jellyfin", - table: "CustomItemDisplayPreferences"); - - migrationBuilder.AlterColumn( - name: "Username", - schema: "jellyfin", - table: "Users", - type: "TEXT", - maxLength: 255, - nullable: false, - collation: "NOCASE", - oldClrType: typeof(string), - oldType: "TEXT", - oldMaxLength: 255); - - migrationBuilder.AddColumn( - name: "UserId", - schema: "jellyfin", - table: "Preferences", - type: "TEXT", - nullable: true); - - migrationBuilder.AddColumn( - name: "UserId", - schema: "jellyfin", - table: "Permissions", - type: "TEXT", - nullable: true); - - migrationBuilder.Sql("UPDATE Preferences SET UserId = Preference_Preferences_Guid"); - migrationBuilder.Sql("UPDATE Permissions SET UserId = Permission_Permissions_Guid"); - - migrationBuilder.CreateIndex( - name: "IX_Users_Username", - schema: "jellyfin", - table: "Users", - column: "Username", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Preferences_UserId_Kind", - schema: "jellyfin", - table: "Preferences", - columns: new[] { "UserId", "Kind" }, - unique: true, - filter: "[UserId] IS NOT NULL"); - - migrationBuilder.CreateIndex( - name: "IX_Permissions_UserId_Kind", - schema: "jellyfin", - table: "Permissions", - columns: new[] { "UserId", "Kind" }, - unique: true, - filter: "[UserId] IS NOT NULL"); - - migrationBuilder.AddForeignKey( - name: "FK_ImageInfos_Users_UserId", - schema: "jellyfin", - table: "ImageInfos", - column: "UserId", - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Permissions_Users_UserId", - schema: "jellyfin", - table: "Permissions", - column: "UserId", - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Preferences_Users_UserId", - schema: "jellyfin", - table: "Preferences", - column: "UserId", - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_ImageInfos_Users_UserId", - schema: "jellyfin", - table: "ImageInfos"); - - migrationBuilder.DropForeignKey( - name: "FK_Permissions_Users_UserId", - schema: "jellyfin", - table: "Permissions"); - - migrationBuilder.DropForeignKey( - name: "FK_Preferences_Users_UserId", - schema: "jellyfin", - table: "Preferences"); - - migrationBuilder.DropIndex( - name: "IX_Users_Username", - schema: "jellyfin", - table: "Users"); - - migrationBuilder.DropIndex( - name: "IX_Preferences_UserId_Kind", - schema: "jellyfin", - table: "Preferences"); - - migrationBuilder.DropIndex( - name: "IX_Permissions_UserId_Kind", - schema: "jellyfin", - table: "Permissions"); - - migrationBuilder.DropColumn( - name: "UserId", - schema: "jellyfin", - table: "Preferences"); - - migrationBuilder.DropColumn( - name: "UserId", - schema: "jellyfin", - table: "Permissions"); - - migrationBuilder.AlterColumn( - name: "Username", - schema: "jellyfin", - table: "Users", - type: "TEXT", - maxLength: 255, - nullable: false, - oldClrType: typeof(string), - oldType: "TEXT", - oldMaxLength: 255, - oldCollation: "NOCASE"); - - migrationBuilder.CreateIndex( - name: "IX_Preferences_Preference_Preferences_Guid", - schema: "jellyfin", - table: "Preferences", - column: "Preference_Preferences_Guid"); - - migrationBuilder.CreateIndex( - name: "IX_Permissions_Permission_Permissions_Guid", - schema: "jellyfin", - table: "Permissions", - column: "Permission_Permissions_Guid"); - - migrationBuilder.CreateIndex( - name: "IX_DisplayPreferences_UserId", - schema: "jellyfin", - table: "DisplayPreferences", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_CustomItemDisplayPreferences_UserId", - schema: "jellyfin", - table: "CustomItemDisplayPreferences", - column: "UserId"); - - migrationBuilder.AddForeignKey( - name: "FK_ImageInfos_Users_UserId", - schema: "jellyfin", - table: "ImageInfos", - column: "UserId", - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - - migrationBuilder.AddForeignKey( - name: "FK_Permissions_Users_Permission_Permissions_Guid", - schema: "jellyfin", - table: "Permissions", - column: "Permission_Permissions_Guid", - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - - migrationBuilder.AddForeignKey( - name: "FK_Preferences_Users_Preference_Preferences_Guid", - schema: "jellyfin", - table: "Preferences", - column: "Preference_Preferences_Guid", - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs deleted file mode 100644 index ecf7af495..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs +++ /dev/null @@ -1,520 +0,0 @@ -#pragma warning disable CS1591 -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20210407110544_NullableCustomPrefValue")] - partial class NullableCustomPrefValue - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "5.0.3"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("Permission_Permissions_Guid"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("Preference_Preferences_Guid"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EasyPassword") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("Permission_Permissions_Guid"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("Preference_Preferences_Guid"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20210407110544_NullableCustomPrefValue.cs b/Jellyfin.Server.Implementations/Migrations/20210407110544_NullableCustomPrefValue.cs deleted file mode 100644 index a6b169a61..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20210407110544_NullableCustomPrefValue.cs +++ /dev/null @@ -1,35 +0,0 @@ -#pragma warning disable CS1591 -// -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Jellyfin.Server.Implementations.Migrations -{ - public partial class NullableCustomPrefValue : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "Value", - schema: "jellyfin", - table: "CustomItemDisplayPreferences", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "Value", - schema: "jellyfin", - table: "CustomItemDisplayPreferences", - type: "TEXT", - nullable: false, - defaultValue: "", - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20210814002109_AddDevices.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20210814002109_AddDevices.Designer.cs deleted file mode 100644 index dccba6f77..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20210814002109_AddDevices.Designer.cs +++ /dev/null @@ -1,653 +0,0 @@ -#pragma warning disable CS1591 - -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20210814002109_AddDevices")] - partial class AddDevices - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "5.0.7"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EasyPassword") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20210814002109_AddDevices.cs b/Jellyfin.Server.Implementations/Migrations/20210814002109_AddDevices.cs deleted file mode 100644 index bf90044cb..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20210814002109_AddDevices.cs +++ /dev/null @@ -1,128 +0,0 @@ -#pragma warning disable CS1591, SA1601 - -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Jellyfin.Server.Implementations.Migrations -{ - public partial class AddDevices : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "ApiKeys", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - DateCreated = table.Column(type: "TEXT", nullable: false), - DateLastActivity = table.Column(type: "TEXT", nullable: false), - Name = table.Column(type: "TEXT", maxLength: 64, nullable: false), - AccessToken = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_ApiKeys", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "DeviceOptions", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - DeviceId = table.Column(type: "TEXT", nullable: false), - CustomName = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_DeviceOptions", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "Devices", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - UserId = table.Column(type: "TEXT", nullable: false), - AccessToken = table.Column(type: "TEXT", nullable: false), - AppName = table.Column(type: "TEXT", maxLength: 64, nullable: false), - AppVersion = table.Column(type: "TEXT", maxLength: 32, nullable: false), - DeviceName = table.Column(type: "TEXT", maxLength: 64, nullable: false), - DeviceId = table.Column(type: "TEXT", maxLength: 256, nullable: false), - IsActive = table.Column(type: "INTEGER", nullable: false), - DateCreated = table.Column(type: "TEXT", nullable: false), - DateModified = table.Column(type: "TEXT", nullable: false), - DateLastActivity = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Devices", x => x.Id); - table.ForeignKey( - name: "FK_Devices_Users_UserId", - column: x => x.UserId, - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_ApiKeys_AccessToken", - schema: "jellyfin", - table: "ApiKeys", - column: "AccessToken", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_DeviceOptions_DeviceId", - schema: "jellyfin", - table: "DeviceOptions", - column: "DeviceId", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Devices_AccessToken_DateLastActivity", - schema: "jellyfin", - table: "Devices", - columns: new[] { "AccessToken", "DateLastActivity" }); - - migrationBuilder.CreateIndex( - name: "IX_Devices_DeviceId", - schema: "jellyfin", - table: "Devices", - column: "DeviceId"); - - migrationBuilder.CreateIndex( - name: "IX_Devices_DeviceId_DateLastActivity", - schema: "jellyfin", - table: "Devices", - columns: new[] { "DeviceId", "DateLastActivity" }); - - migrationBuilder.CreateIndex( - name: "IX_Devices_UserId_DeviceId", - schema: "jellyfin", - table: "Devices", - columns: new[] { "UserId", "DeviceId" }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "ApiKeys", - schema: "jellyfin"); - - migrationBuilder.DropTable( - name: "DeviceOptions", - schema: "jellyfin"); - - migrationBuilder.DropTable( - name: "Devices", - schema: "jellyfin"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs deleted file mode 100644 index e821c106e..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs +++ /dev/null @@ -1,657 +0,0 @@ -#pragma warning disable CS1591 - -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20221022080052_AddIndexActivityLogsDateCreated")] - partial class AddIndexActivityLogsDateCreated - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "6.0.9"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules", "jellyfin"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs", "jellyfin"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences", "jellyfin"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences", "jellyfin"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection", "jellyfin"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos", "jellyfin"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences", "jellyfin"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions", "jellyfin"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences", "jellyfin"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys", "jellyfin"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices", "jellyfin"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions", "jellyfin"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EasyPassword") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users", "jellyfin"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20221022080052_AddIndexActivityLogsDateCreated.cs b/Jellyfin.Server.Implementations/Migrations/20221022080052_AddIndexActivityLogsDateCreated.cs deleted file mode 100644 index 9d5d7632b..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20221022080052_AddIndexActivityLogsDateCreated.cs +++ /dev/null @@ -1,28 +0,0 @@ -#pragma warning disable CS1591, SA1601 - -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - public partial class AddIndexActivityLogsDateCreated : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateIndex( - name: "IX_ActivityLogs_DateCreated", - schema: "jellyfin", - table: "ActivityLogs", - column: "DateCreated"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_ActivityLogs_DateCreated", - schema: "jellyfin", - table: "ActivityLogs"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.Designer.cs deleted file mode 100644 index 360fa0376..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.Designer.cs +++ /dev/null @@ -1,650 +0,0 @@ -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20230526173516_RemoveEasyPassword")] - partial class RemoveEasyPassword - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "7.0.5"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.cs b/Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.cs deleted file mode 100644 index 354d91c38..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.cs +++ /dev/null @@ -1,164 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - /// - public partial class RemoveEasyPassword : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "EasyPassword", - schema: "jellyfin", - table: "Users"); - - migrationBuilder.RenameTable( - name: "Users", - schema: "jellyfin", - newName: "Users"); - - migrationBuilder.RenameTable( - name: "Preferences", - schema: "jellyfin", - newName: "Preferences"); - - migrationBuilder.RenameTable( - name: "Permissions", - schema: "jellyfin", - newName: "Permissions"); - - migrationBuilder.RenameTable( - name: "ItemDisplayPreferences", - schema: "jellyfin", - newName: "ItemDisplayPreferences"); - - migrationBuilder.RenameTable( - name: "ImageInfos", - schema: "jellyfin", - newName: "ImageInfos"); - - migrationBuilder.RenameTable( - name: "HomeSection", - schema: "jellyfin", - newName: "HomeSection"); - - migrationBuilder.RenameTable( - name: "DisplayPreferences", - schema: "jellyfin", - newName: "DisplayPreferences"); - - migrationBuilder.RenameTable( - name: "Devices", - schema: "jellyfin", - newName: "Devices"); - - migrationBuilder.RenameTable( - name: "DeviceOptions", - schema: "jellyfin", - newName: "DeviceOptions"); - - migrationBuilder.RenameTable( - name: "CustomItemDisplayPreferences", - schema: "jellyfin", - newName: "CustomItemDisplayPreferences"); - - migrationBuilder.RenameTable( - name: "ApiKeys", - schema: "jellyfin", - newName: "ApiKeys"); - - migrationBuilder.RenameTable( - name: "ActivityLogs", - schema: "jellyfin", - newName: "ActivityLogs"); - - migrationBuilder.RenameTable( - name: "AccessSchedules", - schema: "jellyfin", - newName: "AccessSchedules"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.EnsureSchema( - name: "jellyfin"); - - migrationBuilder.RenameTable( - name: "Users", - newName: "Users", - newSchema: "jellyfin"); - - migrationBuilder.RenameTable( - name: "Preferences", - newName: "Preferences", - newSchema: "jellyfin"); - - migrationBuilder.RenameTable( - name: "Permissions", - newName: "Permissions", - newSchema: "jellyfin"); - - migrationBuilder.RenameTable( - name: "ItemDisplayPreferences", - newName: "ItemDisplayPreferences", - newSchema: "jellyfin"); - - migrationBuilder.RenameTable( - name: "ImageInfos", - newName: "ImageInfos", - newSchema: "jellyfin"); - - migrationBuilder.RenameTable( - name: "HomeSection", - newName: "HomeSection", - newSchema: "jellyfin"); - - migrationBuilder.RenameTable( - name: "DisplayPreferences", - newName: "DisplayPreferences", - newSchema: "jellyfin"); - - migrationBuilder.RenameTable( - name: "Devices", - newName: "Devices", - newSchema: "jellyfin"); - - migrationBuilder.RenameTable( - name: "DeviceOptions", - newName: "DeviceOptions", - newSchema: "jellyfin"); - - migrationBuilder.RenameTable( - name: "CustomItemDisplayPreferences", - newName: "CustomItemDisplayPreferences", - newSchema: "jellyfin"); - - migrationBuilder.RenameTable( - name: "ApiKeys", - newName: "ApiKeys", - newSchema: "jellyfin"); - - migrationBuilder.RenameTable( - name: "ActivityLogs", - newName: "ActivityLogs", - newSchema: "jellyfin"); - - migrationBuilder.RenameTable( - name: "AccessSchedules", - newName: "AccessSchedules", - newSchema: "jellyfin"); - - migrationBuilder.AddColumn( - name: "EasyPassword", - schema: "jellyfin", - table: "Users", - type: "TEXT", - maxLength: 65535, - nullable: true); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20230626233818_AddTrickplayInfos.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20230626233818_AddTrickplayInfos.Designer.cs deleted file mode 100644 index 17d33845f..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20230626233818_AddTrickplayInfos.Designer.cs +++ /dev/null @@ -1,681 +0,0 @@ -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20230626233818_AddTrickplayInfos")] - partial class AddTrickplayInfos - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "7.0.7"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.Property("Bandwidth") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("Interval") - .HasColumnType("INTEGER"); - - b.Property("ThumbnailCount") - .HasColumnType("INTEGER"); - - b.Property("TileHeight") - .HasColumnType("INTEGER"); - - b.Property("TileWidth") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "Width"); - - b.ToTable("TrickplayInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20230626233818_AddTrickplayInfos.cs b/Jellyfin.Server.Implementations/Migrations/20230626233818_AddTrickplayInfos.cs deleted file mode 100644 index 85f1b5b7d..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20230626233818_AddTrickplayInfos.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - /// - public partial class AddTrickplayInfos : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "TrickplayInfos", - columns: table => new - { - ItemId = table.Column(type: "TEXT", nullable: false), - Width = table.Column(type: "INTEGER", nullable: false), - Height = table.Column(type: "INTEGER", nullable: false), - TileWidth = table.Column(type: "INTEGER", nullable: false), - TileHeight = table.Column(type: "INTEGER", nullable: false), - ThumbnailCount = table.Column(type: "INTEGER", nullable: false), - Interval = table.Column(type: "INTEGER", nullable: false), - Bandwidth = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_TrickplayInfos", x => new { x.ItemId, x.Width }); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "TrickplayInfos"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20230923170422_UserCastReceiver.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20230923170422_UserCastReceiver.Designer.cs deleted file mode 100644 index 4c0917669..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20230923170422_UserCastReceiver.Designer.cs +++ /dev/null @@ -1,654 +0,0 @@ -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20230923170422_UserCastReceiver")] - partial class UserCastReceiver - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "7.0.11"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("CastReceiverId") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20230923170422_UserCastReceiver.cs b/Jellyfin.Server.Implementations/Migrations/20230923170422_UserCastReceiver.cs deleted file mode 100644 index 5919e4665..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20230923170422_UserCastReceiver.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - /// - public partial class UserCastReceiver : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "CastReceiverId", - table: "Users", - type: "TEXT", - maxLength: 32, - nullable: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "CastReceiverId", - table: "Users"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20240729140605_AddMediaSegments.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20240729140605_AddMediaSegments.Designer.cs deleted file mode 100644 index 35a3cdad2..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20240729140605_AddMediaSegments.Designer.cs +++ /dev/null @@ -1,708 +0,0 @@ -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20240729140605_AddMediaSegments")] - partial class AddMediaSegments - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.7"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("EndTicks") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("StartTicks") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("MediaSegments"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.Property("Bandwidth") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("Interval") - .HasColumnType("INTEGER"); - - b.Property("ThumbnailCount") - .HasColumnType("INTEGER"); - - b.Property("TileHeight") - .HasColumnType("INTEGER"); - - b.Property("TileWidth") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "Width"); - - b.ToTable("TrickplayInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("CastReceiverId") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20240729140605_AddMediaSegments.cs b/Jellyfin.Server.Implementations/Migrations/20240729140605_AddMediaSegments.cs deleted file mode 100644 index 18164d999..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20240729140605_AddMediaSegments.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - /// - public partial class AddMediaSegments : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "MediaSegments", - columns: table => new - { - Id = table.Column(type: "TEXT", nullable: false), - ItemId = table.Column(type: "TEXT", nullable: false), - Type = table.Column(type: "INTEGER", nullable: false), - EndTicks = table.Column(type: "INTEGER", nullable: false), - StartTicks = table.Column(type: "INTEGER", nullable: false), - SegmentProviderId = table.Column(type: "TEXT", nullable: false), - }, - constraints: table => - { - table.PrimaryKey("PK_MediaSegments", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "MediaSegments"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs deleted file mode 100644 index 8dba31a67..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs +++ /dev/null @@ -1,712 +0,0 @@ -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20240928082930_MarkSegmentProviderIdNonNullable")] - partial class MarkSegmentProviderIdNonNullable - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.8"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("EndTicks") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("SegmentProviderId") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("StartTicks") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("MediaSegments"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.Property("Bandwidth") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("Interval") - .HasColumnType("INTEGER"); - - b.Property("ThumbnailCount") - .HasColumnType("INTEGER"); - - b.Property("TileHeight") - .HasColumnType("INTEGER"); - - b.Property("TileWidth") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "Width"); - - b.ToTable("TrickplayInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("CastReceiverId") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.cs b/Jellyfin.Server.Implementations/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.cs deleted file mode 100644 index 55b90a54d..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - /// - public partial class MarkSegmentProviderIdNonNullable : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "SegmentProviderId", - table: "MediaSegments", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "SegmentProviderId", - table: "MediaSegments", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241020103111_LibraryDbMigration.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20241020103111_LibraryDbMigration.Designer.cs deleted file mode 100644 index 27745f601..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241020103111_LibraryDbMigration.Designer.cs +++ /dev/null @@ -1,1607 +0,0 @@ -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20241020103111_LibraryDbMigration")] - partial class LibraryDbMigration - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ParentItemId") - .HasColumnType("TEXT"); - - b.Property("BaseItemEntityId") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ParentItemId"); - - b.HasIndex("BaseItemEntityId"); - - b.HasIndex("ParentItemId"); - - b.ToTable("AncestorIds"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Index") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .HasColumnType("TEXT"); - - b.Property("Comment") - .HasColumnType("TEXT"); - - b.Property("Filename") - .HasColumnType("TEXT"); - - b.Property("MimeType") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "Index"); - - b.ToTable("AttachmentStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Album") - .HasColumnType("TEXT"); - - b.Property("AlbumArtists") - .HasColumnType("TEXT"); - - b.Property("Artists") - .HasColumnType("TEXT"); - - b.Property("Audio") - .HasColumnType("INTEGER"); - - b.Property("ChannelId") - .HasColumnType("TEXT"); - - b.Property("CleanName") - .HasColumnType("TEXT"); - - b.Property("CommunityRating") - .HasColumnType("REAL"); - - b.Property("CriticRating") - .HasColumnType("REAL"); - - b.Property("CustomRating") - .HasColumnType("TEXT"); - - b.Property("Data") - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastMediaAdded") - .HasColumnType("TEXT"); - - b.Property("DateLastRefreshed") - .HasColumnType("TEXT"); - - b.Property("DateLastSaved") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("EndDate") - .HasColumnType("TEXT"); - - b.Property("EpisodeTitle") - .HasColumnType("TEXT"); - - b.Property("ExternalId") - .HasColumnType("TEXT"); - - b.Property("ExternalSeriesId") - .HasColumnType("TEXT"); - - b.Property("ExternalServiceId") - .HasColumnType("TEXT"); - - b.Property("ExtraIds") - .HasColumnType("TEXT"); - - b.Property("ExtraType") - .HasColumnType("INTEGER"); - - b.Property("ForcedSortName") - .HasColumnType("TEXT"); - - b.Property("Genres") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IndexNumber") - .HasColumnType("INTEGER"); - - b.Property("InheritedParentalRatingValue") - .HasColumnType("INTEGER"); - - b.Property("IsFolder") - .HasColumnType("INTEGER"); - - b.Property("IsInMixedFolder") - .HasColumnType("INTEGER"); - - b.Property("IsLocked") - .HasColumnType("INTEGER"); - - b.Property("IsMovie") - .HasColumnType("INTEGER"); - - b.Property("IsRepeat") - .HasColumnType("INTEGER"); - - b.Property("IsSeries") - .HasColumnType("INTEGER"); - - b.Property("IsVirtualItem") - .HasColumnType("INTEGER"); - - b.Property("LUFS") - .HasColumnType("REAL"); - - b.Property("MediaType") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("NormalizationGain") - .HasColumnType("REAL"); - - b.Property("OfficialRating") - .HasColumnType("TEXT"); - - b.Property("OriginalTitle") - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasColumnType("TEXT"); - - b.Property("OwnerId") - .HasColumnType("TEXT"); - - b.Property("ParentId") - .HasColumnType("TEXT"); - - b.Property("ParentIndexNumber") - .HasColumnType("INTEGER"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataCountryCode") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataLanguage") - .HasColumnType("TEXT"); - - b.Property("PremiereDate") - .HasColumnType("TEXT"); - - b.Property("PresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("PrimaryVersionId") - .HasColumnType("TEXT"); - - b.Property("ProductionLocations") - .HasColumnType("TEXT"); - - b.Property("ProductionYear") - .HasColumnType("INTEGER"); - - b.Property("RunTimeTicks") - .HasColumnType("INTEGER"); - - b.Property("SeasonId") - .HasColumnType("TEXT"); - - b.Property("SeasonName") - .HasColumnType("TEXT"); - - b.Property("SeriesId") - .HasColumnType("TEXT"); - - b.Property("SeriesName") - .HasColumnType("TEXT"); - - b.Property("SeriesPresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("ShowId") - .HasColumnType("TEXT"); - - b.Property("Size") - .HasColumnType("INTEGER"); - - b.Property("SortName") - .HasColumnType("TEXT"); - - b.Property("StartDate") - .HasColumnType("TEXT"); - - b.Property("Studios") - .HasColumnType("TEXT"); - - b.Property("Tagline") - .HasColumnType("TEXT"); - - b.Property("Tags") - .HasColumnType("TEXT"); - - b.Property("TopParentId") - .HasColumnType("TEXT"); - - b.Property("TotalBitrate") - .HasColumnType("INTEGER"); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UnratedType") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ParentId"); - - b.HasIndex("Path"); - - b.HasIndex("PresentationUniqueKey"); - - b.HasIndex("TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); - - b.HasIndex("Type", "TopParentId", "StartDate"); - - b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); - - b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); - - b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.ToTable("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Blurhash") - .HasColumnType("BLOB"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("ImageType") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemMetadataFields"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ProviderId") - .HasColumnType("TEXT"); - - b.Property("ProviderValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ProviderId"); - - b.HasIndex("ProviderId", "ProviderValue", "ItemId"); - - b.ToTable("BaseItemProviders"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemTrailerTypes"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ChapterIndex") - .HasColumnType("INTEGER"); - - b.Property("ImageDateModified") - .HasColumnType("TEXT"); - - b.Property("ImagePath") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("StartPositionTicks") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "ChapterIndex"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Property("ItemValueId") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("CleanValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId"); - - b.HasIndex("Type", "CleanValue"); - - b.ToTable("ItemValues"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.Property("ItemValueId") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("ItemValuesMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("EndTicks") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("SegmentProviderId") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("StartTicks") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("MediaSegments"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("StreamIndex") - .HasColumnType("INTEGER"); - - b.Property("AspectRatio") - .HasColumnType("TEXT"); - - b.Property("AverageFrameRate") - .HasColumnType("REAL"); - - b.Property("BitDepth") - .HasColumnType("INTEGER"); - - b.Property("BitRate") - .HasColumnType("INTEGER"); - - b.Property("BlPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("ChannelLayout") - .HasColumnType("TEXT"); - - b.Property("Channels") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("CodecTimeBase") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("ColorPrimaries") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("ColorSpace") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("ColorTransfer") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Comment") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DvBlSignalCompatibilityId") - .HasColumnType("INTEGER"); - - b.Property("DvLevel") - .HasColumnType("INTEGER"); - - b.Property("DvProfile") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMajor") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMinor") - .HasColumnType("INTEGER"); - - b.Property("ElPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IsAnamorphic") - .HasColumnType("INTEGER"); - - b.Property("IsAvc") - .HasColumnType("INTEGER"); - - b.Property("IsDefault") - .HasColumnType("INTEGER"); - - b.Property("IsExternal") - .HasColumnType("INTEGER"); - - b.Property("IsForced") - .HasColumnType("INTEGER"); - - b.Property("IsHearingImpaired") - .HasColumnType("INTEGER"); - - b.Property("IsInterlaced") - .HasColumnType("INTEGER"); - - b.Property("KeyFrames") - .HasColumnType("TEXT"); - - b.Property("Language") - .HasColumnType("TEXT"); - - b.Property("Level") - .HasColumnType("REAL"); - - b.Property("NalLengthSize") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PixelFormat") - .HasColumnType("TEXT"); - - b.Property("Profile") - .HasColumnType("TEXT"); - - b.Property("RealFrameRate") - .HasColumnType("REAL"); - - b.Property("RefFrames") - .HasColumnType("INTEGER"); - - b.Property("Rotation") - .HasColumnType("INTEGER"); - - b.Property("RpuPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("SampleRate") - .HasColumnType("INTEGER"); - - b.Property("StreamType") - .HasColumnType("INTEGER"); - - b.Property("TimeBase") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Title") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "StreamIndex"); - - b.HasIndex("StreamIndex"); - - b.HasIndex("StreamType"); - - b.HasIndex("StreamIndex", "StreamType"); - - b.HasIndex("StreamIndex", "StreamType", "Language"); - - b.ToTable("MediaStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("PersonType") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("Name"); - - b.ToTable("Peoples"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("PeopleId") - .HasColumnType("TEXT"); - - b.Property("ListOrder") - .HasColumnType("INTEGER"); - - b.Property("Role") - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "PeopleId"); - - b.HasIndex("PeopleId"); - - b.HasIndex("ItemId", "ListOrder"); - - b.HasIndex("ItemId", "SortOrder"); - - b.ToTable("PeopleBaseItemMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.Property("Bandwidth") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("Interval") - .HasColumnType("INTEGER"); - - b.Property("ThumbnailCount") - .HasColumnType("INTEGER"); - - b.Property("TileHeight") - .HasColumnType("INTEGER"); - - b.Property("TileWidth") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "Width"); - - b.ToTable("TrickplayInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("CastReceiverId") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("AudioStreamIndex") - .HasColumnType("INTEGER"); - - b.Property("IsFavorite") - .HasColumnType("INTEGER"); - - b.Property("LastPlayedDate") - .HasColumnType("TEXT"); - - b.Property("Likes") - .HasColumnType("INTEGER"); - - b.Property("PlayCount") - .HasColumnType("INTEGER"); - - b.Property("PlaybackPositionTicks") - .HasColumnType("INTEGER"); - - b.Property("Played") - .HasColumnType("INTEGER"); - - b.Property("Rating") - .HasColumnType("REAL"); - - b.Property("SubtitleStreamIndex") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "UserId"); - - b.HasIndex("UserId"); - - b.HasIndex("ItemId", "UserId", "IsFavorite"); - - b.HasIndex("ItemId", "UserId", "LastPlayedDate"); - - b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); - - b.HasIndex("ItemId", "UserId", "Played"); - - b.ToTable("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", null) - .WithMany("AncestorIds") - .HasForeignKey("BaseItemEntityId"); - - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany() - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") - .WithMany() - .HasForeignKey("ParentItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ParentItem"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany() - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Images") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("LockedFields") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Provider") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("TrailerTypes") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Chapters") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("ItemValues") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") - .WithMany("BaseItemsMap") - .HasForeignKey("ItemValueId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ItemValue"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("MediaStreams") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Peoples") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.People", "People") - .WithMany("BaseItems") - .HasForeignKey("PeopleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("People"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("UserData") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Navigation("AncestorIds"); - - b.Navigation("Chapters"); - - b.Navigation("Images"); - - b.Navigation("ItemValues"); - - b.Navigation("LockedFields"); - - b.Navigation("MediaStreams"); - - b.Navigation("Peoples"); - - b.Navigation("Provider"); - - b.Navigation("TrailerTypes"); - - b.Navigation("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Navigation("BaseItemsMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Navigation("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241020103111_LibraryDbMigration.cs b/Jellyfin.Server.Implementations/Migrations/20241020103111_LibraryDbMigration.cs deleted file mode 100644 index 8cc7fb452..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241020103111_LibraryDbMigration.cs +++ /dev/null @@ -1,639 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - /// - public partial class LibraryDbMigration : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "BaseItems", - columns: table => new - { - Id = table.Column(type: "TEXT", nullable: false), - Type = table.Column(type: "TEXT", nullable: false), - Data = table.Column(type: "TEXT", nullable: true), - Path = table.Column(type: "TEXT", nullable: true), - StartDate = table.Column(type: "TEXT", nullable: false), - EndDate = table.Column(type: "TEXT", nullable: false), - ChannelId = table.Column(type: "TEXT", nullable: true), - IsMovie = table.Column(type: "INTEGER", nullable: false), - CommunityRating = table.Column(type: "REAL", nullable: true), - CustomRating = table.Column(type: "TEXT", nullable: true), - IndexNumber = table.Column(type: "INTEGER", nullable: true), - IsLocked = table.Column(type: "INTEGER", nullable: false), - Name = table.Column(type: "TEXT", nullable: true), - OfficialRating = table.Column(type: "TEXT", nullable: true), - MediaType = table.Column(type: "TEXT", nullable: true), - Overview = table.Column(type: "TEXT", nullable: true), - ParentIndexNumber = table.Column(type: "INTEGER", nullable: true), - PremiereDate = table.Column(type: "TEXT", nullable: true), - ProductionYear = table.Column(type: "INTEGER", nullable: true), - Genres = table.Column(type: "TEXT", nullable: true), - SortName = table.Column(type: "TEXT", nullable: true), - ForcedSortName = table.Column(type: "TEXT", nullable: true), - RunTimeTicks = table.Column(type: "INTEGER", nullable: true), - DateCreated = table.Column(type: "TEXT", nullable: true), - DateModified = table.Column(type: "TEXT", nullable: true), - IsSeries = table.Column(type: "INTEGER", nullable: false), - EpisodeTitle = table.Column(type: "TEXT", nullable: true), - IsRepeat = table.Column(type: "INTEGER", nullable: false), - PreferredMetadataLanguage = table.Column(type: "TEXT", nullable: true), - PreferredMetadataCountryCode = table.Column(type: "TEXT", nullable: true), - DateLastRefreshed = table.Column(type: "TEXT", nullable: true), - DateLastSaved = table.Column(type: "TEXT", nullable: true), - IsInMixedFolder = table.Column(type: "INTEGER", nullable: false), - Studios = table.Column(type: "TEXT", nullable: true), - ExternalServiceId = table.Column(type: "TEXT", nullable: true), - Tags = table.Column(type: "TEXT", nullable: true), - IsFolder = table.Column(type: "INTEGER", nullable: false), - InheritedParentalRatingValue = table.Column(type: "INTEGER", nullable: true), - UnratedType = table.Column(type: "TEXT", nullable: true), - CriticRating = table.Column(type: "REAL", nullable: true), - CleanName = table.Column(type: "TEXT", nullable: true), - PresentationUniqueKey = table.Column(type: "TEXT", nullable: true), - OriginalTitle = table.Column(type: "TEXT", nullable: true), - PrimaryVersionId = table.Column(type: "TEXT", nullable: true), - DateLastMediaAdded = table.Column(type: "TEXT", nullable: true), - Album = table.Column(type: "TEXT", nullable: true), - LUFS = table.Column(type: "REAL", nullable: true), - NormalizationGain = table.Column(type: "REAL", nullable: true), - IsVirtualItem = table.Column(type: "INTEGER", nullable: false), - SeriesName = table.Column(type: "TEXT", nullable: true), - SeasonName = table.Column(type: "TEXT", nullable: true), - ExternalSeriesId = table.Column(type: "TEXT", nullable: true), - Tagline = table.Column(type: "TEXT", nullable: true), - ProductionLocations = table.Column(type: "TEXT", nullable: true), - ExtraIds = table.Column(type: "TEXT", nullable: true), - TotalBitrate = table.Column(type: "INTEGER", nullable: true), - ExtraType = table.Column(type: "INTEGER", nullable: true), - Artists = table.Column(type: "TEXT", nullable: true), - AlbumArtists = table.Column(type: "TEXT", nullable: true), - ExternalId = table.Column(type: "TEXT", nullable: true), - SeriesPresentationUniqueKey = table.Column(type: "TEXT", nullable: true), - ShowId = table.Column(type: "TEXT", nullable: true), - OwnerId = table.Column(type: "TEXT", nullable: true), - Width = table.Column(type: "INTEGER", nullable: true), - Height = table.Column(type: "INTEGER", nullable: true), - Size = table.Column(type: "INTEGER", nullable: true), - Audio = table.Column(type: "INTEGER", nullable: true), - ParentId = table.Column(type: "TEXT", nullable: true), - TopParentId = table.Column(type: "TEXT", nullable: true), - SeasonId = table.Column(type: "TEXT", nullable: true), - SeriesId = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_BaseItems", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "ItemValues", - columns: table => new - { - ItemValueId = table.Column(type: "TEXT", nullable: false), - Type = table.Column(type: "INTEGER", nullable: false), - Value = table.Column(type: "TEXT", nullable: false), - CleanValue = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_ItemValues", x => x.ItemValueId); - }); - - migrationBuilder.CreateTable( - name: "Peoples", - columns: table => new - { - Id = table.Column(type: "TEXT", nullable: false), - Name = table.Column(type: "TEXT", nullable: false), - PersonType = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Peoples", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AncestorIds", - columns: table => new - { - ParentItemId = table.Column(type: "TEXT", nullable: false), - ItemId = table.Column(type: "TEXT", nullable: false), - BaseItemEntityId = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AncestorIds", x => new { x.ItemId, x.ParentItemId }); - table.ForeignKey( - name: "FK_AncestorIds_BaseItems_BaseItemEntityId", - column: x => x.BaseItemEntityId, - principalTable: "BaseItems", - principalColumn: "Id"); - table.ForeignKey( - name: "FK_AncestorIds_BaseItems_ItemId", - column: x => x.ItemId, - principalTable: "BaseItems", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_AncestorIds_BaseItems_ParentItemId", - column: x => x.ParentItemId, - principalTable: "BaseItems", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AttachmentStreamInfos", - columns: table => new - { - ItemId = table.Column(type: "TEXT", nullable: false), - Index = table.Column(type: "INTEGER", nullable: false), - Codec = table.Column(type: "TEXT", nullable: false), - CodecTag = table.Column(type: "TEXT", nullable: true), - Comment = table.Column(type: "TEXT", nullable: true), - Filename = table.Column(type: "TEXT", nullable: true), - MimeType = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AttachmentStreamInfos", x => new { x.ItemId, x.Index }); - table.ForeignKey( - name: "FK_AttachmentStreamInfos_BaseItems_ItemId", - column: x => x.ItemId, - principalTable: "BaseItems", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "BaseItemImageInfos", - columns: table => new - { - Id = table.Column(type: "TEXT", nullable: false), - Path = table.Column(type: "TEXT", nullable: false), - DateModified = table.Column(type: "TEXT", nullable: false), - ImageType = table.Column(type: "INTEGER", nullable: false), - Width = table.Column(type: "INTEGER", nullable: false), - Height = table.Column(type: "INTEGER", nullable: false), - Blurhash = table.Column(type: "BLOB", nullable: true), - ItemId = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BaseItemImageInfos", x => x.Id); - table.ForeignKey( - name: "FK_BaseItemImageInfos_BaseItems_ItemId", - column: x => x.ItemId, - principalTable: "BaseItems", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "BaseItemMetadataFields", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false), - ItemId = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BaseItemMetadataFields", x => new { x.Id, x.ItemId }); - table.ForeignKey( - name: "FK_BaseItemMetadataFields_BaseItems_ItemId", - column: x => x.ItemId, - principalTable: "BaseItems", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "BaseItemProviders", - columns: table => new - { - ItemId = table.Column(type: "TEXT", nullable: false), - ProviderId = table.Column(type: "TEXT", nullable: false), - ProviderValue = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BaseItemProviders", x => new { x.ItemId, x.ProviderId }); - table.ForeignKey( - name: "FK_BaseItemProviders_BaseItems_ItemId", - column: x => x.ItemId, - principalTable: "BaseItems", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "BaseItemTrailerTypes", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false), - ItemId = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BaseItemTrailerTypes", x => new { x.Id, x.ItemId }); - table.ForeignKey( - name: "FK_BaseItemTrailerTypes_BaseItems_ItemId", - column: x => x.ItemId, - principalTable: "BaseItems", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Chapters", - columns: table => new - { - ItemId = table.Column(type: "TEXT", nullable: false), - ChapterIndex = table.Column(type: "INTEGER", nullable: false), - StartPositionTicks = table.Column(type: "INTEGER", nullable: false), - Name = table.Column(type: "TEXT", nullable: true), - ImagePath = table.Column(type: "TEXT", nullable: true), - ImageDateModified = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Chapters", x => new { x.ItemId, x.ChapterIndex }); - table.ForeignKey( - name: "FK_Chapters_BaseItems_ItemId", - column: x => x.ItemId, - principalTable: "BaseItems", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "MediaStreamInfos", - columns: table => new - { - ItemId = table.Column(type: "TEXT", nullable: false), - StreamIndex = table.Column(type: "INTEGER", nullable: false), - StreamType = table.Column(type: "INTEGER", nullable: true), - Codec = table.Column(type: "TEXT", nullable: true), - Language = table.Column(type: "TEXT", nullable: true), - ChannelLayout = table.Column(type: "TEXT", nullable: true), - Profile = table.Column(type: "TEXT", nullable: true), - AspectRatio = table.Column(type: "TEXT", nullable: true), - Path = table.Column(type: "TEXT", nullable: true), - IsInterlaced = table.Column(type: "INTEGER", nullable: false), - BitRate = table.Column(type: "INTEGER", nullable: false), - Channels = table.Column(type: "INTEGER", nullable: false), - SampleRate = table.Column(type: "INTEGER", nullable: false), - IsDefault = table.Column(type: "INTEGER", nullable: false), - IsForced = table.Column(type: "INTEGER", nullable: false), - IsExternal = table.Column(type: "INTEGER", nullable: false), - Height = table.Column(type: "INTEGER", nullable: false), - Width = table.Column(type: "INTEGER", nullable: false), - AverageFrameRate = table.Column(type: "REAL", nullable: false), - RealFrameRate = table.Column(type: "REAL", nullable: false), - Level = table.Column(type: "REAL", nullable: false), - PixelFormat = table.Column(type: "TEXT", nullable: true), - BitDepth = table.Column(type: "INTEGER", nullable: false), - IsAnamorphic = table.Column(type: "INTEGER", nullable: false), - RefFrames = table.Column(type: "INTEGER", nullable: false), - CodecTag = table.Column(type: "TEXT", nullable: false), - Comment = table.Column(type: "TEXT", nullable: false), - NalLengthSize = table.Column(type: "TEXT", nullable: false), - IsAvc = table.Column(type: "INTEGER", nullable: false), - Title = table.Column(type: "TEXT", nullable: false), - TimeBase = table.Column(type: "TEXT", nullable: false), - CodecTimeBase = table.Column(type: "TEXT", nullable: false), - ColorPrimaries = table.Column(type: "TEXT", nullable: false), - ColorSpace = table.Column(type: "TEXT", nullable: false), - ColorTransfer = table.Column(type: "TEXT", nullable: false), - DvVersionMajor = table.Column(type: "INTEGER", nullable: false), - DvVersionMinor = table.Column(type: "INTEGER", nullable: false), - DvProfile = table.Column(type: "INTEGER", nullable: false), - DvLevel = table.Column(type: "INTEGER", nullable: false), - RpuPresentFlag = table.Column(type: "INTEGER", nullable: false), - ElPresentFlag = table.Column(type: "INTEGER", nullable: false), - BlPresentFlag = table.Column(type: "INTEGER", nullable: false), - DvBlSignalCompatibilityId = table.Column(type: "INTEGER", nullable: false), - IsHearingImpaired = table.Column(type: "INTEGER", nullable: false), - Rotation = table.Column(type: "INTEGER", nullable: false), - KeyFrames = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_MediaStreamInfos", x => new { x.ItemId, x.StreamIndex }); - table.ForeignKey( - name: "FK_MediaStreamInfos_BaseItems_ItemId", - column: x => x.ItemId, - principalTable: "BaseItems", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "UserData", - columns: table => new - { - ItemId = table.Column(type: "TEXT", nullable: false), - UserId = table.Column(type: "TEXT", nullable: false), - Rating = table.Column(type: "REAL", nullable: true), - PlaybackPositionTicks = table.Column(type: "INTEGER", nullable: false), - PlayCount = table.Column(type: "INTEGER", nullable: false), - IsFavorite = table.Column(type: "INTEGER", nullable: false), - LastPlayedDate = table.Column(type: "TEXT", nullable: true), - Played = table.Column(type: "INTEGER", nullable: false), - AudioStreamIndex = table.Column(type: "INTEGER", nullable: true), - SubtitleStreamIndex = table.Column(type: "INTEGER", nullable: true), - Likes = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_UserData", x => new { x.ItemId, x.UserId }); - table.ForeignKey( - name: "FK_UserData_BaseItems_ItemId", - column: x => x.ItemId, - principalTable: "BaseItems", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_UserData_Users_UserId", - column: x => x.UserId, - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "ItemValuesMap", - columns: table => new - { - ItemId = table.Column(type: "TEXT", nullable: false), - ItemValueId = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_ItemValuesMap", x => new { x.ItemValueId, x.ItemId }); - table.ForeignKey( - name: "FK_ItemValuesMap_BaseItems_ItemId", - column: x => x.ItemId, - principalTable: "BaseItems", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_ItemValuesMap_ItemValues_ItemValueId", - column: x => x.ItemValueId, - principalTable: "ItemValues", - principalColumn: "ItemValueId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "PeopleBaseItemMap", - columns: table => new - { - ItemId = table.Column(type: "TEXT", nullable: false), - PeopleId = table.Column(type: "TEXT", nullable: false), - SortOrder = table.Column(type: "INTEGER", nullable: true), - ListOrder = table.Column(type: "INTEGER", nullable: true), - Role = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_PeopleBaseItemMap", x => new { x.ItemId, x.PeopleId }); - table.ForeignKey( - name: "FK_PeopleBaseItemMap_BaseItems_ItemId", - column: x => x.ItemId, - principalTable: "BaseItems", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_PeopleBaseItemMap_Peoples_PeopleId", - column: x => x.PeopleId, - principalTable: "Peoples", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_AncestorIds_BaseItemEntityId", - table: "AncestorIds", - column: "BaseItemEntityId"); - - migrationBuilder.CreateIndex( - name: "IX_AncestorIds_ParentItemId", - table: "AncestorIds", - column: "ParentItemId"); - - migrationBuilder.CreateIndex( - name: "IX_BaseItemImageInfos_ItemId", - table: "BaseItemImageInfos", - column: "ItemId"); - - migrationBuilder.CreateIndex( - name: "IX_BaseItemMetadataFields_ItemId", - table: "BaseItemMetadataFields", - column: "ItemId"); - - migrationBuilder.CreateIndex( - name: "IX_BaseItemProviders_ProviderId_ProviderValue_ItemId", - table: "BaseItemProviders", - columns: new[] { "ProviderId", "ProviderValue", "ItemId" }); - - migrationBuilder.CreateIndex( - name: "IX_BaseItems_Id_Type_IsFolder_IsVirtualItem", - table: "BaseItems", - columns: new[] { "Id", "Type", "IsFolder", "IsVirtualItem" }); - - migrationBuilder.CreateIndex( - name: "IX_BaseItems_IsFolder_TopParentId_IsVirtualItem_PresentationUniqueKey_DateCreated", - table: "BaseItems", - columns: new[] { "IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated" }); - - migrationBuilder.CreateIndex( - name: "IX_BaseItems_MediaType_TopParentId_IsVirtualItem_PresentationUniqueKey", - table: "BaseItems", - columns: new[] { "MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey" }); - - migrationBuilder.CreateIndex( - name: "IX_BaseItems_ParentId", - table: "BaseItems", - column: "ParentId"); - - migrationBuilder.CreateIndex( - name: "IX_BaseItems_Path", - table: "BaseItems", - column: "Path"); - - migrationBuilder.CreateIndex( - name: "IX_BaseItems_PresentationUniqueKey", - table: "BaseItems", - column: "PresentationUniqueKey"); - - migrationBuilder.CreateIndex( - name: "IX_BaseItems_TopParentId_Id", - table: "BaseItems", - columns: new[] { "TopParentId", "Id" }); - - migrationBuilder.CreateIndex( - name: "IX_BaseItems_Type_SeriesPresentationUniqueKey_IsFolder_IsVirtualItem", - table: "BaseItems", - columns: new[] { "Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem" }); - - migrationBuilder.CreateIndex( - name: "IX_BaseItems_Type_SeriesPresentationUniqueKey_PresentationUniqueKey_SortName", - table: "BaseItems", - columns: new[] { "Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName" }); - - migrationBuilder.CreateIndex( - name: "IX_BaseItems_Type_TopParentId_Id", - table: "BaseItems", - columns: new[] { "Type", "TopParentId", "Id" }); - - migrationBuilder.CreateIndex( - name: "IX_BaseItems_Type_TopParentId_IsVirtualItem_PresentationUniqueKey_DateCreated", - table: "BaseItems", - columns: new[] { "Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated" }); - - migrationBuilder.CreateIndex( - name: "IX_BaseItems_Type_TopParentId_PresentationUniqueKey", - table: "BaseItems", - columns: new[] { "Type", "TopParentId", "PresentationUniqueKey" }); - - migrationBuilder.CreateIndex( - name: "IX_BaseItems_Type_TopParentId_StartDate", - table: "BaseItems", - columns: new[] { "Type", "TopParentId", "StartDate" }); - - migrationBuilder.CreateIndex( - name: "IX_BaseItemTrailerTypes_ItemId", - table: "BaseItemTrailerTypes", - column: "ItemId"); - - migrationBuilder.CreateIndex( - name: "IX_ItemValues_Type_CleanValue", - table: "ItemValues", - columns: new[] { "Type", "CleanValue" }); - - migrationBuilder.CreateIndex( - name: "IX_ItemValuesMap_ItemId", - table: "ItemValuesMap", - column: "ItemId"); - - migrationBuilder.CreateIndex( - name: "IX_MediaStreamInfos_StreamIndex", - table: "MediaStreamInfos", - column: "StreamIndex"); - - migrationBuilder.CreateIndex( - name: "IX_MediaStreamInfos_StreamIndex_StreamType", - table: "MediaStreamInfos", - columns: new[] { "StreamIndex", "StreamType" }); - - migrationBuilder.CreateIndex( - name: "IX_MediaStreamInfos_StreamIndex_StreamType_Language", - table: "MediaStreamInfos", - columns: new[] { "StreamIndex", "StreamType", "Language" }); - - migrationBuilder.CreateIndex( - name: "IX_MediaStreamInfos_StreamType", - table: "MediaStreamInfos", - column: "StreamType"); - - migrationBuilder.CreateIndex( - name: "IX_PeopleBaseItemMap_ItemId_ListOrder", - table: "PeopleBaseItemMap", - columns: new[] { "ItemId", "ListOrder" }); - - migrationBuilder.CreateIndex( - name: "IX_PeopleBaseItemMap_ItemId_SortOrder", - table: "PeopleBaseItemMap", - columns: new[] { "ItemId", "SortOrder" }); - - migrationBuilder.CreateIndex( - name: "IX_PeopleBaseItemMap_PeopleId", - table: "PeopleBaseItemMap", - column: "PeopleId"); - - migrationBuilder.CreateIndex( - name: "IX_Peoples_Name", - table: "Peoples", - column: "Name"); - - migrationBuilder.CreateIndex( - name: "IX_UserData_ItemId_UserId_IsFavorite", - table: "UserData", - columns: new[] { "ItemId", "UserId", "IsFavorite" }); - - migrationBuilder.CreateIndex( - name: "IX_UserData_ItemId_UserId_LastPlayedDate", - table: "UserData", - columns: new[] { "ItemId", "UserId", "LastPlayedDate" }); - - migrationBuilder.CreateIndex( - name: "IX_UserData_ItemId_UserId_PlaybackPositionTicks", - table: "UserData", - columns: new[] { "ItemId", "UserId", "PlaybackPositionTicks" }); - - migrationBuilder.CreateIndex( - name: "IX_UserData_ItemId_UserId_Played", - table: "UserData", - columns: new[] { "ItemId", "UserId", "Played" }); - - migrationBuilder.CreateIndex( - name: "IX_UserData_UserId", - table: "UserData", - column: "UserId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "AncestorIds"); - - migrationBuilder.DropTable( - name: "AttachmentStreamInfos"); - - migrationBuilder.DropTable( - name: "BaseItemImageInfos"); - - migrationBuilder.DropTable( - name: "BaseItemMetadataFields"); - - migrationBuilder.DropTable( - name: "BaseItemProviders"); - - migrationBuilder.DropTable( - name: "BaseItemTrailerTypes"); - - migrationBuilder.DropTable( - name: "Chapters"); - - migrationBuilder.DropTable( - name: "ItemValuesMap"); - - migrationBuilder.DropTable( - name: "MediaStreamInfos"); - - migrationBuilder.DropTable( - name: "PeopleBaseItemMap"); - - migrationBuilder.DropTable( - name: "UserData"); - - migrationBuilder.DropTable( - name: "ItemValues"); - - migrationBuilder.DropTable( - name: "Peoples"); - - migrationBuilder.DropTable( - name: "BaseItems"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241111131257_AddedCustomDataKey.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20241111131257_AddedCustomDataKey.Designer.cs deleted file mode 100644 index 1fbf21492..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241111131257_AddedCustomDataKey.Designer.cs +++ /dev/null @@ -1,1610 +0,0 @@ -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20241111131257_AddedCustomDataKey")] - partial class AddedCustomDataKey - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ParentItemId") - .HasColumnType("TEXT"); - - b.Property("BaseItemEntityId") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ParentItemId"); - - b.HasIndex("BaseItemEntityId"); - - b.HasIndex("ParentItemId"); - - b.ToTable("AncestorIds"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Index") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .HasColumnType("TEXT"); - - b.Property("Comment") - .HasColumnType("TEXT"); - - b.Property("Filename") - .HasColumnType("TEXT"); - - b.Property("MimeType") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "Index"); - - b.ToTable("AttachmentStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Album") - .HasColumnType("TEXT"); - - b.Property("AlbumArtists") - .HasColumnType("TEXT"); - - b.Property("Artists") - .HasColumnType("TEXT"); - - b.Property("Audio") - .HasColumnType("INTEGER"); - - b.Property("ChannelId") - .HasColumnType("TEXT"); - - b.Property("CleanName") - .HasColumnType("TEXT"); - - b.Property("CommunityRating") - .HasColumnType("REAL"); - - b.Property("CriticRating") - .HasColumnType("REAL"); - - b.Property("CustomRating") - .HasColumnType("TEXT"); - - b.Property("Data") - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastMediaAdded") - .HasColumnType("TEXT"); - - b.Property("DateLastRefreshed") - .HasColumnType("TEXT"); - - b.Property("DateLastSaved") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("EndDate") - .HasColumnType("TEXT"); - - b.Property("EpisodeTitle") - .HasColumnType("TEXT"); - - b.Property("ExternalId") - .HasColumnType("TEXT"); - - b.Property("ExternalSeriesId") - .HasColumnType("TEXT"); - - b.Property("ExternalServiceId") - .HasColumnType("TEXT"); - - b.Property("ExtraIds") - .HasColumnType("TEXT"); - - b.Property("ExtraType") - .HasColumnType("INTEGER"); - - b.Property("ForcedSortName") - .HasColumnType("TEXT"); - - b.Property("Genres") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IndexNumber") - .HasColumnType("INTEGER"); - - b.Property("InheritedParentalRatingValue") - .HasColumnType("INTEGER"); - - b.Property("IsFolder") - .HasColumnType("INTEGER"); - - b.Property("IsInMixedFolder") - .HasColumnType("INTEGER"); - - b.Property("IsLocked") - .HasColumnType("INTEGER"); - - b.Property("IsMovie") - .HasColumnType("INTEGER"); - - b.Property("IsRepeat") - .HasColumnType("INTEGER"); - - b.Property("IsSeries") - .HasColumnType("INTEGER"); - - b.Property("IsVirtualItem") - .HasColumnType("INTEGER"); - - b.Property("LUFS") - .HasColumnType("REAL"); - - b.Property("MediaType") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("NormalizationGain") - .HasColumnType("REAL"); - - b.Property("OfficialRating") - .HasColumnType("TEXT"); - - b.Property("OriginalTitle") - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasColumnType("TEXT"); - - b.Property("OwnerId") - .HasColumnType("TEXT"); - - b.Property("ParentId") - .HasColumnType("TEXT"); - - b.Property("ParentIndexNumber") - .HasColumnType("INTEGER"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataCountryCode") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataLanguage") - .HasColumnType("TEXT"); - - b.Property("PremiereDate") - .HasColumnType("TEXT"); - - b.Property("PresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("PrimaryVersionId") - .HasColumnType("TEXT"); - - b.Property("ProductionLocations") - .HasColumnType("TEXT"); - - b.Property("ProductionYear") - .HasColumnType("INTEGER"); - - b.Property("RunTimeTicks") - .HasColumnType("INTEGER"); - - b.Property("SeasonId") - .HasColumnType("TEXT"); - - b.Property("SeasonName") - .HasColumnType("TEXT"); - - b.Property("SeriesId") - .HasColumnType("TEXT"); - - b.Property("SeriesName") - .HasColumnType("TEXT"); - - b.Property("SeriesPresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("ShowId") - .HasColumnType("TEXT"); - - b.Property("Size") - .HasColumnType("INTEGER"); - - b.Property("SortName") - .HasColumnType("TEXT"); - - b.Property("StartDate") - .HasColumnType("TEXT"); - - b.Property("Studios") - .HasColumnType("TEXT"); - - b.Property("Tagline") - .HasColumnType("TEXT"); - - b.Property("Tags") - .HasColumnType("TEXT"); - - b.Property("TopParentId") - .HasColumnType("TEXT"); - - b.Property("TotalBitrate") - .HasColumnType("INTEGER"); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UnratedType") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ParentId"); - - b.HasIndex("Path"); - - b.HasIndex("PresentationUniqueKey"); - - b.HasIndex("TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); - - b.HasIndex("Type", "TopParentId", "StartDate"); - - b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); - - b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); - - b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.ToTable("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Blurhash") - .HasColumnType("BLOB"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("ImageType") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemMetadataFields"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ProviderId") - .HasColumnType("TEXT"); - - b.Property("ProviderValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ProviderId"); - - b.HasIndex("ProviderId", "ProviderValue", "ItemId"); - - b.ToTable("BaseItemProviders"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemTrailerTypes"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ChapterIndex") - .HasColumnType("INTEGER"); - - b.Property("ImageDateModified") - .HasColumnType("TEXT"); - - b.Property("ImagePath") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("StartPositionTicks") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "ChapterIndex"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Property("ItemValueId") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("CleanValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId"); - - b.HasIndex("Type", "CleanValue"); - - b.ToTable("ItemValues"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.Property("ItemValueId") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("ItemValuesMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("EndTicks") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("SegmentProviderId") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("StartTicks") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("MediaSegments"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("StreamIndex") - .HasColumnType("INTEGER"); - - b.Property("AspectRatio") - .HasColumnType("TEXT"); - - b.Property("AverageFrameRate") - .HasColumnType("REAL"); - - b.Property("BitDepth") - .HasColumnType("INTEGER"); - - b.Property("BitRate") - .HasColumnType("INTEGER"); - - b.Property("BlPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("ChannelLayout") - .HasColumnType("TEXT"); - - b.Property("Channels") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("CodecTimeBase") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("ColorPrimaries") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("ColorSpace") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("ColorTransfer") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Comment") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DvBlSignalCompatibilityId") - .HasColumnType("INTEGER"); - - b.Property("DvLevel") - .HasColumnType("INTEGER"); - - b.Property("DvProfile") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMajor") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMinor") - .HasColumnType("INTEGER"); - - b.Property("ElPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IsAnamorphic") - .HasColumnType("INTEGER"); - - b.Property("IsAvc") - .HasColumnType("INTEGER"); - - b.Property("IsDefault") - .HasColumnType("INTEGER"); - - b.Property("IsExternal") - .HasColumnType("INTEGER"); - - b.Property("IsForced") - .HasColumnType("INTEGER"); - - b.Property("IsHearingImpaired") - .HasColumnType("INTEGER"); - - b.Property("IsInterlaced") - .HasColumnType("INTEGER"); - - b.Property("KeyFrames") - .HasColumnType("TEXT"); - - b.Property("Language") - .HasColumnType("TEXT"); - - b.Property("Level") - .HasColumnType("REAL"); - - b.Property("NalLengthSize") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PixelFormat") - .HasColumnType("TEXT"); - - b.Property("Profile") - .HasColumnType("TEXT"); - - b.Property("RealFrameRate") - .HasColumnType("REAL"); - - b.Property("RefFrames") - .HasColumnType("INTEGER"); - - b.Property("Rotation") - .HasColumnType("INTEGER"); - - b.Property("RpuPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("SampleRate") - .HasColumnType("INTEGER"); - - b.Property("StreamType") - .HasColumnType("INTEGER"); - - b.Property("TimeBase") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Title") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "StreamIndex"); - - b.HasIndex("StreamIndex"); - - b.HasIndex("StreamType"); - - b.HasIndex("StreamIndex", "StreamType"); - - b.HasIndex("StreamIndex", "StreamType", "Language"); - - b.ToTable("MediaStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("PersonType") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("Name"); - - b.ToTable("Peoples"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("PeopleId") - .HasColumnType("TEXT"); - - b.Property("ListOrder") - .HasColumnType("INTEGER"); - - b.Property("Role") - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "PeopleId"); - - b.HasIndex("PeopleId"); - - b.HasIndex("ItemId", "ListOrder"); - - b.HasIndex("ItemId", "SortOrder"); - - b.ToTable("PeopleBaseItemMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.Property("Bandwidth") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("Interval") - .HasColumnType("INTEGER"); - - b.Property("ThumbnailCount") - .HasColumnType("INTEGER"); - - b.Property("TileHeight") - .HasColumnType("INTEGER"); - - b.Property("TileWidth") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "Width"); - - b.ToTable("TrickplayInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("CastReceiverId") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("AudioStreamIndex") - .HasColumnType("INTEGER"); - - b.Property("CustomDataKey") - .HasColumnType("TEXT"); - - b.Property("IsFavorite") - .HasColumnType("INTEGER"); - - b.Property("LastPlayedDate") - .HasColumnType("TEXT"); - - b.Property("Likes") - .HasColumnType("INTEGER"); - - b.Property("PlayCount") - .HasColumnType("INTEGER"); - - b.Property("PlaybackPositionTicks") - .HasColumnType("INTEGER"); - - b.Property("Played") - .HasColumnType("INTEGER"); - - b.Property("Rating") - .HasColumnType("REAL"); - - b.Property("SubtitleStreamIndex") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "UserId"); - - b.HasIndex("UserId"); - - b.HasIndex("ItemId", "UserId", "IsFavorite"); - - b.HasIndex("ItemId", "UserId", "LastPlayedDate"); - - b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); - - b.HasIndex("ItemId", "UserId", "Played"); - - b.ToTable("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", null) - .WithMany("AncestorIds") - .HasForeignKey("BaseItemEntityId"); - - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany() - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") - .WithMany() - .HasForeignKey("ParentItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ParentItem"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany() - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Images") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("LockedFields") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Provider") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("TrailerTypes") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Chapters") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("ItemValues") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") - .WithMany("BaseItemsMap") - .HasForeignKey("ItemValueId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ItemValue"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("MediaStreams") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Peoples") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.People", "People") - .WithMany("BaseItems") - .HasForeignKey("PeopleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("People"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("UserData") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Navigation("AncestorIds"); - - b.Navigation("Chapters"); - - b.Navigation("Images"); - - b.Navigation("ItemValues"); - - b.Navigation("LockedFields"); - - b.Navigation("MediaStreams"); - - b.Navigation("Peoples"); - - b.Navigation("Provider"); - - b.Navigation("TrailerTypes"); - - b.Navigation("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Navigation("BaseItemsMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Navigation("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241111131257_AddedCustomDataKey.cs b/Jellyfin.Server.Implementations/Migrations/20241111131257_AddedCustomDataKey.cs deleted file mode 100644 index ac78019ed..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241111131257_AddedCustomDataKey.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - /// - public partial class AddedCustomDataKey : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "CustomDataKey", - table: "UserData", - type: "TEXT", - nullable: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "CustomDataKey", - table: "UserData"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs deleted file mode 100644 index bac6fd5b5..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs +++ /dev/null @@ -1,1610 +0,0 @@ -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20241111135439_AddedCustomDataKeyKey")] - partial class AddedCustomDataKeyKey - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ParentItemId") - .HasColumnType("TEXT"); - - b.Property("BaseItemEntityId") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ParentItemId"); - - b.HasIndex("BaseItemEntityId"); - - b.HasIndex("ParentItemId"); - - b.ToTable("AncestorIds"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Index") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .HasColumnType("TEXT"); - - b.Property("Comment") - .HasColumnType("TEXT"); - - b.Property("Filename") - .HasColumnType("TEXT"); - - b.Property("MimeType") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "Index"); - - b.ToTable("AttachmentStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Album") - .HasColumnType("TEXT"); - - b.Property("AlbumArtists") - .HasColumnType("TEXT"); - - b.Property("Artists") - .HasColumnType("TEXT"); - - b.Property("Audio") - .HasColumnType("INTEGER"); - - b.Property("ChannelId") - .HasColumnType("TEXT"); - - b.Property("CleanName") - .HasColumnType("TEXT"); - - b.Property("CommunityRating") - .HasColumnType("REAL"); - - b.Property("CriticRating") - .HasColumnType("REAL"); - - b.Property("CustomRating") - .HasColumnType("TEXT"); - - b.Property("Data") - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastMediaAdded") - .HasColumnType("TEXT"); - - b.Property("DateLastRefreshed") - .HasColumnType("TEXT"); - - b.Property("DateLastSaved") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("EndDate") - .HasColumnType("TEXT"); - - b.Property("EpisodeTitle") - .HasColumnType("TEXT"); - - b.Property("ExternalId") - .HasColumnType("TEXT"); - - b.Property("ExternalSeriesId") - .HasColumnType("TEXT"); - - b.Property("ExternalServiceId") - .HasColumnType("TEXT"); - - b.Property("ExtraIds") - .HasColumnType("TEXT"); - - b.Property("ExtraType") - .HasColumnType("INTEGER"); - - b.Property("ForcedSortName") - .HasColumnType("TEXT"); - - b.Property("Genres") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IndexNumber") - .HasColumnType("INTEGER"); - - b.Property("InheritedParentalRatingValue") - .HasColumnType("INTEGER"); - - b.Property("IsFolder") - .HasColumnType("INTEGER"); - - b.Property("IsInMixedFolder") - .HasColumnType("INTEGER"); - - b.Property("IsLocked") - .HasColumnType("INTEGER"); - - b.Property("IsMovie") - .HasColumnType("INTEGER"); - - b.Property("IsRepeat") - .HasColumnType("INTEGER"); - - b.Property("IsSeries") - .HasColumnType("INTEGER"); - - b.Property("IsVirtualItem") - .HasColumnType("INTEGER"); - - b.Property("LUFS") - .HasColumnType("REAL"); - - b.Property("MediaType") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("NormalizationGain") - .HasColumnType("REAL"); - - b.Property("OfficialRating") - .HasColumnType("TEXT"); - - b.Property("OriginalTitle") - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasColumnType("TEXT"); - - b.Property("OwnerId") - .HasColumnType("TEXT"); - - b.Property("ParentId") - .HasColumnType("TEXT"); - - b.Property("ParentIndexNumber") - .HasColumnType("INTEGER"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataCountryCode") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataLanguage") - .HasColumnType("TEXT"); - - b.Property("PremiereDate") - .HasColumnType("TEXT"); - - b.Property("PresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("PrimaryVersionId") - .HasColumnType("TEXT"); - - b.Property("ProductionLocations") - .HasColumnType("TEXT"); - - b.Property("ProductionYear") - .HasColumnType("INTEGER"); - - b.Property("RunTimeTicks") - .HasColumnType("INTEGER"); - - b.Property("SeasonId") - .HasColumnType("TEXT"); - - b.Property("SeasonName") - .HasColumnType("TEXT"); - - b.Property("SeriesId") - .HasColumnType("TEXT"); - - b.Property("SeriesName") - .HasColumnType("TEXT"); - - b.Property("SeriesPresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("ShowId") - .HasColumnType("TEXT"); - - b.Property("Size") - .HasColumnType("INTEGER"); - - b.Property("SortName") - .HasColumnType("TEXT"); - - b.Property("StartDate") - .HasColumnType("TEXT"); - - b.Property("Studios") - .HasColumnType("TEXT"); - - b.Property("Tagline") - .HasColumnType("TEXT"); - - b.Property("Tags") - .HasColumnType("TEXT"); - - b.Property("TopParentId") - .HasColumnType("TEXT"); - - b.Property("TotalBitrate") - .HasColumnType("INTEGER"); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UnratedType") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ParentId"); - - b.HasIndex("Path"); - - b.HasIndex("PresentationUniqueKey"); - - b.HasIndex("TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); - - b.HasIndex("Type", "TopParentId", "StartDate"); - - b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); - - b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); - - b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.ToTable("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Blurhash") - .HasColumnType("BLOB"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("ImageType") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemMetadataFields"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ProviderId") - .HasColumnType("TEXT"); - - b.Property("ProviderValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ProviderId"); - - b.HasIndex("ProviderId", "ProviderValue", "ItemId"); - - b.ToTable("BaseItemProviders"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemTrailerTypes"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ChapterIndex") - .HasColumnType("INTEGER"); - - b.Property("ImageDateModified") - .HasColumnType("TEXT"); - - b.Property("ImagePath") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("StartPositionTicks") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "ChapterIndex"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Property("ItemValueId") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("CleanValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId"); - - b.HasIndex("Type", "CleanValue"); - - b.ToTable("ItemValues"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.Property("ItemValueId") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("ItemValuesMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("EndTicks") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("SegmentProviderId") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("StartTicks") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("MediaSegments"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("StreamIndex") - .HasColumnType("INTEGER"); - - b.Property("AspectRatio") - .HasColumnType("TEXT"); - - b.Property("AverageFrameRate") - .HasColumnType("REAL"); - - b.Property("BitDepth") - .HasColumnType("INTEGER"); - - b.Property("BitRate") - .HasColumnType("INTEGER"); - - b.Property("BlPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("ChannelLayout") - .HasColumnType("TEXT"); - - b.Property("Channels") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("CodecTimeBase") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("ColorPrimaries") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("ColorSpace") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("ColorTransfer") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Comment") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DvBlSignalCompatibilityId") - .HasColumnType("INTEGER"); - - b.Property("DvLevel") - .HasColumnType("INTEGER"); - - b.Property("DvProfile") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMajor") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMinor") - .HasColumnType("INTEGER"); - - b.Property("ElPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IsAnamorphic") - .HasColumnType("INTEGER"); - - b.Property("IsAvc") - .HasColumnType("INTEGER"); - - b.Property("IsDefault") - .HasColumnType("INTEGER"); - - b.Property("IsExternal") - .HasColumnType("INTEGER"); - - b.Property("IsForced") - .HasColumnType("INTEGER"); - - b.Property("IsHearingImpaired") - .HasColumnType("INTEGER"); - - b.Property("IsInterlaced") - .HasColumnType("INTEGER"); - - b.Property("KeyFrames") - .HasColumnType("TEXT"); - - b.Property("Language") - .HasColumnType("TEXT"); - - b.Property("Level") - .HasColumnType("REAL"); - - b.Property("NalLengthSize") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PixelFormat") - .HasColumnType("TEXT"); - - b.Property("Profile") - .HasColumnType("TEXT"); - - b.Property("RealFrameRate") - .HasColumnType("REAL"); - - b.Property("RefFrames") - .HasColumnType("INTEGER"); - - b.Property("Rotation") - .HasColumnType("INTEGER"); - - b.Property("RpuPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("SampleRate") - .HasColumnType("INTEGER"); - - b.Property("StreamType") - .HasColumnType("INTEGER"); - - b.Property("TimeBase") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Title") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "StreamIndex"); - - b.HasIndex("StreamIndex"); - - b.HasIndex("StreamType"); - - b.HasIndex("StreamIndex", "StreamType"); - - b.HasIndex("StreamIndex", "StreamType", "Language"); - - b.ToTable("MediaStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("PersonType") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("Name"); - - b.ToTable("Peoples"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("PeopleId") - .HasColumnType("TEXT"); - - b.Property("ListOrder") - .HasColumnType("INTEGER"); - - b.Property("Role") - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "PeopleId"); - - b.HasIndex("PeopleId"); - - b.HasIndex("ItemId", "ListOrder"); - - b.HasIndex("ItemId", "SortOrder"); - - b.ToTable("PeopleBaseItemMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.Property("Bandwidth") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("Interval") - .HasColumnType("INTEGER"); - - b.Property("ThumbnailCount") - .HasColumnType("INTEGER"); - - b.Property("TileHeight") - .HasColumnType("INTEGER"); - - b.Property("TileWidth") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "Width"); - - b.ToTable("TrickplayInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("CastReceiverId") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("CustomDataKey") - .HasColumnType("TEXT"); - - b.Property("AudioStreamIndex") - .HasColumnType("INTEGER"); - - b.Property("IsFavorite") - .HasColumnType("INTEGER"); - - b.Property("LastPlayedDate") - .HasColumnType("TEXT"); - - b.Property("Likes") - .HasColumnType("INTEGER"); - - b.Property("PlayCount") - .HasColumnType("INTEGER"); - - b.Property("PlaybackPositionTicks") - .HasColumnType("INTEGER"); - - b.Property("Played") - .HasColumnType("INTEGER"); - - b.Property("Rating") - .HasColumnType("REAL"); - - b.Property("SubtitleStreamIndex") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "UserId", "CustomDataKey"); - - b.HasIndex("UserId"); - - b.HasIndex("ItemId", "UserId", "IsFavorite"); - - b.HasIndex("ItemId", "UserId", "LastPlayedDate"); - - b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); - - b.HasIndex("ItemId", "UserId", "Played"); - - b.ToTable("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", null) - .WithMany("AncestorIds") - .HasForeignKey("BaseItemEntityId"); - - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany() - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") - .WithMany() - .HasForeignKey("ParentItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ParentItem"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany() - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Images") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("LockedFields") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Provider") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("TrailerTypes") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Chapters") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("ItemValues") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") - .WithMany("BaseItemsMap") - .HasForeignKey("ItemValueId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ItemValue"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("MediaStreams") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Peoples") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.People", "People") - .WithMany("BaseItems") - .HasForeignKey("PeopleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("People"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("UserData") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Navigation("AncestorIds"); - - b.Navigation("Chapters"); - - b.Navigation("Images"); - - b.Navigation("ItemValues"); - - b.Navigation("LockedFields"); - - b.Navigation("MediaStreams"); - - b.Navigation("Peoples"); - - b.Navigation("Provider"); - - b.Navigation("TrailerTypes"); - - b.Navigation("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Navigation("BaseItemsMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Navigation("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241111135439_AddedCustomDataKeyKey.cs b/Jellyfin.Server.Implementations/Migrations/20241111135439_AddedCustomDataKeyKey.cs deleted file mode 100644 index 4558d7c49..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241111135439_AddedCustomDataKeyKey.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - /// - public partial class AddedCustomDataKeyKey : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropPrimaryKey( - name: "PK_UserData", - table: "UserData"); - - migrationBuilder.AlterColumn( - name: "CustomDataKey", - table: "UserData", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AddPrimaryKey( - name: "PK_UserData", - table: "UserData", - columns: new[] { "ItemId", "UserId", "CustomDataKey" }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropPrimaryKey( - name: "PK_UserData", - table: "UserData"); - - migrationBuilder.AlterColumn( - name: "CustomDataKey", - table: "UserData", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AddPrimaryKey( - name: "PK_UserData", - table: "UserData", - columns: new[] { "ItemId", "UserId" }); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs deleted file mode 100644 index ad622d44c..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs +++ /dev/null @@ -1,1603 +0,0 @@ -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20241112152323_FixAncestorIdConfig")] - partial class FixAncestorIdConfig - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ParentItemId") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ParentItemId"); - - b.HasIndex("ParentItemId"); - - b.ToTable("AncestorIds"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Index") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .HasColumnType("TEXT"); - - b.Property("Comment") - .HasColumnType("TEXT"); - - b.Property("Filename") - .HasColumnType("TEXT"); - - b.Property("MimeType") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "Index"); - - b.ToTable("AttachmentStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Album") - .HasColumnType("TEXT"); - - b.Property("AlbumArtists") - .HasColumnType("TEXT"); - - b.Property("Artists") - .HasColumnType("TEXT"); - - b.Property("Audio") - .HasColumnType("INTEGER"); - - b.Property("ChannelId") - .HasColumnType("TEXT"); - - b.Property("CleanName") - .HasColumnType("TEXT"); - - b.Property("CommunityRating") - .HasColumnType("REAL"); - - b.Property("CriticRating") - .HasColumnType("REAL"); - - b.Property("CustomRating") - .HasColumnType("TEXT"); - - b.Property("Data") - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastMediaAdded") - .HasColumnType("TEXT"); - - b.Property("DateLastRefreshed") - .HasColumnType("TEXT"); - - b.Property("DateLastSaved") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("EndDate") - .HasColumnType("TEXT"); - - b.Property("EpisodeTitle") - .HasColumnType("TEXT"); - - b.Property("ExternalId") - .HasColumnType("TEXT"); - - b.Property("ExternalSeriesId") - .HasColumnType("TEXT"); - - b.Property("ExternalServiceId") - .HasColumnType("TEXT"); - - b.Property("ExtraIds") - .HasColumnType("TEXT"); - - b.Property("ExtraType") - .HasColumnType("INTEGER"); - - b.Property("ForcedSortName") - .HasColumnType("TEXT"); - - b.Property("Genres") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IndexNumber") - .HasColumnType("INTEGER"); - - b.Property("InheritedParentalRatingValue") - .HasColumnType("INTEGER"); - - b.Property("IsFolder") - .HasColumnType("INTEGER"); - - b.Property("IsInMixedFolder") - .HasColumnType("INTEGER"); - - b.Property("IsLocked") - .HasColumnType("INTEGER"); - - b.Property("IsMovie") - .HasColumnType("INTEGER"); - - b.Property("IsRepeat") - .HasColumnType("INTEGER"); - - b.Property("IsSeries") - .HasColumnType("INTEGER"); - - b.Property("IsVirtualItem") - .HasColumnType("INTEGER"); - - b.Property("LUFS") - .HasColumnType("REAL"); - - b.Property("MediaType") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("NormalizationGain") - .HasColumnType("REAL"); - - b.Property("OfficialRating") - .HasColumnType("TEXT"); - - b.Property("OriginalTitle") - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasColumnType("TEXT"); - - b.Property("OwnerId") - .HasColumnType("TEXT"); - - b.Property("ParentId") - .HasColumnType("TEXT"); - - b.Property("ParentIndexNumber") - .HasColumnType("INTEGER"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataCountryCode") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataLanguage") - .HasColumnType("TEXT"); - - b.Property("PremiereDate") - .HasColumnType("TEXT"); - - b.Property("PresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("PrimaryVersionId") - .HasColumnType("TEXT"); - - b.Property("ProductionLocations") - .HasColumnType("TEXT"); - - b.Property("ProductionYear") - .HasColumnType("INTEGER"); - - b.Property("RunTimeTicks") - .HasColumnType("INTEGER"); - - b.Property("SeasonId") - .HasColumnType("TEXT"); - - b.Property("SeasonName") - .HasColumnType("TEXT"); - - b.Property("SeriesId") - .HasColumnType("TEXT"); - - b.Property("SeriesName") - .HasColumnType("TEXT"); - - b.Property("SeriesPresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("ShowId") - .HasColumnType("TEXT"); - - b.Property("Size") - .HasColumnType("INTEGER"); - - b.Property("SortName") - .HasColumnType("TEXT"); - - b.Property("StartDate") - .HasColumnType("TEXT"); - - b.Property("Studios") - .HasColumnType("TEXT"); - - b.Property("Tagline") - .HasColumnType("TEXT"); - - b.Property("Tags") - .HasColumnType("TEXT"); - - b.Property("TopParentId") - .HasColumnType("TEXT"); - - b.Property("TotalBitrate") - .HasColumnType("INTEGER"); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UnratedType") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ParentId"); - - b.HasIndex("Path"); - - b.HasIndex("PresentationUniqueKey"); - - b.HasIndex("TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); - - b.HasIndex("Type", "TopParentId", "StartDate"); - - b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); - - b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); - - b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.ToTable("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Blurhash") - .HasColumnType("BLOB"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("ImageType") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemMetadataFields"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ProviderId") - .HasColumnType("TEXT"); - - b.Property("ProviderValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ProviderId"); - - b.HasIndex("ProviderId", "ProviderValue", "ItemId"); - - b.ToTable("BaseItemProviders"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemTrailerTypes"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ChapterIndex") - .HasColumnType("INTEGER"); - - b.Property("ImageDateModified") - .HasColumnType("TEXT"); - - b.Property("ImagePath") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("StartPositionTicks") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "ChapterIndex"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Property("ItemValueId") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("CleanValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId"); - - b.HasIndex("Type", "CleanValue"); - - b.ToTable("ItemValues"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.Property("ItemValueId") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("ItemValuesMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("EndTicks") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("SegmentProviderId") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("StartTicks") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("MediaSegments"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("StreamIndex") - .HasColumnType("INTEGER"); - - b.Property("AspectRatio") - .HasColumnType("TEXT"); - - b.Property("AverageFrameRate") - .HasColumnType("REAL"); - - b.Property("BitDepth") - .HasColumnType("INTEGER"); - - b.Property("BitRate") - .HasColumnType("INTEGER"); - - b.Property("BlPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("ChannelLayout") - .HasColumnType("TEXT"); - - b.Property("Channels") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("CodecTimeBase") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("ColorPrimaries") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("ColorSpace") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("ColorTransfer") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Comment") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DvBlSignalCompatibilityId") - .HasColumnType("INTEGER"); - - b.Property("DvLevel") - .HasColumnType("INTEGER"); - - b.Property("DvProfile") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMajor") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMinor") - .HasColumnType("INTEGER"); - - b.Property("ElPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IsAnamorphic") - .HasColumnType("INTEGER"); - - b.Property("IsAvc") - .HasColumnType("INTEGER"); - - b.Property("IsDefault") - .HasColumnType("INTEGER"); - - b.Property("IsExternal") - .HasColumnType("INTEGER"); - - b.Property("IsForced") - .HasColumnType("INTEGER"); - - b.Property("IsHearingImpaired") - .HasColumnType("INTEGER"); - - b.Property("IsInterlaced") - .HasColumnType("INTEGER"); - - b.Property("KeyFrames") - .HasColumnType("TEXT"); - - b.Property("Language") - .HasColumnType("TEXT"); - - b.Property("Level") - .HasColumnType("REAL"); - - b.Property("NalLengthSize") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PixelFormat") - .HasColumnType("TEXT"); - - b.Property("Profile") - .HasColumnType("TEXT"); - - b.Property("RealFrameRate") - .HasColumnType("REAL"); - - b.Property("RefFrames") - .HasColumnType("INTEGER"); - - b.Property("Rotation") - .HasColumnType("INTEGER"); - - b.Property("RpuPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("SampleRate") - .HasColumnType("INTEGER"); - - b.Property("StreamType") - .HasColumnType("INTEGER"); - - b.Property("TimeBase") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Title") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "StreamIndex"); - - b.HasIndex("StreamIndex"); - - b.HasIndex("StreamType"); - - b.HasIndex("StreamIndex", "StreamType"); - - b.HasIndex("StreamIndex", "StreamType", "Language"); - - b.ToTable("MediaStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("PersonType") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("Name"); - - b.ToTable("Peoples"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("PeopleId") - .HasColumnType("TEXT"); - - b.Property("ListOrder") - .HasColumnType("INTEGER"); - - b.Property("Role") - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "PeopleId"); - - b.HasIndex("PeopleId"); - - b.HasIndex("ItemId", "ListOrder"); - - b.HasIndex("ItemId", "SortOrder"); - - b.ToTable("PeopleBaseItemMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.Property("Bandwidth") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("Interval") - .HasColumnType("INTEGER"); - - b.Property("ThumbnailCount") - .HasColumnType("INTEGER"); - - b.Property("TileHeight") - .HasColumnType("INTEGER"); - - b.Property("TileWidth") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "Width"); - - b.ToTable("TrickplayInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("CastReceiverId") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("CustomDataKey") - .HasColumnType("TEXT"); - - b.Property("AudioStreamIndex") - .HasColumnType("INTEGER"); - - b.Property("IsFavorite") - .HasColumnType("INTEGER"); - - b.Property("LastPlayedDate") - .HasColumnType("TEXT"); - - b.Property("Likes") - .HasColumnType("INTEGER"); - - b.Property("PlayCount") - .HasColumnType("INTEGER"); - - b.Property("PlaybackPositionTicks") - .HasColumnType("INTEGER"); - - b.Property("Played") - .HasColumnType("INTEGER"); - - b.Property("Rating") - .HasColumnType("REAL"); - - b.Property("SubtitleStreamIndex") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "UserId", "CustomDataKey"); - - b.HasIndex("UserId"); - - b.HasIndex("ItemId", "UserId", "IsFavorite"); - - b.HasIndex("ItemId", "UserId", "LastPlayedDate"); - - b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); - - b.HasIndex("ItemId", "UserId", "Played"); - - b.ToTable("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Children") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") - .WithMany("ParentAncestors") - .HasForeignKey("ParentItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ParentItem"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany() - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Images") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("LockedFields") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Provider") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("TrailerTypes") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Chapters") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("ItemValues") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") - .WithMany("BaseItemsMap") - .HasForeignKey("ItemValueId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ItemValue"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("MediaStreams") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Peoples") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.People", "People") - .WithMany("BaseItems") - .HasForeignKey("PeopleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("People"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("UserData") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Navigation("Chapters"); - - b.Navigation("Children"); - - b.Navigation("Images"); - - b.Navigation("ItemValues"); - - b.Navigation("LockedFields"); - - b.Navigation("MediaStreams"); - - b.Navigation("ParentAncestors"); - - b.Navigation("Peoples"); - - b.Navigation("Provider"); - - b.Navigation("TrailerTypes"); - - b.Navigation("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Navigation("BaseItemsMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Navigation("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241112152323_FixAncestorIdConfig.cs b/Jellyfin.Server.Implementations/Migrations/20241112152323_FixAncestorIdConfig.cs deleted file mode 100644 index 70e81f367..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241112152323_FixAncestorIdConfig.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - /// - public partial class FixAncestorIdConfig : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_AncestorIds_BaseItems_BaseItemEntityId", - table: "AncestorIds"); - - migrationBuilder.DropIndex( - name: "IX_AncestorIds_BaseItemEntityId", - table: "AncestorIds"); - - migrationBuilder.DropColumn( - name: "BaseItemEntityId", - table: "AncestorIds"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "BaseItemEntityId", - table: "AncestorIds", - type: "TEXT", - nullable: true); - - migrationBuilder.CreateIndex( - name: "IX_AncestorIds_BaseItemEntityId", - table: "AncestorIds", - column: "BaseItemEntityId"); - - migrationBuilder.AddForeignKey( - name: "FK_AncestorIds_BaseItems_BaseItemEntityId", - table: "AncestorIds", - column: "BaseItemEntityId", - principalTable: "BaseItems", - principalColumn: "Id"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241112232041_fixMediaStreams.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20241112232041_fixMediaStreams.Designer.cs deleted file mode 100644 index dc4c8212b..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241112232041_fixMediaStreams.Designer.cs +++ /dev/null @@ -1,1600 +0,0 @@ -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20241112232041_FixMediaStreams")] - partial class FixMediaStreams - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ParentItemId") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ParentItemId"); - - b.HasIndex("ParentItemId"); - - b.ToTable("AncestorIds"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Index") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .HasColumnType("TEXT"); - - b.Property("Comment") - .HasColumnType("TEXT"); - - b.Property("Filename") - .HasColumnType("TEXT"); - - b.Property("MimeType") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "Index"); - - b.ToTable("AttachmentStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Album") - .HasColumnType("TEXT"); - - b.Property("AlbumArtists") - .HasColumnType("TEXT"); - - b.Property("Artists") - .HasColumnType("TEXT"); - - b.Property("Audio") - .HasColumnType("INTEGER"); - - b.Property("ChannelId") - .HasColumnType("TEXT"); - - b.Property("CleanName") - .HasColumnType("TEXT"); - - b.Property("CommunityRating") - .HasColumnType("REAL"); - - b.Property("CriticRating") - .HasColumnType("REAL"); - - b.Property("CustomRating") - .HasColumnType("TEXT"); - - b.Property("Data") - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastMediaAdded") - .HasColumnType("TEXT"); - - b.Property("DateLastRefreshed") - .HasColumnType("TEXT"); - - b.Property("DateLastSaved") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("EndDate") - .HasColumnType("TEXT"); - - b.Property("EpisodeTitle") - .HasColumnType("TEXT"); - - b.Property("ExternalId") - .HasColumnType("TEXT"); - - b.Property("ExternalSeriesId") - .HasColumnType("TEXT"); - - b.Property("ExternalServiceId") - .HasColumnType("TEXT"); - - b.Property("ExtraIds") - .HasColumnType("TEXT"); - - b.Property("ExtraType") - .HasColumnType("INTEGER"); - - b.Property("ForcedSortName") - .HasColumnType("TEXT"); - - b.Property("Genres") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IndexNumber") - .HasColumnType("INTEGER"); - - b.Property("InheritedParentalRatingValue") - .HasColumnType("INTEGER"); - - b.Property("IsFolder") - .HasColumnType("INTEGER"); - - b.Property("IsInMixedFolder") - .HasColumnType("INTEGER"); - - b.Property("IsLocked") - .HasColumnType("INTEGER"); - - b.Property("IsMovie") - .HasColumnType("INTEGER"); - - b.Property("IsRepeat") - .HasColumnType("INTEGER"); - - b.Property("IsSeries") - .HasColumnType("INTEGER"); - - b.Property("IsVirtualItem") - .HasColumnType("INTEGER"); - - b.Property("LUFS") - .HasColumnType("REAL"); - - b.Property("MediaType") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("NormalizationGain") - .HasColumnType("REAL"); - - b.Property("OfficialRating") - .HasColumnType("TEXT"); - - b.Property("OriginalTitle") - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasColumnType("TEXT"); - - b.Property("OwnerId") - .HasColumnType("TEXT"); - - b.Property("ParentId") - .HasColumnType("TEXT"); - - b.Property("ParentIndexNumber") - .HasColumnType("INTEGER"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataCountryCode") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataLanguage") - .HasColumnType("TEXT"); - - b.Property("PremiereDate") - .HasColumnType("TEXT"); - - b.Property("PresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("PrimaryVersionId") - .HasColumnType("TEXT"); - - b.Property("ProductionLocations") - .HasColumnType("TEXT"); - - b.Property("ProductionYear") - .HasColumnType("INTEGER"); - - b.Property("RunTimeTicks") - .HasColumnType("INTEGER"); - - b.Property("SeasonId") - .HasColumnType("TEXT"); - - b.Property("SeasonName") - .HasColumnType("TEXT"); - - b.Property("SeriesId") - .HasColumnType("TEXT"); - - b.Property("SeriesName") - .HasColumnType("TEXT"); - - b.Property("SeriesPresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("ShowId") - .HasColumnType("TEXT"); - - b.Property("Size") - .HasColumnType("INTEGER"); - - b.Property("SortName") - .HasColumnType("TEXT"); - - b.Property("StartDate") - .HasColumnType("TEXT"); - - b.Property("Studios") - .HasColumnType("TEXT"); - - b.Property("Tagline") - .HasColumnType("TEXT"); - - b.Property("Tags") - .HasColumnType("TEXT"); - - b.Property("TopParentId") - .HasColumnType("TEXT"); - - b.Property("TotalBitrate") - .HasColumnType("INTEGER"); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UnratedType") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ParentId"); - - b.HasIndex("Path"); - - b.HasIndex("PresentationUniqueKey"); - - b.HasIndex("TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); - - b.HasIndex("Type", "TopParentId", "StartDate"); - - b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); - - b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); - - b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.ToTable("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Blurhash") - .HasColumnType("BLOB"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("ImageType") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemMetadataFields"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ProviderId") - .HasColumnType("TEXT"); - - b.Property("ProviderValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ProviderId"); - - b.HasIndex("ProviderId", "ProviderValue", "ItemId"); - - b.ToTable("BaseItemProviders"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemTrailerTypes"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ChapterIndex") - .HasColumnType("INTEGER"); - - b.Property("ImageDateModified") - .HasColumnType("TEXT"); - - b.Property("ImagePath") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("StartPositionTicks") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "ChapterIndex"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Property("ItemValueId") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("CleanValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId"); - - b.HasIndex("Type", "CleanValue"); - - b.ToTable("ItemValues"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.Property("ItemValueId") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("ItemValuesMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("EndTicks") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("SegmentProviderId") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("StartTicks") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("MediaSegments"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("StreamIndex") - .HasColumnType("INTEGER"); - - b.Property("AspectRatio") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AverageFrameRate") - .HasColumnType("REAL"); - - b.Property("BitDepth") - .HasColumnType("INTEGER"); - - b.Property("BitRate") - .HasColumnType("INTEGER"); - - b.Property("BlPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("ChannelLayout") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Channels") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .HasColumnType("TEXT"); - - b.Property("CodecTimeBase") - .HasColumnType("TEXT"); - - b.Property("ColorPrimaries") - .HasColumnType("TEXT"); - - b.Property("ColorSpace") - .HasColumnType("TEXT"); - - b.Property("ColorTransfer") - .HasColumnType("TEXT"); - - b.Property("Comment") - .HasColumnType("TEXT"); - - b.Property("DvBlSignalCompatibilityId") - .HasColumnType("INTEGER"); - - b.Property("DvLevel") - .HasColumnType("INTEGER"); - - b.Property("DvProfile") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMajor") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMinor") - .HasColumnType("INTEGER"); - - b.Property("ElPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IsAnamorphic") - .HasColumnType("INTEGER"); - - b.Property("IsAvc") - .HasColumnType("INTEGER"); - - b.Property("IsDefault") - .HasColumnType("INTEGER"); - - b.Property("IsExternal") - .HasColumnType("INTEGER"); - - b.Property("IsForced") - .HasColumnType("INTEGER"); - - b.Property("IsHearingImpaired") - .HasColumnType("INTEGER"); - - b.Property("IsInterlaced") - .HasColumnType("INTEGER"); - - b.Property("KeyFrames") - .HasColumnType("TEXT"); - - b.Property("Language") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Level") - .HasColumnType("REAL"); - - b.Property("NalLengthSize") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("PixelFormat") - .HasColumnType("TEXT"); - - b.Property("Profile") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("RealFrameRate") - .HasColumnType("REAL"); - - b.Property("RefFrames") - .HasColumnType("INTEGER"); - - b.Property("Rotation") - .HasColumnType("INTEGER"); - - b.Property("RpuPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("SampleRate") - .HasColumnType("INTEGER"); - - b.Property("StreamType") - .HasColumnType("INTEGER"); - - b.Property("TimeBase") - .HasColumnType("TEXT"); - - b.Property("Title") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "StreamIndex"); - - b.HasIndex("StreamIndex"); - - b.HasIndex("StreamType"); - - b.HasIndex("StreamIndex", "StreamType"); - - b.HasIndex("StreamIndex", "StreamType", "Language"); - - b.ToTable("MediaStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("PersonType") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("Name"); - - b.ToTable("Peoples"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("PeopleId") - .HasColumnType("TEXT"); - - b.Property("ListOrder") - .HasColumnType("INTEGER"); - - b.Property("Role") - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "PeopleId"); - - b.HasIndex("PeopleId"); - - b.HasIndex("ItemId", "ListOrder"); - - b.HasIndex("ItemId", "SortOrder"); - - b.ToTable("PeopleBaseItemMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.Property("Bandwidth") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("Interval") - .HasColumnType("INTEGER"); - - b.Property("ThumbnailCount") - .HasColumnType("INTEGER"); - - b.Property("TileHeight") - .HasColumnType("INTEGER"); - - b.Property("TileWidth") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "Width"); - - b.ToTable("TrickplayInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("CastReceiverId") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("CustomDataKey") - .HasColumnType("TEXT"); - - b.Property("AudioStreamIndex") - .HasColumnType("INTEGER"); - - b.Property("IsFavorite") - .HasColumnType("INTEGER"); - - b.Property("LastPlayedDate") - .HasColumnType("TEXT"); - - b.Property("Likes") - .HasColumnType("INTEGER"); - - b.Property("PlayCount") - .HasColumnType("INTEGER"); - - b.Property("PlaybackPositionTicks") - .HasColumnType("INTEGER"); - - b.Property("Played") - .HasColumnType("INTEGER"); - - b.Property("Rating") - .HasColumnType("REAL"); - - b.Property("SubtitleStreamIndex") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "UserId", "CustomDataKey"); - - b.HasIndex("UserId"); - - b.HasIndex("ItemId", "UserId", "IsFavorite"); - - b.HasIndex("ItemId", "UserId", "LastPlayedDate"); - - b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); - - b.HasIndex("ItemId", "UserId", "Played"); - - b.ToTable("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Children") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") - .WithMany("ParentAncestors") - .HasForeignKey("ParentItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ParentItem"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany() - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Images") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("LockedFields") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Provider") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("TrailerTypes") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Chapters") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("ItemValues") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") - .WithMany("BaseItemsMap") - .HasForeignKey("ItemValueId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ItemValue"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("MediaStreams") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Peoples") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.People", "People") - .WithMany("BaseItems") - .HasForeignKey("PeopleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("People"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("UserData") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Navigation("Chapters"); - - b.Navigation("Children"); - - b.Navigation("Images"); - - b.Navigation("ItemValues"); - - b.Navigation("LockedFields"); - - b.Navigation("MediaStreams"); - - b.Navigation("ParentAncestors"); - - b.Navigation("Peoples"); - - b.Navigation("Provider"); - - b.Navigation("TrailerTypes"); - - b.Navigation("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Navigation("BaseItemsMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Navigation("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241112232041_fixMediaStreams.cs b/Jellyfin.Server.Implementations/Migrations/20241112232041_fixMediaStreams.cs deleted file mode 100644 index d57ea81b3..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241112232041_fixMediaStreams.cs +++ /dev/null @@ -1,702 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - /// - public partial class FixMediaStreams : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "Width", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "Title", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "TimeBase", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "StreamType", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "SampleRate", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "RpuPresentFlag", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "Rotation", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "RefFrames", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "RealFrameRate", - table: "MediaStreamInfos", - type: "REAL", - nullable: true, - oldClrType: typeof(float), - oldType: "REAL"); - - migrationBuilder.AlterColumn( - name: "Profile", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "Path", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "NalLengthSize", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "Level", - table: "MediaStreamInfos", - type: "REAL", - nullable: true, - oldClrType: typeof(float), - oldType: "REAL"); - - migrationBuilder.AlterColumn( - name: "Language", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "IsHearingImpaired", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(bool), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "IsAvc", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(bool), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "IsAnamorphic", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(bool), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "Height", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "ElPresentFlag", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "DvVersionMinor", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "DvVersionMajor", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "DvProfile", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "DvLevel", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "DvBlSignalCompatibilityId", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "Comment", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "ColorTransfer", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "ColorSpace", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "ColorPrimaries", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "CodecTimeBase", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "CodecTag", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "Codec", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "Channels", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "ChannelLayout", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "BlPresentFlag", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "BitRate", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "BitDepth", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "AverageFrameRate", - table: "MediaStreamInfos", - type: "REAL", - nullable: true, - oldClrType: typeof(float), - oldType: "REAL"); - - migrationBuilder.AlterColumn( - name: "AspectRatio", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "Width", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "Title", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "TimeBase", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "StreamType", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(int), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "SampleRate", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "RpuPresentFlag", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "Rotation", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "RefFrames", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "RealFrameRate", - table: "MediaStreamInfos", - type: "REAL", - nullable: false, - defaultValue: 0f, - oldClrType: typeof(float), - oldType: "REAL", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "Profile", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "Path", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "NalLengthSize", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "Level", - table: "MediaStreamInfos", - type: "REAL", - nullable: false, - defaultValue: 0f, - oldClrType: typeof(float), - oldType: "REAL", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "Language", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "IsHearingImpaired", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: false, - oldClrType: typeof(bool), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "IsAvc", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: false, - oldClrType: typeof(bool), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "IsAnamorphic", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: false, - oldClrType: typeof(bool), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "Height", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "ElPresentFlag", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "DvVersionMinor", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "DvVersionMajor", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "DvProfile", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "DvLevel", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "DvBlSignalCompatibilityId", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "Comment", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "ColorTransfer", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "ColorSpace", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "ColorPrimaries", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "CodecTimeBase", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "CodecTag", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "Codec", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "Channels", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "ChannelLayout", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "BlPresentFlag", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "BitRate", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "BitDepth", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: 0, - oldClrType: typeof(int), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "AverageFrameRate", - table: "MediaStreamInfos", - type: "REAL", - nullable: false, - defaultValue: 0f, - oldClrType: typeof(float), - oldType: "REAL", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "AspectRatio", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241112234144_FixMediaStreams2.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20241112234144_FixMediaStreams2.Designer.cs deleted file mode 100644 index 5714120b5..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241112234144_FixMediaStreams2.Designer.cs +++ /dev/null @@ -1,1594 +0,0 @@ -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20241112234144_FixMediaStreams2")] - partial class FixMediaStreams2 - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ParentItemId") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ParentItemId"); - - b.HasIndex("ParentItemId"); - - b.ToTable("AncestorIds"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Index") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .HasColumnType("TEXT"); - - b.Property("Comment") - .HasColumnType("TEXT"); - - b.Property("Filename") - .HasColumnType("TEXT"); - - b.Property("MimeType") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "Index"); - - b.ToTable("AttachmentStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Album") - .HasColumnType("TEXT"); - - b.Property("AlbumArtists") - .HasColumnType("TEXT"); - - b.Property("Artists") - .HasColumnType("TEXT"); - - b.Property("Audio") - .HasColumnType("INTEGER"); - - b.Property("ChannelId") - .HasColumnType("TEXT"); - - b.Property("CleanName") - .HasColumnType("TEXT"); - - b.Property("CommunityRating") - .HasColumnType("REAL"); - - b.Property("CriticRating") - .HasColumnType("REAL"); - - b.Property("CustomRating") - .HasColumnType("TEXT"); - - b.Property("Data") - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastMediaAdded") - .HasColumnType("TEXT"); - - b.Property("DateLastRefreshed") - .HasColumnType("TEXT"); - - b.Property("DateLastSaved") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("EndDate") - .HasColumnType("TEXT"); - - b.Property("EpisodeTitle") - .HasColumnType("TEXT"); - - b.Property("ExternalId") - .HasColumnType("TEXT"); - - b.Property("ExternalSeriesId") - .HasColumnType("TEXT"); - - b.Property("ExternalServiceId") - .HasColumnType("TEXT"); - - b.Property("ExtraIds") - .HasColumnType("TEXT"); - - b.Property("ExtraType") - .HasColumnType("INTEGER"); - - b.Property("ForcedSortName") - .HasColumnType("TEXT"); - - b.Property("Genres") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IndexNumber") - .HasColumnType("INTEGER"); - - b.Property("InheritedParentalRatingValue") - .HasColumnType("INTEGER"); - - b.Property("IsFolder") - .HasColumnType("INTEGER"); - - b.Property("IsInMixedFolder") - .HasColumnType("INTEGER"); - - b.Property("IsLocked") - .HasColumnType("INTEGER"); - - b.Property("IsMovie") - .HasColumnType("INTEGER"); - - b.Property("IsRepeat") - .HasColumnType("INTEGER"); - - b.Property("IsSeries") - .HasColumnType("INTEGER"); - - b.Property("IsVirtualItem") - .HasColumnType("INTEGER"); - - b.Property("LUFS") - .HasColumnType("REAL"); - - b.Property("MediaType") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("NormalizationGain") - .HasColumnType("REAL"); - - b.Property("OfficialRating") - .HasColumnType("TEXT"); - - b.Property("OriginalTitle") - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasColumnType("TEXT"); - - b.Property("OwnerId") - .HasColumnType("TEXT"); - - b.Property("ParentId") - .HasColumnType("TEXT"); - - b.Property("ParentIndexNumber") - .HasColumnType("INTEGER"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataCountryCode") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataLanguage") - .HasColumnType("TEXT"); - - b.Property("PremiereDate") - .HasColumnType("TEXT"); - - b.Property("PresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("PrimaryVersionId") - .HasColumnType("TEXT"); - - b.Property("ProductionLocations") - .HasColumnType("TEXT"); - - b.Property("ProductionYear") - .HasColumnType("INTEGER"); - - b.Property("RunTimeTicks") - .HasColumnType("INTEGER"); - - b.Property("SeasonId") - .HasColumnType("TEXT"); - - b.Property("SeasonName") - .HasColumnType("TEXT"); - - b.Property("SeriesId") - .HasColumnType("TEXT"); - - b.Property("SeriesName") - .HasColumnType("TEXT"); - - b.Property("SeriesPresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("ShowId") - .HasColumnType("TEXT"); - - b.Property("Size") - .HasColumnType("INTEGER"); - - b.Property("SortName") - .HasColumnType("TEXT"); - - b.Property("StartDate") - .HasColumnType("TEXT"); - - b.Property("Studios") - .HasColumnType("TEXT"); - - b.Property("Tagline") - .HasColumnType("TEXT"); - - b.Property("Tags") - .HasColumnType("TEXT"); - - b.Property("TopParentId") - .HasColumnType("TEXT"); - - b.Property("TotalBitrate") - .HasColumnType("INTEGER"); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UnratedType") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ParentId"); - - b.HasIndex("Path"); - - b.HasIndex("PresentationUniqueKey"); - - b.HasIndex("TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); - - b.HasIndex("Type", "TopParentId", "StartDate"); - - b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); - - b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); - - b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.ToTable("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Blurhash") - .HasColumnType("BLOB"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("ImageType") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemMetadataFields"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ProviderId") - .HasColumnType("TEXT"); - - b.Property("ProviderValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ProviderId"); - - b.HasIndex("ProviderId", "ProviderValue", "ItemId"); - - b.ToTable("BaseItemProviders"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemTrailerTypes"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ChapterIndex") - .HasColumnType("INTEGER"); - - b.Property("ImageDateModified") - .HasColumnType("TEXT"); - - b.Property("ImagePath") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("StartPositionTicks") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "ChapterIndex"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Property("ItemValueId") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("CleanValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId"); - - b.HasIndex("Type", "CleanValue"); - - b.ToTable("ItemValues"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.Property("ItemValueId") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("ItemValuesMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("EndTicks") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("SegmentProviderId") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("StartTicks") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("MediaSegments"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("StreamIndex") - .HasColumnType("INTEGER"); - - b.Property("AspectRatio") - .HasColumnType("TEXT"); - - b.Property("AverageFrameRate") - .HasColumnType("REAL"); - - b.Property("BitDepth") - .HasColumnType("INTEGER"); - - b.Property("BitRate") - .HasColumnType("INTEGER"); - - b.Property("BlPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("ChannelLayout") - .HasColumnType("TEXT"); - - b.Property("Channels") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .HasColumnType("TEXT"); - - b.Property("CodecTimeBase") - .HasColumnType("TEXT"); - - b.Property("ColorPrimaries") - .HasColumnType("TEXT"); - - b.Property("ColorSpace") - .HasColumnType("TEXT"); - - b.Property("ColorTransfer") - .HasColumnType("TEXT"); - - b.Property("Comment") - .HasColumnType("TEXT"); - - b.Property("DvBlSignalCompatibilityId") - .HasColumnType("INTEGER"); - - b.Property("DvLevel") - .HasColumnType("INTEGER"); - - b.Property("DvProfile") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMajor") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMinor") - .HasColumnType("INTEGER"); - - b.Property("ElPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IsAnamorphic") - .HasColumnType("INTEGER"); - - b.Property("IsAvc") - .HasColumnType("INTEGER"); - - b.Property("IsDefault") - .HasColumnType("INTEGER"); - - b.Property("IsExternal") - .HasColumnType("INTEGER"); - - b.Property("IsForced") - .HasColumnType("INTEGER"); - - b.Property("IsHearingImpaired") - .HasColumnType("INTEGER"); - - b.Property("IsInterlaced") - .HasColumnType("INTEGER"); - - b.Property("KeyFrames") - .HasColumnType("TEXT"); - - b.Property("Language") - .HasColumnType("TEXT"); - - b.Property("Level") - .HasColumnType("REAL"); - - b.Property("NalLengthSize") - .HasColumnType("TEXT"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PixelFormat") - .HasColumnType("TEXT"); - - b.Property("Profile") - .HasColumnType("TEXT"); - - b.Property("RealFrameRate") - .HasColumnType("REAL"); - - b.Property("RefFrames") - .HasColumnType("INTEGER"); - - b.Property("Rotation") - .HasColumnType("INTEGER"); - - b.Property("RpuPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("SampleRate") - .HasColumnType("INTEGER"); - - b.Property("StreamType") - .HasColumnType("INTEGER"); - - b.Property("TimeBase") - .HasColumnType("TEXT"); - - b.Property("Title") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "StreamIndex"); - - b.HasIndex("StreamIndex"); - - b.HasIndex("StreamType"); - - b.HasIndex("StreamIndex", "StreamType"); - - b.HasIndex("StreamIndex", "StreamType", "Language"); - - b.ToTable("MediaStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("PersonType") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("Name"); - - b.ToTable("Peoples"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("PeopleId") - .HasColumnType("TEXT"); - - b.Property("ListOrder") - .HasColumnType("INTEGER"); - - b.Property("Role") - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "PeopleId"); - - b.HasIndex("PeopleId"); - - b.HasIndex("ItemId", "ListOrder"); - - b.HasIndex("ItemId", "SortOrder"); - - b.ToTable("PeopleBaseItemMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.Property("Bandwidth") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("Interval") - .HasColumnType("INTEGER"); - - b.Property("ThumbnailCount") - .HasColumnType("INTEGER"); - - b.Property("TileHeight") - .HasColumnType("INTEGER"); - - b.Property("TileWidth") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "Width"); - - b.ToTable("TrickplayInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("CastReceiverId") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("CustomDataKey") - .HasColumnType("TEXT"); - - b.Property("AudioStreamIndex") - .HasColumnType("INTEGER"); - - b.Property("IsFavorite") - .HasColumnType("INTEGER"); - - b.Property("LastPlayedDate") - .HasColumnType("TEXT"); - - b.Property("Likes") - .HasColumnType("INTEGER"); - - b.Property("PlayCount") - .HasColumnType("INTEGER"); - - b.Property("PlaybackPositionTicks") - .HasColumnType("INTEGER"); - - b.Property("Played") - .HasColumnType("INTEGER"); - - b.Property("Rating") - .HasColumnType("REAL"); - - b.Property("SubtitleStreamIndex") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "UserId", "CustomDataKey"); - - b.HasIndex("UserId"); - - b.HasIndex("ItemId", "UserId", "IsFavorite"); - - b.HasIndex("ItemId", "UserId", "LastPlayedDate"); - - b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); - - b.HasIndex("ItemId", "UserId", "Played"); - - b.ToTable("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Children") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") - .WithMany("ParentAncestors") - .HasForeignKey("ParentItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ParentItem"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany() - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Images") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("LockedFields") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Provider") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("TrailerTypes") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Chapters") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("ItemValues") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") - .WithMany("BaseItemsMap") - .HasForeignKey("ItemValueId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ItemValue"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("MediaStreams") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Peoples") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.People", "People") - .WithMany("BaseItems") - .HasForeignKey("PeopleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("People"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("UserData") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Navigation("Chapters"); - - b.Navigation("Children"); - - b.Navigation("Images"); - - b.Navigation("ItemValues"); - - b.Navigation("LockedFields"); - - b.Navigation("MediaStreams"); - - b.Navigation("ParentAncestors"); - - b.Navigation("Peoples"); - - b.Navigation("Provider"); - - b.Navigation("TrailerTypes"); - - b.Navigation("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Navigation("BaseItemsMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Navigation("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241112234144_FixMediaStreams2.cs b/Jellyfin.Server.Implementations/Migrations/20241112234144_FixMediaStreams2.cs deleted file mode 100644 index 78611b9e4..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241112234144_FixMediaStreams2.cs +++ /dev/null @@ -1,144 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - /// - public partial class FixMediaStreams2 : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "Profile", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "Path", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "Language", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "IsInterlaced", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: true, - oldClrType: typeof(bool), - oldType: "INTEGER"); - - migrationBuilder.AlterColumn( - name: "Codec", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "ChannelLayout", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - - migrationBuilder.AlterColumn( - name: "AspectRatio", - table: "MediaStreamInfos", - type: "TEXT", - nullable: true, - oldClrType: typeof(string), - oldType: "TEXT"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "Profile", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "Path", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "Language", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "IsInterlaced", - table: "MediaStreamInfos", - type: "INTEGER", - nullable: false, - defaultValue: false, - oldClrType: typeof(bool), - oldType: "INTEGER", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "Codec", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "ChannelLayout", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "AspectRatio", - table: "MediaStreamInfos", - type: "TEXT", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "TEXT", - oldNullable: true); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs deleted file mode 100644 index 855f02fd3..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs +++ /dev/null @@ -1,1595 +0,0 @@ -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - [Migration("20241113133548_EnforceUniqueItemValue")] - partial class EnforceUniqueItemValue - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ParentItemId") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ParentItemId"); - - b.HasIndex("ParentItemId"); - - b.ToTable("AncestorIds"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Index") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .HasColumnType("TEXT"); - - b.Property("Comment") - .HasColumnType("TEXT"); - - b.Property("Filename") - .HasColumnType("TEXT"); - - b.Property("MimeType") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "Index"); - - b.ToTable("AttachmentStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Album") - .HasColumnType("TEXT"); - - b.Property("AlbumArtists") - .HasColumnType("TEXT"); - - b.Property("Artists") - .HasColumnType("TEXT"); - - b.Property("Audio") - .HasColumnType("INTEGER"); - - b.Property("ChannelId") - .HasColumnType("TEXT"); - - b.Property("CleanName") - .HasColumnType("TEXT"); - - b.Property("CommunityRating") - .HasColumnType("REAL"); - - b.Property("CriticRating") - .HasColumnType("REAL"); - - b.Property("CustomRating") - .HasColumnType("TEXT"); - - b.Property("Data") - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastMediaAdded") - .HasColumnType("TEXT"); - - b.Property("DateLastRefreshed") - .HasColumnType("TEXT"); - - b.Property("DateLastSaved") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("EndDate") - .HasColumnType("TEXT"); - - b.Property("EpisodeTitle") - .HasColumnType("TEXT"); - - b.Property("ExternalId") - .HasColumnType("TEXT"); - - b.Property("ExternalSeriesId") - .HasColumnType("TEXT"); - - b.Property("ExternalServiceId") - .HasColumnType("TEXT"); - - b.Property("ExtraIds") - .HasColumnType("TEXT"); - - b.Property("ExtraType") - .HasColumnType("INTEGER"); - - b.Property("ForcedSortName") - .HasColumnType("TEXT"); - - b.Property("Genres") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IndexNumber") - .HasColumnType("INTEGER"); - - b.Property("InheritedParentalRatingValue") - .HasColumnType("INTEGER"); - - b.Property("IsFolder") - .HasColumnType("INTEGER"); - - b.Property("IsInMixedFolder") - .HasColumnType("INTEGER"); - - b.Property("IsLocked") - .HasColumnType("INTEGER"); - - b.Property("IsMovie") - .HasColumnType("INTEGER"); - - b.Property("IsRepeat") - .HasColumnType("INTEGER"); - - b.Property("IsSeries") - .HasColumnType("INTEGER"); - - b.Property("IsVirtualItem") - .HasColumnType("INTEGER"); - - b.Property("LUFS") - .HasColumnType("REAL"); - - b.Property("MediaType") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("NormalizationGain") - .HasColumnType("REAL"); - - b.Property("OfficialRating") - .HasColumnType("TEXT"); - - b.Property("OriginalTitle") - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasColumnType("TEXT"); - - b.Property("OwnerId") - .HasColumnType("TEXT"); - - b.Property("ParentId") - .HasColumnType("TEXT"); - - b.Property("ParentIndexNumber") - .HasColumnType("INTEGER"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataCountryCode") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataLanguage") - .HasColumnType("TEXT"); - - b.Property("PremiereDate") - .HasColumnType("TEXT"); - - b.Property("PresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("PrimaryVersionId") - .HasColumnType("TEXT"); - - b.Property("ProductionLocations") - .HasColumnType("TEXT"); - - b.Property("ProductionYear") - .HasColumnType("INTEGER"); - - b.Property("RunTimeTicks") - .HasColumnType("INTEGER"); - - b.Property("SeasonId") - .HasColumnType("TEXT"); - - b.Property("SeasonName") - .HasColumnType("TEXT"); - - b.Property("SeriesId") - .HasColumnType("TEXT"); - - b.Property("SeriesName") - .HasColumnType("TEXT"); - - b.Property("SeriesPresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("ShowId") - .HasColumnType("TEXT"); - - b.Property("Size") - .HasColumnType("INTEGER"); - - b.Property("SortName") - .HasColumnType("TEXT"); - - b.Property("StartDate") - .HasColumnType("TEXT"); - - b.Property("Studios") - .HasColumnType("TEXT"); - - b.Property("Tagline") - .HasColumnType("TEXT"); - - b.Property("Tags") - .HasColumnType("TEXT"); - - b.Property("TopParentId") - .HasColumnType("TEXT"); - - b.Property("TotalBitrate") - .HasColumnType("INTEGER"); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UnratedType") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ParentId"); - - b.HasIndex("Path"); - - b.HasIndex("PresentationUniqueKey"); - - b.HasIndex("TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); - - b.HasIndex("Type", "TopParentId", "StartDate"); - - b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); - - b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); - - b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.ToTable("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Blurhash") - .HasColumnType("BLOB"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("ImageType") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemMetadataFields"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ProviderId") - .HasColumnType("TEXT"); - - b.Property("ProviderValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ProviderId"); - - b.HasIndex("ProviderId", "ProviderValue", "ItemId"); - - b.ToTable("BaseItemProviders"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemTrailerTypes"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ChapterIndex") - .HasColumnType("INTEGER"); - - b.Property("ImageDateModified") - .HasColumnType("TEXT"); - - b.Property("ImagePath") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("StartPositionTicks") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "ChapterIndex"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Property("ItemValueId") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("CleanValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId"); - - b.HasIndex("Type", "CleanValue") - .IsUnique(); - - b.ToTable("ItemValues"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.Property("ItemValueId") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("ItemValuesMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("EndTicks") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("SegmentProviderId") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("StartTicks") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("MediaSegments"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("StreamIndex") - .HasColumnType("INTEGER"); - - b.Property("AspectRatio") - .HasColumnType("TEXT"); - - b.Property("AverageFrameRate") - .HasColumnType("REAL"); - - b.Property("BitDepth") - .HasColumnType("INTEGER"); - - b.Property("BitRate") - .HasColumnType("INTEGER"); - - b.Property("BlPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("ChannelLayout") - .HasColumnType("TEXT"); - - b.Property("Channels") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .HasColumnType("TEXT"); - - b.Property("CodecTimeBase") - .HasColumnType("TEXT"); - - b.Property("ColorPrimaries") - .HasColumnType("TEXT"); - - b.Property("ColorSpace") - .HasColumnType("TEXT"); - - b.Property("ColorTransfer") - .HasColumnType("TEXT"); - - b.Property("Comment") - .HasColumnType("TEXT"); - - b.Property("DvBlSignalCompatibilityId") - .HasColumnType("INTEGER"); - - b.Property("DvLevel") - .HasColumnType("INTEGER"); - - b.Property("DvProfile") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMajor") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMinor") - .HasColumnType("INTEGER"); - - b.Property("ElPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IsAnamorphic") - .HasColumnType("INTEGER"); - - b.Property("IsAvc") - .HasColumnType("INTEGER"); - - b.Property("IsDefault") - .HasColumnType("INTEGER"); - - b.Property("IsExternal") - .HasColumnType("INTEGER"); - - b.Property("IsForced") - .HasColumnType("INTEGER"); - - b.Property("IsHearingImpaired") - .HasColumnType("INTEGER"); - - b.Property("IsInterlaced") - .HasColumnType("INTEGER"); - - b.Property("KeyFrames") - .HasColumnType("TEXT"); - - b.Property("Language") - .HasColumnType("TEXT"); - - b.Property("Level") - .HasColumnType("REAL"); - - b.Property("NalLengthSize") - .HasColumnType("TEXT"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PixelFormat") - .HasColumnType("TEXT"); - - b.Property("Profile") - .HasColumnType("TEXT"); - - b.Property("RealFrameRate") - .HasColumnType("REAL"); - - b.Property("RefFrames") - .HasColumnType("INTEGER"); - - b.Property("Rotation") - .HasColumnType("INTEGER"); - - b.Property("RpuPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("SampleRate") - .HasColumnType("INTEGER"); - - b.Property("StreamType") - .HasColumnType("INTEGER"); - - b.Property("TimeBase") - .HasColumnType("TEXT"); - - b.Property("Title") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "StreamIndex"); - - b.HasIndex("StreamIndex"); - - b.HasIndex("StreamType"); - - b.HasIndex("StreamIndex", "StreamType"); - - b.HasIndex("StreamIndex", "StreamType", "Language"); - - b.ToTable("MediaStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("PersonType") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("Name"); - - b.ToTable("Peoples"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("PeopleId") - .HasColumnType("TEXT"); - - b.Property("ListOrder") - .HasColumnType("INTEGER"); - - b.Property("Role") - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "PeopleId"); - - b.HasIndex("PeopleId"); - - b.HasIndex("ItemId", "ListOrder"); - - b.HasIndex("ItemId", "SortOrder"); - - b.ToTable("PeopleBaseItemMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.Property("Bandwidth") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("Interval") - .HasColumnType("INTEGER"); - - b.Property("ThumbnailCount") - .HasColumnType("INTEGER"); - - b.Property("TileHeight") - .HasColumnType("INTEGER"); - - b.Property("TileWidth") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "Width"); - - b.ToTable("TrickplayInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("CastReceiverId") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("CustomDataKey") - .HasColumnType("TEXT"); - - b.Property("AudioStreamIndex") - .HasColumnType("INTEGER"); - - b.Property("IsFavorite") - .HasColumnType("INTEGER"); - - b.Property("LastPlayedDate") - .HasColumnType("TEXT"); - - b.Property("Likes") - .HasColumnType("INTEGER"); - - b.Property("PlayCount") - .HasColumnType("INTEGER"); - - b.Property("PlaybackPositionTicks") - .HasColumnType("INTEGER"); - - b.Property("Played") - .HasColumnType("INTEGER"); - - b.Property("Rating") - .HasColumnType("REAL"); - - b.Property("SubtitleStreamIndex") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "UserId", "CustomDataKey"); - - b.HasIndex("UserId"); - - b.HasIndex("ItemId", "UserId", "IsFavorite"); - - b.HasIndex("ItemId", "UserId", "LastPlayedDate"); - - b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); - - b.HasIndex("ItemId", "UserId", "Played"); - - b.ToTable("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Children") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") - .WithMany("ParentAncestors") - .HasForeignKey("ParentItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ParentItem"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany() - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Images") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("LockedFields") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Provider") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("TrailerTypes") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Chapters") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("ItemValues") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") - .WithMany("BaseItemsMap") - .HasForeignKey("ItemValueId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ItemValue"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("MediaStreams") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Peoples") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.People", "People") - .WithMany("BaseItems") - .HasForeignKey("PeopleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("People"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("UserData") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Navigation("Chapters"); - - b.Navigation("Children"); - - b.Navigation("Images"); - - b.Navigation("ItemValues"); - - b.Navigation("LockedFields"); - - b.Navigation("MediaStreams"); - - b.Navigation("ParentAncestors"); - - b.Navigation("Peoples"); - - b.Navigation("Provider"); - - b.Navigation("TrailerTypes"); - - b.Navigation("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Navigation("BaseItemsMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Navigation("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20241113133548_EnforceUniqueItemValue.cs b/Jellyfin.Server.Implementations/Migrations/20241113133548_EnforceUniqueItemValue.cs deleted file mode 100644 index d1b06ceae..000000000 --- a/Jellyfin.Server.Implementations/Migrations/20241113133548_EnforceUniqueItemValue.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - /// - public partial class EnforceUniqueItemValue : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_ItemValues_Type_CleanValue", - table: "ItemValues"); - - migrationBuilder.CreateIndex( - name: "IX_ItemValues_Type_CleanValue", - table: "ItemValues", - columns: new[] { "Type", "CleanValue" }, - unique: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_ItemValues_Type_CleanValue", - table: "ItemValues"); - - migrationBuilder.CreateIndex( - name: "IX_ItemValues_Type_CleanValue", - table: "ItemValues", - columns: new[] { "Type", "CleanValue" }); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/DesignTimeJellyfinDbFactory.cs b/Jellyfin.Server.Implementations/Migrations/DesignTimeJellyfinDbFactory.cs deleted file mode 100644 index 500c4a1c7..000000000 --- a/Jellyfin.Server.Implementations/Migrations/DesignTimeJellyfinDbFactory.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Design; -using Microsoft.Extensions.Logging.Abstractions; - -namespace Jellyfin.Server.Implementations.Migrations -{ - /// - /// The design time factory for . - /// This is only used for the creation of migrations and not during runtime. - /// - internal class DesignTimeJellyfinDbFactory : IDesignTimeDbContextFactory - { - public JellyfinDbContext CreateDbContext(string[] args) - { - var optionsBuilder = new DbContextOptionsBuilder(); - optionsBuilder.UseSqlite("Data Source=jellyfin.db"); - - return new JellyfinDbContext(optionsBuilder.Options, NullLogger.Instance); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs deleted file mode 100644 index e75760d80..000000000 --- a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs +++ /dev/null @@ -1,1592 +0,0 @@ -// -using System; -using Jellyfin.Server.Implementations; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Jellyfin.Server.Implementations.Migrations -{ - [DbContext(typeof(JellyfinDbContext))] - partial class JellyfinDbModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("Type") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DateCreated"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ParentItemId") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ParentItemId"); - - b.HasIndex("ParentItemId"); - - b.ToTable("AncestorIds"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Index") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .HasColumnType("TEXT"); - - b.Property("Comment") - .HasColumnType("TEXT"); - - b.Property("Filename") - .HasColumnType("TEXT"); - - b.Property("MimeType") - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "Index"); - - b.ToTable("AttachmentStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Album") - .HasColumnType("TEXT"); - - b.Property("AlbumArtists") - .HasColumnType("TEXT"); - - b.Property("Artists") - .HasColumnType("TEXT"); - - b.Property("Audio") - .HasColumnType("INTEGER"); - - b.Property("ChannelId") - .HasColumnType("TEXT"); - - b.Property("CleanName") - .HasColumnType("TEXT"); - - b.Property("CommunityRating") - .HasColumnType("REAL"); - - b.Property("CriticRating") - .HasColumnType("REAL"); - - b.Property("CustomRating") - .HasColumnType("TEXT"); - - b.Property("Data") - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastMediaAdded") - .HasColumnType("TEXT"); - - b.Property("DateLastRefreshed") - .HasColumnType("TEXT"); - - b.Property("DateLastSaved") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("EndDate") - .HasColumnType("TEXT"); - - b.Property("EpisodeTitle") - .HasColumnType("TEXT"); - - b.Property("ExternalId") - .HasColumnType("TEXT"); - - b.Property("ExternalSeriesId") - .HasColumnType("TEXT"); - - b.Property("ExternalServiceId") - .HasColumnType("TEXT"); - - b.Property("ExtraIds") - .HasColumnType("TEXT"); - - b.Property("ExtraType") - .HasColumnType("INTEGER"); - - b.Property("ForcedSortName") - .HasColumnType("TEXT"); - - b.Property("Genres") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IndexNumber") - .HasColumnType("INTEGER"); - - b.Property("InheritedParentalRatingValue") - .HasColumnType("INTEGER"); - - b.Property("IsFolder") - .HasColumnType("INTEGER"); - - b.Property("IsInMixedFolder") - .HasColumnType("INTEGER"); - - b.Property("IsLocked") - .HasColumnType("INTEGER"); - - b.Property("IsMovie") - .HasColumnType("INTEGER"); - - b.Property("IsRepeat") - .HasColumnType("INTEGER"); - - b.Property("IsSeries") - .HasColumnType("INTEGER"); - - b.Property("IsVirtualItem") - .HasColumnType("INTEGER"); - - b.Property("LUFS") - .HasColumnType("REAL"); - - b.Property("MediaType") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("NormalizationGain") - .HasColumnType("REAL"); - - b.Property("OfficialRating") - .HasColumnType("TEXT"); - - b.Property("OriginalTitle") - .HasColumnType("TEXT"); - - b.Property("Overview") - .HasColumnType("TEXT"); - - b.Property("OwnerId") - .HasColumnType("TEXT"); - - b.Property("ParentId") - .HasColumnType("TEXT"); - - b.Property("ParentIndexNumber") - .HasColumnType("INTEGER"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataCountryCode") - .HasColumnType("TEXT"); - - b.Property("PreferredMetadataLanguage") - .HasColumnType("TEXT"); - - b.Property("PremiereDate") - .HasColumnType("TEXT"); - - b.Property("PresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("PrimaryVersionId") - .HasColumnType("TEXT"); - - b.Property("ProductionLocations") - .HasColumnType("TEXT"); - - b.Property("ProductionYear") - .HasColumnType("INTEGER"); - - b.Property("RunTimeTicks") - .HasColumnType("INTEGER"); - - b.Property("SeasonId") - .HasColumnType("TEXT"); - - b.Property("SeasonName") - .HasColumnType("TEXT"); - - b.Property("SeriesId") - .HasColumnType("TEXT"); - - b.Property("SeriesName") - .HasColumnType("TEXT"); - - b.Property("SeriesPresentationUniqueKey") - .HasColumnType("TEXT"); - - b.Property("ShowId") - .HasColumnType("TEXT"); - - b.Property("Size") - .HasColumnType("INTEGER"); - - b.Property("SortName") - .HasColumnType("TEXT"); - - b.Property("StartDate") - .HasColumnType("TEXT"); - - b.Property("Studios") - .HasColumnType("TEXT"); - - b.Property("Tagline") - .HasColumnType("TEXT"); - - b.Property("Tags") - .HasColumnType("TEXT"); - - b.Property("TopParentId") - .HasColumnType("TEXT"); - - b.Property("TotalBitrate") - .HasColumnType("INTEGER"); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UnratedType") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ParentId"); - - b.HasIndex("Path"); - - b.HasIndex("PresentationUniqueKey"); - - b.HasIndex("TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "Id"); - - b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); - - b.HasIndex("Type", "TopParentId", "StartDate"); - - b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); - - b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); - - b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); - - b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); - - b.ToTable("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Blurhash") - .HasColumnType("BLOB"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("ImageType") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemMetadataFields"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ProviderId") - .HasColumnType("TEXT"); - - b.Property("ProviderValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemId", "ProviderId"); - - b.HasIndex("ProviderId", "ProviderValue", "ItemId"); - - b.ToTable("BaseItemProviders"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.Property("Id") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("Id", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("BaseItemTrailerTypes"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ChapterIndex") - .HasColumnType("INTEGER"); - - b.Property("ImageDateModified") - .HasColumnType("TEXT"); - - b.Property("ImagePath") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("StartPositionTicks") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "ChapterIndex"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Key") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client", "Key") - .IsUnique(); - - b.ToTable("CustomItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DashboardTheme") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("TvHome") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "ItemId", "Client") - .IsUnique(); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("ItemDisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Property("ItemValueId") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("CleanValue") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.Property("Value") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId"); - - b.HasIndex("Type", "CleanValue") - .IsUnique(); - - b.ToTable("ItemValues"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.Property("ItemValueId") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.HasKey("ItemValueId", "ItemId"); - - b.HasIndex("ItemId"); - - b.ToTable("ItemValuesMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("EndTicks") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("SegmentProviderId") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("StartTicks") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("MediaSegments"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("StreamIndex") - .HasColumnType("INTEGER"); - - b.Property("AspectRatio") - .HasColumnType("TEXT"); - - b.Property("AverageFrameRate") - .HasColumnType("REAL"); - - b.Property("BitDepth") - .HasColumnType("INTEGER"); - - b.Property("BitRate") - .HasColumnType("INTEGER"); - - b.Property("BlPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("ChannelLayout") - .HasColumnType("TEXT"); - - b.Property("Channels") - .HasColumnType("INTEGER"); - - b.Property("Codec") - .HasColumnType("TEXT"); - - b.Property("CodecTag") - .HasColumnType("TEXT"); - - b.Property("CodecTimeBase") - .HasColumnType("TEXT"); - - b.Property("ColorPrimaries") - .HasColumnType("TEXT"); - - b.Property("ColorSpace") - .HasColumnType("TEXT"); - - b.Property("ColorTransfer") - .HasColumnType("TEXT"); - - b.Property("Comment") - .HasColumnType("TEXT"); - - b.Property("DvBlSignalCompatibilityId") - .HasColumnType("INTEGER"); - - b.Property("DvLevel") - .HasColumnType("INTEGER"); - - b.Property("DvProfile") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMajor") - .HasColumnType("INTEGER"); - - b.Property("DvVersionMinor") - .HasColumnType("INTEGER"); - - b.Property("ElPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("IsAnamorphic") - .HasColumnType("INTEGER"); - - b.Property("IsAvc") - .HasColumnType("INTEGER"); - - b.Property("IsDefault") - .HasColumnType("INTEGER"); - - b.Property("IsExternal") - .HasColumnType("INTEGER"); - - b.Property("IsForced") - .HasColumnType("INTEGER"); - - b.Property("IsHearingImpaired") - .HasColumnType("INTEGER"); - - b.Property("IsInterlaced") - .HasColumnType("INTEGER"); - - b.Property("KeyFrames") - .HasColumnType("TEXT"); - - b.Property("Language") - .HasColumnType("TEXT"); - - b.Property("Level") - .HasColumnType("REAL"); - - b.Property("NalLengthSize") - .HasColumnType("TEXT"); - - b.Property("Path") - .HasColumnType("TEXT"); - - b.Property("PixelFormat") - .HasColumnType("TEXT"); - - b.Property("Profile") - .HasColumnType("TEXT"); - - b.Property("RealFrameRate") - .HasColumnType("REAL"); - - b.Property("RefFrames") - .HasColumnType("INTEGER"); - - b.Property("Rotation") - .HasColumnType("INTEGER"); - - b.Property("RpuPresentFlag") - .HasColumnType("INTEGER"); - - b.Property("SampleRate") - .HasColumnType("INTEGER"); - - b.Property("StreamType") - .HasColumnType("INTEGER"); - - b.Property("TimeBase") - .HasColumnType("TEXT"); - - b.Property("Title") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "StreamIndex"); - - b.HasIndex("StreamIndex"); - - b.HasIndex("StreamType"); - - b.HasIndex("StreamIndex", "StreamType"); - - b.HasIndex("StreamIndex", "StreamType", "Language"); - - b.ToTable("MediaStreamInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("PersonType") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("Name"); - - b.ToTable("Peoples"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("PeopleId") - .HasColumnType("TEXT"); - - b.Property("ListOrder") - .HasColumnType("INTEGER"); - - b.Property("Role") - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "PeopleId"); - - b.HasIndex("PeopleId"); - - b.HasIndex("ItemId", "ListOrder"); - - b.HasIndex("ItemId", "SortOrder"); - - b.ToTable("PeopleBaseItemMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId", "Kind") - .IsUnique() - .HasFilter("[UserId] IS NOT NULL"); - - b.ToTable("Preferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("AccessToken") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("AppName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("AppVersion") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("DateLastActivity") - .HasColumnType("TEXT"); - - b.Property("DateModified") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("TEXT"); - - b.Property("IsActive") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId"); - - b.HasIndex("AccessToken", "DateLastActivity"); - - b.HasIndex("DeviceId", "DateLastActivity"); - - b.HasIndex("UserId", "DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CustomName") - .HasColumnType("TEXT"); - - b.Property("DeviceId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("DeviceId") - .IsUnique(); - - b.ToTable("DeviceOptions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("Width") - .HasColumnType("INTEGER"); - - b.Property("Bandwidth") - .HasColumnType("INTEGER"); - - b.Property("Height") - .HasColumnType("INTEGER"); - - b.Property("Interval") - .HasColumnType("INTEGER"); - - b.Property("ThumbnailCount") - .HasColumnType("INTEGER"); - - b.Property("TileHeight") - .HasColumnType("INTEGER"); - - b.Property("TileWidth") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "Width"); - - b.ToTable("TrickplayInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("CastReceiverId") - .HasMaxLength(32) - .HasColumnType("TEXT"); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxActiveSessions") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasMaxLength(255) - .HasColumnType("TEXT"); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("TEXT") - .UseCollation("NOCASE"); - - b.HasKey("Id"); - - b.HasIndex("Username") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("CustomDataKey") - .HasColumnType("TEXT"); - - b.Property("AudioStreamIndex") - .HasColumnType("INTEGER"); - - b.Property("IsFavorite") - .HasColumnType("INTEGER"); - - b.Property("LastPlayedDate") - .HasColumnType("TEXT"); - - b.Property("Likes") - .HasColumnType("INTEGER"); - - b.Property("PlayCount") - .HasColumnType("INTEGER"); - - b.Property("PlaybackPositionTicks") - .HasColumnType("INTEGER"); - - b.Property("Played") - .HasColumnType("INTEGER"); - - b.Property("Rating") - .HasColumnType("REAL"); - - b.Property("SubtitleStreamIndex") - .HasColumnType("INTEGER"); - - b.HasKey("ItemId", "UserId", "CustomDataKey"); - - b.HasIndex("UserId"); - - b.HasIndex("ItemId", "UserId", "IsFavorite"); - - b.HasIndex("ItemId", "UserId", "LastPlayedDate"); - - b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); - - b.HasIndex("ItemId", "UserId", "Played"); - - b.ToTable("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("AccessSchedules") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Children") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") - .WithMany("ParentAncestors") - .HasForeignKey("ParentItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ParentItem"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany() - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Images") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("LockedFields") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Provider") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("TrailerTypes") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Chapters") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) - .WithMany("HomeSections") - .HasForeignKey("DisplayPreferencesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("ItemDisplayPreferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("ItemValues") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") - .WithMany("BaseItemsMap") - .HasForeignKey("ItemValueId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("ItemValue"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("MediaStreams") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("Peoples") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.People", "People") - .WithMany("BaseItems") - .HasForeignKey("PeopleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("People"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Permissions") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("Preferences") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => - { - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => - { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") - .WithMany("UserData") - .HasForeignKey("ItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Jellyfin.Data.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Item"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => - { - b.Navigation("Chapters"); - - b.Navigation("Children"); - - b.Navigation("Images"); - - b.Navigation("ItemValues"); - - b.Navigation("LockedFields"); - - b.Navigation("MediaStreams"); - - b.Navigation("ParentAncestors"); - - b.Navigation("Peoples"); - - b.Navigation("Provider"); - - b.Navigation("TrailerTypes"); - - b.Navigation("UserData"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Navigation("HomeSections"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => - { - b.Navigation("BaseItemsMap"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => - { - b.Navigation("BaseItems"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => - { - b.Navigation("AccessSchedules"); - - b.Navigation("DisplayPreferences"); - - b.Navigation("ItemDisplayPreferences"); - - b.Navigation("Permissions"); - - b.Navigation("Preferences"); - - b.Navigation("ProfileImage"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/ActivityLogConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/ActivityLogConfiguration.cs deleted file mode 100644 index 9a63ed9f2..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/ActivityLogConfiguration.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// FluentAPI configuration for the ActivityLog entity. -/// -public class ActivityLogConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasIndex(entity => entity.DateCreated); - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/AncestorIdConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/AncestorIdConfiguration.cs deleted file mode 100644 index 8cc817fb8..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/AncestorIdConfiguration.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// AncestorId configuration. -/// -public class AncestorIdConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => new { e.ItemId, e.ParentItemId }); - builder.HasIndex(e => e.ParentItemId); - builder.HasOne(e => e.ParentItem).WithMany(e => e.ParentAncestors).HasForeignKey(f => f.ParentItemId); - builder.HasOne(e => e.Item).WithMany(e => e.Children).HasForeignKey(f => f.ItemId); - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs deleted file mode 100644 index 3f19b6986..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Jellyfin.Data.Entities.Security; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration -{ - /// - /// FluentAPI configuration for the ApiKey entity. - /// - public class ApiKeyConfiguration : IEntityTypeConfiguration - { - /// - public void Configure(EntityTypeBuilder builder) - { - builder - .HasIndex(entity => entity.AccessToken) - .IsUnique(); - } - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs deleted file mode 100644 index 057b6689a..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// FluentAPI configuration for the AttachmentStreamInfo entity. -/// -public class AttachmentStreamInfoConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => new { e.ItemId, e.Index }); - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/BaseItemConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/BaseItemConfiguration.cs deleted file mode 100644 index eaf48981c..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/BaseItemConfiguration.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using SQLitePCL; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// Configuration for BaseItem. -/// -public class BaseItemConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => e.Id); - // TODO: See rant in entity file. - // builder.HasOne(e => e.Parent).WithMany(e => e.DirectChildren).HasForeignKey(e => e.ParentId); - // builder.HasOne(e => e.TopParent).WithMany(e => e.AllChildren).HasForeignKey(e => e.TopParentId); - // builder.HasOne(e => e.Season).WithMany(e => e.SeasonEpisodes).HasForeignKey(e => e.SeasonId); - // builder.HasOne(e => e.Series).WithMany(e => e.SeriesEpisodes).HasForeignKey(e => e.SeriesId); - builder.HasMany(e => e.Peoples); - builder.HasMany(e => e.UserData); - builder.HasMany(e => e.ItemValues); - builder.HasMany(e => e.MediaStreams); - builder.HasMany(e => e.Chapters); - builder.HasMany(e => e.Provider); - builder.HasMany(e => e.ParentAncestors); - builder.HasMany(e => e.Children); - builder.HasMany(e => e.LockedFields); - builder.HasMany(e => e.TrailerTypes); - builder.HasMany(e => e.Images); - - builder.HasIndex(e => e.Path); - builder.HasIndex(e => e.ParentId); - builder.HasIndex(e => e.PresentationUniqueKey); - builder.HasIndex(e => new { e.Id, e.Type, e.IsFolder, e.IsVirtualItem }); - - // covering index - builder.HasIndex(e => new { e.TopParentId, e.Id }); - // series - builder.HasIndex(e => new { e.Type, e.SeriesPresentationUniqueKey, e.PresentationUniqueKey, e.SortName }); - // series counts - // seriesdateplayed sort order - builder.HasIndex(e => new { e.Type, e.SeriesPresentationUniqueKey, e.IsFolder, e.IsVirtualItem }); - // live tv programs - builder.HasIndex(e => new { e.Type, e.TopParentId, e.StartDate }); - // covering index for getitemvalues - builder.HasIndex(e => new { e.Type, e.TopParentId, e.Id }); - // used by movie suggestions - builder.HasIndex(e => new { e.Type, e.TopParentId, e.PresentationUniqueKey }); - // latest items - builder.HasIndex(e => new { e.Type, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey, e.DateCreated }); - builder.HasIndex(e => new { e.IsFolder, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey, e.DateCreated }); - // resume - builder.HasIndex(e => new { e.MediaType, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey }); - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs deleted file mode 100644 index 137f4a883..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Linq; -using Jellyfin.Data.Entities; -using MediaBrowser.Model.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using SQLitePCL; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// Provides configuration for the BaseItemMetadataField entity. -/// -public class BaseItemMetadataFieldConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => new { e.Id, e.ItemId }); - builder.HasOne(e => e.Item); - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs deleted file mode 100644 index d15049a1f..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// BaseItemProvider configuration. -/// -public class BaseItemProviderConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => new { e.ItemId, e.ProviderId }); - builder.HasOne(e => e.Item); - builder.HasIndex(e => new { e.ProviderId, e.ProviderValue, e.ItemId }); - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs deleted file mode 100644 index f03d99c29..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Linq; -using Jellyfin.Data.Entities; -using MediaBrowser.Model.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using SQLitePCL; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// Provides configuration for the BaseItemMetadataField entity. -/// -public class BaseItemTrailerTypeConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => new { e.Id, e.ItemId }); - builder.HasOne(e => e.Item); - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/ChapterConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/ChapterConfiguration.cs deleted file mode 100644 index 5a84f7750..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/ChapterConfiguration.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// Chapter configuration. -/// -public class ChapterConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => new { e.ItemId, e.ChapterIndex }); - builder.HasOne(e => e.Item); - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs deleted file mode 100644 index 779aec986..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration -{ - /// - /// FluentAPI configuration for the CustomItemDisplayPreferences entity. - /// - public class CustomItemDisplayPreferencesConfiguration : IEntityTypeConfiguration - { - /// - public void Configure(EntityTypeBuilder builder) - { - builder - .HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client, entity.Key }) - .IsUnique(); - } - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/DeviceConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/DeviceConfiguration.cs deleted file mode 100644 index a750b65c0..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/DeviceConfiguration.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Jellyfin.Data.Entities.Security; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration -{ - /// - /// FluentAPI configuration for the Device entity. - /// - public class DeviceConfiguration : IEntityTypeConfiguration - { - /// - public void Configure(EntityTypeBuilder builder) - { - builder - .HasIndex(entity => new { entity.DeviceId, entity.DateLastActivity }); - - builder - .HasIndex(entity => new { entity.AccessToken, entity.DateLastActivity }); - - builder - .HasIndex(entity => new { entity.UserId, entity.DeviceId }); - - builder - .HasIndex(entity => entity.DeviceId); - } - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs deleted file mode 100644 index 038afd752..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Jellyfin.Data.Entities.Security; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration -{ - /// - /// FluentAPI configuration for the DeviceOptions entity. - /// - public class DeviceOptionsConfiguration : IEntityTypeConfiguration - { - /// - public void Configure(EntityTypeBuilder builder) - { - builder - .HasIndex(entity => entity.DeviceId) - .IsUnique(); - } - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs deleted file mode 100644 index 9b437861b..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration -{ - /// - /// FluentAPI configuration for the DisplayPreferencesConfiguration entity. - /// - public class DisplayPreferencesConfiguration : IEntityTypeConfiguration - { - /// - public void Configure(EntityTypeBuilder builder) - { - builder - .HasMany(d => d.HomeSections) - .WithOne() - .OnDelete(DeleteBehavior.Cascade); - - builder - .HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client }) - .IsUnique(); - } - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/ItemValuesConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/ItemValuesConfiguration.cs deleted file mode 100644 index abeeb09c9..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/ItemValuesConfiguration.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// itemvalues Configuration. -/// -public class ItemValuesConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => e.ItemValueId); - builder.HasIndex(e => new { e.Type, e.CleanValue }).IsUnique(); - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs deleted file mode 100644 index 9c22b114c..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// itemvalues Configuration. -/// -public class ItemValuesMapConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => new { e.ItemValueId, e.ItemId }); - builder.HasOne(e => e.Item); - builder.HasOne(e => e.ItemValue); - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs deleted file mode 100644 index 7e572f9a3..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// People configuration. -/// -public class MediaStreamInfoConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => new { e.ItemId, e.StreamIndex }); - builder.HasIndex(e => e.StreamIndex); - builder.HasIndex(e => e.StreamType); - builder.HasIndex(e => new { e.StreamIndex, e.StreamType }); - builder.HasIndex(e => new { e.StreamIndex, e.StreamType, e.Language }); - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs deleted file mode 100644 index cdaee9161..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// People configuration. -/// -public class PeopleBaseItemMapConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => new { e.ItemId, e.PeopleId }); - builder.HasIndex(e => new { e.ItemId, e.SortOrder }); - builder.HasIndex(e => new { e.ItemId, e.ListOrder }); - builder.HasOne(e => e.Item); - builder.HasOne(e => e.People); - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/PeopleConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/PeopleConfiguration.cs deleted file mode 100644 index f3cccb13f..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/PeopleConfiguration.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// People configuration. -/// -public class PeopleConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => e.Id); - builder.HasIndex(e => e.Name); - builder.HasMany(e => e.BaseItems); - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/PermissionConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/PermissionConfiguration.cs deleted file mode 100644 index 240e284c0..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/PermissionConfiguration.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration -{ - /// - /// FluentAPI configuration for the Permission entity. - /// - public class PermissionConfiguration : IEntityTypeConfiguration - { - /// - public void Configure(EntityTypeBuilder builder) - { - // Used to get a user's permissions or a specific permission for a user. - // Also prevents multiple values being created for a user. - // Filtered over non-null user ids for when other entities (groups, API keys) get permissions - builder - .HasIndex(p => new { p.UserId, p.Kind }) - .HasFilter("[UserId] IS NOT NULL") - .IsUnique(); - } - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/PreferenceConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/PreferenceConfiguration.cs deleted file mode 100644 index 49c869c6a..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/PreferenceConfiguration.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration -{ - /// - /// FluentAPI configuration for the Permission entity. - /// - public class PreferenceConfiguration : IEntityTypeConfiguration - { - /// - public void Configure(EntityTypeBuilder builder) - { - builder - .HasIndex(p => new { p.UserId, p.Kind }) - .HasFilter("[UserId] IS NOT NULL") - .IsUnique(); - } - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs deleted file mode 100644 index dc1c17e5e..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration -{ - /// - /// FluentAPI configuration for the TrickplayInfo entity. - /// - public class TrickplayInfoConfiguration : IEntityTypeConfiguration - { - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(info => new { info.ItemId, info.Width }); - } - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/UserConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/UserConfiguration.cs deleted file mode 100644 index a369cf656..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/UserConfiguration.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration -{ - /// - /// FluentAPI configuration for the User entity. - /// - public class UserConfiguration : IEntityTypeConfiguration - { - /// - public void Configure(EntityTypeBuilder builder) - { - builder - .Property(user => user.Username) - .UseCollation("NOCASE"); - - builder - .HasOne(u => u.ProfileImage) - .WithOne() - .OnDelete(DeleteBehavior.Cascade); - - builder - .HasMany(u => u.Permissions) - .WithOne() - .HasForeignKey(p => p.UserId) - .OnDelete(DeleteBehavior.Cascade); - - builder - .HasMany(u => u.Preferences) - .WithOne() - .HasForeignKey(p => p.UserId) - .OnDelete(DeleteBehavior.Cascade); - - builder - .HasMany(u => u.AccessSchedules) - .WithOne() - .OnDelete(DeleteBehavior.Cascade); - - builder - .HasMany(u => u.DisplayPreferences) - .WithOne() - .OnDelete(DeleteBehavior.Cascade); - - builder - .HasMany(u => u.ItemDisplayPreferences) - .WithOne() - .OnDelete(DeleteBehavior.Cascade); - - builder - .HasIndex(entity => entity.Username) - .IsUnique(); - } - } -} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/UserDataConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/UserDataConfiguration.cs deleted file mode 100644 index 7bbb28d43..000000000 --- a/Jellyfin.Server.Implementations/ModelConfiguration/UserDataConfiguration.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using Jellyfin.Data.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Jellyfin.Server.Implementations.ModelConfiguration; - -/// -/// FluentAPI configuration for the UserData entity. -/// -public class UserDataConfiguration : IEntityTypeConfiguration -{ - /// - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(d => new { d.ItemId, d.UserId, d.CustomDataKey }); - builder.HasIndex(d => new { d.ItemId, d.UserId, d.Played }); - builder.HasIndex(d => new { d.ItemId, d.UserId, d.PlaybackPositionTicks }); - builder.HasIndex(d => new { d.ItemId, d.UserId, d.IsFavorite }); - builder.HasIndex(d => new { d.ItemId, d.UserId, d.LastPlayedDate }); - builder.HasOne(e => e.Item); - } -} diff --git a/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs b/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs index 45b0a0853..27222a183 100644 --- a/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs +++ b/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs @@ -1,5 +1,6 @@ using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index c7ae0f4db..44de11b66 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -7,6 +7,7 @@ using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index ebb12ba4e..bd094d691 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -66,6 +66,7 @@ + diff --git a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs index d0360a56d..13ea61d65 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs @@ -9,6 +9,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Text; +using System.Threading; using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities; using Jellyfin.Extensions; @@ -33,6 +34,7 @@ public class MigrateLibraryDb : IMigrationRoutine private readonly ILogger _logger; private readonly IServerApplicationPaths _paths; + private readonly IJellyfinDatabaseProvider _jellyfinDatabaseProvider; private readonly IDbContextFactory _provider; /// @@ -41,14 +43,17 @@ public class MigrateLibraryDb : IMigrationRoutine /// The logger. /// The database provider. /// The server application paths. + /// The database provider for special access. public MigrateLibraryDb( ILogger logger, IDbContextFactory provider, - IServerApplicationPaths paths) + IServerApplicationPaths paths, + IJellyfinDatabaseProvider jellyfinDatabaseProvider) { _logger = logger; _provider = provider; _paths = paths; + _jellyfinDatabaseProvider = jellyfinDatabaseProvider; } /// @@ -319,17 +324,7 @@ public class MigrateLibraryDb : IMigrationRoutine _logger.LogInformation("Migrating Library db took {0}.", migrationTotalTime); - if (dbContext.Database.IsSqlite()) - { - _logger.LogInformation("Vaccum and Optimise jellyfin.db now."); - dbContext.Database.ExecuteSqlRaw("PRAGMA optimize"); - dbContext.Database.ExecuteSqlRaw("VACUUM"); - _logger.LogInformation("jellyfin.db optimized successfully!"); - } - else - { - _logger.LogInformation("This database doesn't support optimization"); - } + _jellyfinDatabaseProvider.RunScheduledOptimisation(CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult(); } private UserData? GetUserData(ImmutableArray users, SqliteDataReader dto) diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index 7dcae5bd9..f126230fb 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -1,6 +1,7 @@ using System; using System.IO; using Emby.Server.Implementations.Data; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions.Json; diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 3f73c15b4..a6270aa93 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -194,23 +194,11 @@ namespace Jellyfin.Server // Don't throw additional exception if startup failed. if (appHost.ServiceProvider is not null) { - var isSqlite = false; _logger.LogInformation("Running query planner optimizations in the database... This might take a while"); - // Run before disposing the application - var context = await appHost.ServiceProvider.GetRequiredService>().CreateDbContextAsync().ConfigureAwait(false); - await using (context.ConfigureAwait(false)) - { - if (context.Database.IsSqlite()) - { - isSqlite = true; - await context.Database.ExecuteSqlRawAsync("PRAGMA optimize").ConfigureAwait(false); - } - } - if (isSqlite) - { - SqliteConnection.ClearAllPools(); - } + var databaseProvider = appHost.ServiceProvider.GetRequiredService(); + + await databaseProvider.DisposeAsync().ConfigureAwait(false); } host?.Dispose(); diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs index c68661469..850b653e1 100644 --- a/Jellyfin.Server/Startup.cs +++ b/Jellyfin.Server/Startup.cs @@ -67,7 +67,7 @@ namespace Jellyfin.Server // TODO remove once this is fixed upstream https://github.com/dotnet/aspnetcore/issues/34371 services.AddSingleton, SymlinkFollowingPhysicalFileResultExecutor>(); services.AddJellyfinApi(_serverApplicationHost.GetApiPluginAssemblies(), _serverConfigurationManager.GetNetworkConfiguration()); - services.AddJellyfinDbContext(); + services.AddJellyfinDbContext(_serverApplicationHost.ConfigurationManager); services.AddJellyfinApiSwagger(); // configure custom legacy authentication diff --git a/Jellyfin.sln b/Jellyfin.sln index edef9b7a5..e6642c296 100644 --- a/Jellyfin.sln +++ b/Jellyfin.sln @@ -87,6 +87,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.LiveTv.Tests", "te EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.LiveTv", "src\Jellyfin.LiveTv\Jellyfin.LiveTv.csproj", "{8C6B2B13-58A4-4506-9DAB-1F882A093FE0}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Jellyfin.Database", "Jellyfin.Database", "{4C54CE05-69C8-48FA-8785-39F7F6DB1CAD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Database.SqLite", "Jellyfin.Database\Jellyfin.Database.Providers.SqLite\Jellyfin.Database.Providers.SqLite.csproj", "{A5590358-33CC-4B39-BDE7-DC62FEB03C76}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Database.PgSql", "Jellyfin.Database\Jellyfin.Database.Providers.PgSql\Jellyfin.Database.Providers.PgSql.csproj", "{EC91A604-C99E-44E2-BB74-B4EB2A4B6A0C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Database.Implementations", "Jellyfin.Database\Jellyfin.Database.Implementations\Jellyfin.Database.Implementations.csproj", "{8C9F9221-8415-496C-B1F5-E7756F03FA59}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -241,17 +249,32 @@ Global {8C6B2B13-58A4-4506-9DAB-1F882A093FE0}.Debug|Any CPU.Build.0 = Debug|Any CPU {8C6B2B13-58A4-4506-9DAB-1F882A093FE0}.Release|Any CPU.ActiveCfg = Release|Any CPU {8C6B2B13-58A4-4506-9DAB-1F882A093FE0}.Release|Any CPU.Build.0 = Release|Any CPU + {A5590358-33CC-4B39-BDE7-DC62FEB03C76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A5590358-33CC-4B39-BDE7-DC62FEB03C76}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A5590358-33CC-4B39-BDE7-DC62FEB03C76}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A5590358-33CC-4B39-BDE7-DC62FEB03C76}.Release|Any CPU.Build.0 = Release|Any CPU + {EC91A604-C99E-44E2-BB74-B4EB2A4B6A0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EC91A604-C99E-44E2-BB74-B4EB2A4B6A0C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EC91A604-C99E-44E2-BB74-B4EB2A4B6A0C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EC91A604-C99E-44E2-BB74-B4EB2A4B6A0C}.Release|Any CPU.Build.0 = Release|Any CPU + {8C9F9221-8415-496C-B1F5-E7756F03FA59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C9F9221-8415-496C-B1F5-E7756F03FA59}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C9F9221-8415-496C-B1F5-E7756F03FA59}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C9F9221-8415-496C-B1F5-E7756F03FA59}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {08FFF49B-F175-4807-A2B5-73B0EBD9F716} = {C9F0AB5D-F4D7-40C8-A353-3305C86D6D4C} + {154872D9-6C12-4007-96E3-8F70A58386CE} = {C9F0AB5D-F4D7-40C8-A353-3305C86D6D4C} {DF194677-DFD3-42AF-9F75-D44D5A416478} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} {28464062-0939-4AA7-9F7B-24DDDA61A7C0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} {3998657B-1CCC-49DD-A19F-275DC8495F57} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} {A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} {2E3A1B4B-4225-4AAA-8B29-0181A84E7AEE} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} {462584F7-5023-4019-9EAC-B98CA458C0A0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} + {0A3FCC4D-C714-4072-B90F-E374A15F9FF9} = {C9F0AB5D-F4D7-40C8-A353-3305C86D6D4C} {30922383-D513-4F4D-B890-A940B57FA353} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} {FC1BC0CE-E8D2-4AE9-A6AB-8A02143B335D} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} {42816EA8-4511-4CBF-A9C7-7791D5DDDAE6} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} @@ -264,11 +287,11 @@ Global {DA9FD356-4894-4830-B208-D6BCE3E65B11} = {C9F0AB5D-F4D7-40C8-A353-3305C86D6D4C} {FE47334C-EFDE-4519-BD50-F24430FF360B} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} {24960660-DE6C-47BF-AEEF-CEE8F19FE6C2} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} - {08FFF49B-F175-4807-A2B5-73B0EBD9F716} = {C9F0AB5D-F4D7-40C8-A353-3305C86D6D4C} - {154872D9-6C12-4007-96E3-8F70A58386CE} = {C9F0AB5D-F4D7-40C8-A353-3305C86D6D4C} - {0A3FCC4D-C714-4072-B90F-E374A15F9FF9} = {C9F0AB5D-F4D7-40C8-A353-3305C86D6D4C} {C4F71272-C6BE-4C30-BE0D-4E6ED651D6D3} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} {8C6B2B13-58A4-4506-9DAB-1F882A093FE0} = {C9F0AB5D-F4D7-40C8-A353-3305C86D6D4C} + {A5590358-33CC-4B39-BDE7-DC62FEB03C76} = {4C54CE05-69C8-48FA-8785-39F7F6DB1CAD} + {EC91A604-C99E-44E2-BB74-B4EB2A4B6A0C} = {4C54CE05-69C8-48FA-8785-39F7F6DB1CAD} + {8C9F9221-8415-496C-B1F5-E7756F03FA59} = {4C54CE05-69C8-48FA-8785-39F7F6DB1CAD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3448830C-EBDC-426C-85CD-7BBB9651A7FE} diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index f186523b9..b289a3dd1 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -7,6 +7,7 @@ using System.Globalization; using System.Linq; using System.Text.Json.Serialization; using System.Threading; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index f3873775b..3b0938ea7 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 537550925..b857d9537 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index a6bc35a9f..6b19cdea3 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -12,6 +12,7 @@ using System.Text; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index a13f04614..9605782ae 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -13,6 +13,7 @@ using System.Threading; using System.Threading.Tasks; using System.Threading.Tasks.Dataflow; using J2N.Collections.Generic.Extensions; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 43f02fb72..0bd28154d 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index d0c9f049a..a73cc917e 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Text.Json.Serialization; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Providers; diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 137d91f1c..f3c252dec 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -9,12 +9,12 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Providers; using MediaBrowser.Model.Querying; using MetadataProvider = MediaBrowser.Model.Entities.MetadataProvider; diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 4ec2e4c0a..367080867 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 9399679a4..cd3172668 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -13,6 +13,7 @@ using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Threading; +using Jellyfin.Data; using Jellyfin.Data.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index bf6871a74..a3b5aa9a6 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; diff --git a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs index 57557d55c..d35ed57b8 100644 --- a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs +++ b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs @@ -10,6 +10,7 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; +using Jellyfin.Data; using Jellyfin.Data.Enums; using Jellyfin.Extensions; using MediaBrowser.Common; diff --git a/src/Jellyfin.LiveTv/LiveTvManager.cs b/src/Jellyfin.LiveTv/LiveTvManager.cs index 0c85dc434..da98606a4 100644 --- a/src/Jellyfin.LiveTv/LiveTvManager.cs +++ b/src/Jellyfin.LiveTv/LiveTvManager.cs @@ -8,6 +8,7 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; diff --git a/src/Jellyfin.LiveTv/Recordings/RecordingNotifier.cs b/src/Jellyfin.LiveTv/Recordings/RecordingNotifier.cs index e63afa626..1d571805b 100644 --- a/src/Jellyfin.LiveTv/Recordings/RecordingNotifier.cs +++ b/src/Jellyfin.LiveTv/Recordings/RecordingNotifier.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using MediaBrowser.Controller.Library; diff --git a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs index 6f5c0ed0c..99f10583c 100644 --- a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs @@ -6,6 +6,7 @@ using AutoFixture; using AutoFixture.AutoMoq; using Jellyfin.Api.Auth; using Jellyfin.Api.Constants; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Authentication; diff --git a/tests/Jellyfin.Api.Tests/TestHelpers.cs b/tests/Jellyfin.Api.Tests/TestHelpers.cs index 12cf025bc..d84da89e2 100644 --- a/tests/Jellyfin.Api.Tests/TestHelpers.cs +++ b/tests/Jellyfin.Api.Tests/TestHelpers.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Net; using System.Security.Claims; using Jellyfin.Api.Constants; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Server.Implementations.Users; diff --git a/tests/Jellyfin.Server.Implementations.Tests/EfMigrations/EfMigrationTests.cs b/tests/Jellyfin.Server.Implementations.Tests/EfMigrations/EfMigrationTests.cs index e6ccae183..54d5d2adf 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/EfMigrations/EfMigrationTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/EfMigrations/EfMigrationTests.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using Jellyfin.Server.Implementations.Migrations; using Microsoft.EntityFrameworkCore; using Xunit; @@ -8,11 +7,11 @@ namespace Jellyfin.Server.Implementations.Tests.EfMigrations; public class EfMigrationTests { - [Fact] - public void CheckForUnappliedMigrations() - { - var dbDesignContext = new DesignTimeJellyfinDbFactory(); - var context = dbDesignContext.CreateDbContext([]); - Assert.False(context.Database.HasPendingModelChanges(), "There are unapplied changes to the EfCore model. Please create a Migration."); - } + // [Fact] + // public void CheckForUnappliedMigrations() + // { + // var dbDesignContext = new DesignTimeJellyfinDbFactory(); + // var context = dbDesignContext.CreateDbContext([]); + // Assert.False(context.Database.HasPendingModelChanges(), "There are unapplied changes to the EfCore model. Please create a Migration."); + // } } -- cgit v1.2.3 From 114591c1aacbdf4d07e95c536ea2e42af1c5ab0d Mon Sep 17 00:00:00 2001 From: Marc Brooks Date: Tue, 25 Feb 2025 01:51:38 -0600 Subject: Clean up usings and honor SortName --- MediaBrowser.Controller/Entities/BaseItem.cs | 1 - .../Probing/ProbeResultNormalizer.cs | 1 - MediaBrowser.Providers/MediaInfo/AudioFileProber.cs | 1 - .../Plugins/Tmdb/Movies/TmdbMovieProvider.cs | 1 - MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs | 1 + MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs | 3 +-- MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs | 20 +++++++++++++++++++- MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs | 1 - 8 files changed, 21 insertions(+), 8 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 29b0b6861..95d0f311e 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -24,7 +24,6 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; -using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index c6a2ca5a4..6b0fd9a14 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -12,7 +12,6 @@ using Jellyfin.Data.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Extensions; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; diff --git a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs index 0e22dd96e..b504da48f 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs @@ -14,7 +14,6 @@ using MediaBrowser.Controller.Lyrics; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; -using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs index ce10d4a8a..9bb6507fe 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs @@ -12,7 +12,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; -using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; using TMDbLib.Objects.Find; diff --git a/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs index 774539c95..440296f09 100644 --- a/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs @@ -74,6 +74,7 @@ namespace MediaBrowser.XbmcMetadata.Savers foreach (var track in tracks .OrderBy(i => i.ParentIndexNumber ?? 0) .ThenBy(i => i.IndexNumber ?? 0) + .ThenBy(i => SortNameOrName(i)) .ThenBy(i => i.Name?.Trim())) { writer.WriteStartElement("track"); diff --git a/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs index e1d006bfa..b5ba2d24f 100644 --- a/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs @@ -7,7 +7,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.IO; using MediaBrowser.XbmcMetadata.Configuration; using Microsoft.Extensions.Logging; @@ -73,7 +72,7 @@ namespace MediaBrowser.XbmcMetadata.Savers { foreach (var album in albums .OrderBy(album => album.ProductionYear ?? 0) - .ThenBy(album => album.SortName?.Trim()) + .ThenBy(album => SortNameOrName(album)) .ThenBy(album => album.Name?.Trim())) { writer.WriteStartElement("album"); diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 9c006e206..f14bd437a 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -19,7 +19,6 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; @@ -1038,5 +1037,24 @@ namespace MediaBrowser.XbmcMetadata.Savers private string GetTagForProviderKey(string providerKey) => providerKey.ToLowerInvariant() + "id"; + + protected static string SortNameOrName(BaseItem item) + { + if (item == null) + { + return string.Empty; + } + + if (item.SortName != null) + { + string trimmed = item.SortName.Trim(); + if (trimmed.Length > 0) + { + return trimmed; + } + } + + return (item.Name ?? string.Empty).Trim(); + } } } diff --git a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs index d11975179..a32491c45 100644 --- a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs @@ -9,7 +9,6 @@ using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; -using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using Microsoft.Extensions.Logging; -- cgit v1.2.3 From 160020c551f71441fec093f5a6b2ca2650d9a74d Mon Sep 17 00:00:00 2001 From: JPVenson Date: Tue, 25 Mar 2025 15:30:22 +0000 Subject: WIP fixed namespaces --- Emby.Server.Implementations/ApplicationHost.cs | 2 +- .../Data/CleanDatabaseScheduledTask.cs | 2 +- .../HttpServer/Security/AuthService.cs | 2 +- .../Images/BaseFolderImageProvider.cs | 1 + .../Images/CollectionFolderImageProvider.cs | 1 + .../Images/GenreImageProvider.cs | 1 + .../Images/MusicGenreImageProvider.cs | 1 + .../Library/LibraryManager.cs | 1 + .../Library/MediaSourceManager.cs | 1 + .../Library/MediaStreamSelector.cs | 2 +- .../Library/MusicManager.cs | 1 + .../Library/SearchEngine.cs | 1 + .../Library/SplashscreenPostScanTask.cs | 1 + .../Library/UserDataManager.cs | 2 +- .../Library/UserViewManager.cs | 1 + .../Library/Validators/CollectionPostScanTask.cs | 1 + .../ScheduledTasks/Tasks/OptimizeDatabaseTask.cs | 2 +- .../Session/SessionManager.cs | 1 + Emby.Server.Implementations/TV/TVSeriesManager.cs | 1 + Jellyfin.Api/Auth/CustomAuthenticationHandler.cs | 2 +- .../DefaultAuthorizationHandler.cs | 2 +- .../SyncPlayAccessPolicy/SyncPlayAccessHandler.cs | 1 + .../UserPermissionRequirement.cs | 2 +- Jellyfin.Api/Controllers/ArtistsController.cs | 1 + Jellyfin.Api/Controllers/ChannelsController.cs | 1 + .../Controllers/DisplayPreferencesController.cs | 2 +- Jellyfin.Api/Controllers/GenresController.cs | 1 + Jellyfin.Api/Controllers/ItemsController.cs | 1 + Jellyfin.Api/Controllers/LibraryController.cs | 1 + Jellyfin.Api/Controllers/LiveTvController.cs | 1 + .../Controllers/MediaSegmentsController.cs | 2 +- Jellyfin.Api/Controllers/MoviesController.cs | 1 + Jellyfin.Api/Controllers/MusicGenresController.cs | 1 + Jellyfin.Api/Controllers/SuggestionsController.cs | 1 + Jellyfin.Api/Controllers/TrailersController.cs | 1 + Jellyfin.Api/Controllers/TvShowsController.cs | 1 + Jellyfin.Api/Controllers/UserController.cs | 2 +- Jellyfin.Api/Controllers/YearsController.cs | 1 + Jellyfin.Api/Helpers/MediaInfoHelper.cs | 1 + Jellyfin.Api/Helpers/RequestHelpers.cs | 1 + Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs | 1 + .../ActivityLogWebSocketListener.cs | 2 +- .../SessionInfoWebSocketListener.cs | 2 +- Jellyfin.Data/DayOfWeekHelper.cs | 2 +- Jellyfin.Data/UserEntityExtensions.cs | 4 +- .../Activity/ActivityManager.cs | 1 + .../DbConfiguration/DatabaseConfigurationStore.cs | 1 + .../Devices/DeviceManager.cs | 3 +- .../Extensions/ServiceCollectionExtensions.cs | 5 +- .../Item/BaseItemRepository.cs | 2 + .../Item/ChapterRepository.cs | 1 + .../Item/MediaAttachmentRepository.cs | 1 + .../Item/MediaStreamRepository.cs | 1 + .../Item/PeopleRepository.cs | 1 + .../MediaSegments/MediaSegmentManager.cs | 3 +- .../Security/AuthenticationManager.cs | 1 + .../Security/AuthorizationContext.cs | 1 + .../Trickplay/TrickplayManager.cs | 1 + .../Users/DeviceAccessHost.cs | 2 +- .../Users/DisplayPreferencesManager.cs | 1 + .../Users/UserManager.cs | 2 + Jellyfin.Server/CoreAppHost.cs | 2 +- .../Extensions/ApiServiceCollectionExtensions.cs | 1 + .../Migrations/Routines/MigrateActivityLogDb.cs | 2 +- .../Migrations/Routines/MigrateAuthenticationDb.cs | 2 +- .../Routines/MigrateDisplayPreferencesDb.cs | 4 +- .../Migrations/Routines/MigrateLibraryDb.cs | 2 +- .../Migrations/Routines/MigrateUserDb.cs | 4 +- Jellyfin.Server/Program.cs | 2 +- Jellyfin.Server/Startup.cs | 2 +- MediaBrowser.Controller/Channels/Channel.cs | 2 +- .../Entities/Audio/MusicAlbum.cs | 1 + .../Entities/Audio/MusicArtist.cs | 1 + MediaBrowser.Controller/Entities/BaseItem.cs | 1 + MediaBrowser.Controller/Entities/Folder.cs | 1 + .../Entities/InternalItemsQuery.cs | 1 + MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 1 + MediaBrowser.Controller/Entities/TV/Series.cs | 1 + .../Entities/UserViewBuilder.cs | 1 + MediaBrowser.Controller/Library/ILibraryManager.cs | 1 + .../MediaEncoding/EncodingHelper.cs | 1 + .../MediaSegments/IMediaSegmentManager.cs | 2 +- MediaBrowser.Controller/Playlists/Playlist.cs | 1 + .../Transcoding/TranscodeManager.cs | 2 +- .../Configuration/UserConfiguration.cs | 2 +- MediaBrowser.Model/Dto/DisplayPreferencesDto.cs | 2 +- MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs | 1 + MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs | 2 +- .../MediaSegments/MediaSegmentDto.cs | 2 +- MediaBrowser.Model/Users/UserPolicy.cs | 1 + .../DatabaseConfigurationOptions.cs | 4 +- .../Entities/AccessSchedule.cs | 2 +- .../Entities/ActivityLog.cs | 2 +- .../Entities/BaseItemEntity.cs | 2 - .../Entities/BaseItemImageInfo.cs | 1 - .../Entities/BaseItemProvider.cs | 3 - .../Entities/DisplayPreferences.cs | 2 +- .../Entities/Group.cs | 4 +- .../Entities/HomeSection.cs | 2 +- .../Entities/ItemDisplayPreferences.cs | 2 +- .../Entities/ItemValueMap.cs | 1 - .../Entities/Libraries/Artwork.cs | 4 +- .../Entities/Libraries/Book.cs | 2 +- .../Entities/Libraries/BookMetadata.cs | 2 +- .../Entities/Libraries/Chapter.cs | 2 +- .../Entities/Libraries/Collection.cs | 2 +- .../Entities/Libraries/CollectionItem.cs | 2 +- .../Entities/Libraries/Company.cs | 2 +- .../Entities/Libraries/CustomItem.cs | 2 +- .../Entities/Libraries/Episode.cs | 2 +- .../Entities/Libraries/Genre.cs | 2 +- .../Entities/Libraries/ItemMetadata.cs | 2 +- .../Entities/Libraries/Library.cs | 2 +- .../Entities/Libraries/LibraryItem.cs | 2 +- .../Entities/Libraries/MediaFile.cs | 4 +- .../Entities/Libraries/MediaFileStream.cs | 2 +- .../Entities/Libraries/MetadataProvider.cs | 2 +- .../Entities/Libraries/MetadataProviderId.cs | 2 +- .../Entities/Libraries/Movie.cs | 2 +- .../Entities/Libraries/MovieMetadata.cs | 2 +- .../Entities/Libraries/Person.cs | 2 +- .../Entities/Libraries/PersonRole.cs | 4 +- .../Entities/Libraries/Photo.cs | 2 +- .../Entities/Libraries/Rating.cs | 2 +- .../Entities/Libraries/RatingSource.cs | 2 +- .../Entities/Libraries/Release.cs | 2 +- .../Entities/Libraries/SeriesMetadata.cs | 2 +- .../Entities/Libraries/Track.cs | 2 +- .../Entities/MediaSegment.cs | 2 +- .../Entities/MediaStreamInfo.cs | 1 - .../Entities/Permission.cs | 4 +- .../Entities/Preference.cs | 4 +- .../Entities/User.cs | 6 +- .../Entities/UserData.cs | 1 - .../Enums/ArtKind.cs | 49 ++-- .../Enums/ChromecastVersion.cs | 25 +-- .../Enums/DynamicDayOfWeek.cs | 109 +++++---- .../Enums/HomeSectionType.cs | 109 +++++---- .../Enums/IndexingKind.cs | 33 ++- .../Enums/MediaFileKind.cs | 49 ++-- .../Enums/MediaSegmentType.cs | 2 +- .../Enums/PermissionKind.cs | 249 ++++++++++----------- .../Enums/PersonRoleType.cs | 105 +++++---- .../Enums/PreferenceKind.cs | 113 +++++----- .../Enums/ScrollDirection.cs | 25 +-- .../Enums/SortOrder.cs | 25 +-- .../Enums/SubtitlePlaybackMode.cs | 49 ++-- .../Enums/SyncPlayUserAccessType.cs | 33 ++- .../Enums/ViewType.cs | 219 +++++++++--------- .../IJellyfinDatabaseProvider.cs | 3 +- .../Interfaces/IHasArtwork.cs | 2 +- .../Interfaces/IHasCompanies.cs | 2 +- .../Interfaces/IHasConcurrencyToken.cs | 25 +-- .../Interfaces/IHasPermissions.cs | 18 +- .../Interfaces/IHasReleases.cs | 17 +- .../JellyfinDatabaseProviderKeyAttribute.cs | 4 +- .../JellyfinDbContext.cs | 6 +- .../ModelConfiguration/ActivityLogConfiguration.cs | 2 +- .../ModelConfiguration/AncestorIdConfiguration.cs | 3 +- .../ModelConfiguration/ApiKeyConfiguration.cs | 2 +- .../AttachmentStreamInfoConfiguration.cs | 2 +- .../ModelConfiguration/BaseItemConfiguration.cs | 2 +- .../BaseItemMetadataFieldConfiguration.cs | 2 +- .../BaseItemProviderConfiguration.cs | 3 +- .../BaseItemTrailerTypeConfiguration.cs | 2 +- .../ModelConfiguration/ChapterConfiguration.cs | 3 +- .../CustomItemDisplayPreferencesConfiguration.cs | 2 +- .../ModelConfiguration/DeviceConfiguration.cs | 2 +- .../DeviceOptionsConfiguration.cs | 2 +- .../DisplayPreferencesConfiguration.cs | 2 +- .../ModelConfiguration/ItemValuesConfiguration.cs | 3 +- .../ItemValuesMapConfiguration.cs | 3 +- .../MediaStreamInfoConfiguration.cs | 3 +- .../PeopleBaseItemMapConfiguration.cs | 3 +- .../ModelConfiguration/PeopleConfiguration.cs | 3 +- .../ModelConfiguration/PermissionConfiguration.cs | 2 +- .../ModelConfiguration/PreferenceConfiguration.cs | 2 +- .../TrickplayInfoConfiguration.cs | 2 +- .../ModelConfiguration/UserConfiguration.cs | 2 +- .../ModelConfiguration/UserDataConfiguration.cs | 3 +- .../20200514181226_AddActivityLog.Designer.cs | 2 +- .../Migrations/20200613202153_AddUsers.Designer.cs | 2 +- ...0200728005145_AddDisplayPreferences.Designer.cs | 2 +- ...05220533_FixDisplayPreferencesIndex.Designer.cs | 2 +- ...20201004171403_AddMaxActiveSessions.Designer.cs | 2 +- ...4223655_AddCustomDisplayPreferences.Designer.cs | 2 +- ...10320181425_AddIndexesAndCollations.Designer.cs | 2 +- ...10407110544_NullableCustomPrefValue.Designer.cs | 2 +- .../20210814002109_AddDevices.Designer.cs | 2 +- ...052_AddIndexActivityLogsDateCreated.Designer.cs | 2 +- .../20230526173516_RemoveEasyPassword.Designer.cs | 2 +- .../20230626233818_AddTrickplayInfos.Designer.cs | 2 +- .../20230923170422_UserCastReceiver.Designer.cs | 2 +- .../20240729140605_AddMediaSegments.Designer.cs | 2 +- ...30_MarkSegmentProviderIdNonNullable.Designer.cs | 2 +- .../20241020103111_LibraryDbMigration.Designer.cs | 2 +- .../20241111131257_AddedCustomDataKey.Designer.cs | 2 +- ...0241111135439_AddedCustomDataKeyKey.Designer.cs | 2 +- .../20241112152323_FixAncestorIdConfig.Designer.cs | 2 +- .../20241112232041_fixMediaStreams.Designer.cs | 2 +- .../20241112234144_FixMediaStreams2.Designer.cs | 2 +- ...241113133548_EnforceUniqueItemValue.Designer.cs | 2 +- .../20250202021306_FixedCollation.Designer.cs | 2 +- ...0204092455_MakeStartEndDateNullable.Designer.cs | 2 +- .../20250214031148_ChannelIdGuid.Designer.cs | 2 +- .../Migrations/JellyfinDbModelSnapshot.cs | 2 +- .../SqliteDesignTimeJellyfinDbFactory.cs | 1 + .../ModelBuilderExtensions.cs | 59 +++-- .../SqliteDatabaseProvider.cs | 2 +- src/Jellyfin.LiveTv/Channels/ChannelManager.cs | 1 + src/Jellyfin.LiveTv/DefaultLiveTvService.cs | 1 + src/Jellyfin.LiveTv/LiveTvManager.cs | 1 + .../Recordings/RecordingNotifier.cs | 2 +- .../Recordings/RecordingsManager.cs | 1 + .../Auth/CustomAuthenticationHandlerTests.cs | 2 +- .../FirstTimeSetupHandlerTests.cs | 2 +- .../IgnoreScheduleHandlerTests.cs | 2 +- .../Helpers/RequestHelpersTests.cs | 1 + tests/Jellyfin.Api.Tests/TestHelpers.cs | 2 +- 219 files changed, 858 insertions(+), 838 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 6e8a9fc20..4d959905d 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -35,11 +35,11 @@ using Emby.Server.Implementations.SyncPlay; using Emby.Server.Implementations.TV; using Emby.Server.Implementations.Updates; using Jellyfin.Api.Helpers; +using Jellyfin.Database.Implementations; using Jellyfin.Drawing; using Jellyfin.MediaEncoding.Hls.Playlist; using Jellyfin.Networking.Manager; using Jellyfin.Networking.Udp; -using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Item; using Jellyfin.Server.Implementations.MediaSegments; using MediaBrowser.Common; diff --git a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs index a83ded439..63481b1f8 100644 --- a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs +++ b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs @@ -4,7 +4,7 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index 82945a4f6..8a79cdebc 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Jellyfin.Data; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Http; diff --git a/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs b/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs index f9c10ba09..0d63b3af7 100644 --- a/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs index 34c722e41..273d356a3 100644 --- a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs +++ b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.IO; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Images/GenreImageProvider.cs b/Emby.Server.Implementations/Images/GenreImageProvider.cs index c9b41f819..706de60a9 100644 --- a/Emby.Server.Implementations/Images/GenreImageProvider.cs +++ b/Emby.Server.Implementations/Images/GenreImageProvider.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs b/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs index 31f053f06..c472623e6 100644 --- a/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs +++ b/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index b0003ed41..846663900 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -21,6 +21,7 @@ using Emby.Server.Implementations.Sorting; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 3e71b2fcd..863195836 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -16,6 +16,7 @@ using AsyncKeyedLock; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using Jellyfin.Extensions.Json; using MediaBrowser.Common.Configuration; diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs index 6791e3ca9..631179ffc 100644 --- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs +++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Model.Entities; diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs index 71c69ec50..ffbf8068f 100644 --- a/Emby.Server.Implementations/Library/MusicManager.cs +++ b/Emby.Server.Implementations/Library/MusicManager.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Linq; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs index 3ac1d0219..9253a9a69 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs b/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs index 76e564d53..0c9edd839 100644 --- a/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs +++ b/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index a41ef888b..2a2813151 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -7,8 +7,8 @@ using System.Globalization; using System.Linq; using System.Threading; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using Jellyfin.Extensions; -using Jellyfin.Server.Implementations; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index 2560466c1..22baafbb0 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -9,6 +9,7 @@ using System.Threading; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index 89f64ee4f..337b1afdd 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs index 05223d28a..4d3a04377 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Tasks; using Microsoft.EntityFrameworkCore; diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index dc37c4f2a..959373fec 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -13,6 +13,7 @@ using Jellyfin.Data.Entities.Security; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs index 270c1b441..74db077d8 100644 --- a/Emby.Server.Implementations/TV/TVSeriesManager.cs +++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs @@ -6,6 +6,7 @@ using System.Linq; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs index 0fd014990..f6f2f59c5 100644 --- a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs +++ b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs @@ -4,7 +4,7 @@ using System.Text.Encodings.Web; using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Data; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Authentication; diff --git a/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs b/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs index 07dedb017..6b80d537f 100644 --- a/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs +++ b/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Data; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; diff --git a/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs b/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs index 5fcf72fb4..7efb5b169 100644 --- a/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs +++ b/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Jellyfin.Api.Extensions; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.SyncPlay; diff --git a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs index a7c3cce97..152c400cd 100644 --- a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs +++ b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs @@ -1,5 +1,5 @@ using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Api.Auth.UserPermissionPolicy { diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs index 10556da65..2da483913 100644 --- a/Jellyfin.Api/Controllers/ArtistsController.cs +++ b/Jellyfin.Api/Controllers/ArtistsController.cs @@ -6,6 +6,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Controllers/ChannelsController.cs b/Jellyfin.Api/Controllers/ChannelsController.cs index 2f55e88ec..880b3a82d 100644 --- a/Jellyfin.Api/Controllers/ChannelsController.cs +++ b/Jellyfin.Api/Controllers/ChannelsController.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs index 6d94d96f3..2196616dd 100644 --- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs +++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs @@ -5,7 +5,7 @@ using System.Globalization; using System.Linq; using Jellyfin.Api.Helpers; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; using MediaBrowser.Model.Dto; diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs index f0d17decb..1fd57eba9 100644 --- a/Jellyfin.Api/Controllers/GenresController.cs +++ b/Jellyfin.Api/Controllers/GenresController.cs @@ -6,6 +6,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index e6fe7df79..803c2f1f7 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -6,6 +6,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index 7c6160fc4..ff4540f58 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -13,6 +13,7 @@ using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.LibraryDtos; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Api; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 1c0a6af79..5461d12fa 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -15,6 +15,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.LiveTvDtos; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Api; using MediaBrowser.Common.Configuration; diff --git a/Jellyfin.Api/Controllers/MediaSegmentsController.cs b/Jellyfin.Api/Controllers/MediaSegmentsController.cs index 2d1d4e2c8..e30e2b54e 100644 --- a/Jellyfin.Api/Controllers/MediaSegmentsController.cs +++ b/Jellyfin.Api/Controllers/MediaSegmentsController.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; using Jellyfin.Api.Extensions; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs index cbbaaddbf..09a7b73b9 100644 --- a/Jellyfin.Api/Controllers/MoviesController.cs +++ b/Jellyfin.Api/Controllers/MoviesController.cs @@ -7,6 +7,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index e8bc8f265..0cb20e433 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -6,6 +6,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index 9b56d0849..5075d91be 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -5,6 +5,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs index 7ee4396bb..3e4bac89a 100644 --- a/Jellyfin.Api/Controllers/TrailersController.cs +++ b/Jellyfin.Api/Controllers/TrailersController.cs @@ -1,6 +1,7 @@ using System; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index cc070244b..0f08854d2 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -7,6 +7,7 @@ using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 838578fab..d0ced277a 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -8,7 +8,7 @@ using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.UserDtos; using Jellyfin.Data; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Api; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index 2b32ae728..bbfa270db 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -8,6 +8,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs index 2c45789d3..1801b6bfd 100644 --- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs +++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs @@ -10,6 +10,7 @@ using Jellyfin.Api.Extensions; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs index eb83a37ba..3c2691cb5 100644 --- a/Jellyfin.Api/Helpers/RequestHelpers.cs +++ b/Jellyfin.Api/Helpers/RequestHelpers.cs @@ -7,6 +7,7 @@ using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs b/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs index dece66426..2616694d8 100644 --- a/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs +++ b/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Text.Json.Serialization; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions.Json.Converters; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; diff --git a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs index e2e7b0cb5..60379f415 100644 --- a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs @@ -1,8 +1,8 @@ using System; using System.Threading.Tasks; using Jellyfin.Data; -using Jellyfin.Data.Enums; using Jellyfin.Data.Events; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Activity; diff --git a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs index cc0792477..9d149cc85 100644 --- a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Jellyfin.Data; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; diff --git a/Jellyfin.Data/DayOfWeekHelper.cs b/Jellyfin.Data/DayOfWeekHelper.cs index 82abfb831..836860e0e 100644 --- a/Jellyfin.Data/DayOfWeekHelper.cs +++ b/Jellyfin.Data/DayOfWeekHelper.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 using System; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Data { diff --git a/Jellyfin.Data/UserEntityExtensions.cs b/Jellyfin.Data/UserEntityExtensions.cs index 8d84a6b6e..8bf82265c 100644 --- a/Jellyfin.Data/UserEntityExtensions.cs +++ b/Jellyfin.Data/UserEntityExtensions.cs @@ -2,8 +2,8 @@ using System; using System.ComponentModel; using System.Linq; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data; diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs index 54272aeaf..007a468bf 100644 --- a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs +++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Querying; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationStore.cs b/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationStore.cs index 180561fc8..537630561 100644 --- a/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationStore.cs +++ b/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationStore.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Jellyfin.Database.Implementations.DbConfiguration; using MediaBrowser.Common.Configuration; namespace Jellyfin.Server.Implementations.DatabaseConfiguration; diff --git a/Jellyfin.Server.Implementations/Devices/DeviceManager.cs b/Jellyfin.Server.Implementations/Devices/DeviceManager.cs index 1b4048b8e..e414a8232 100644 --- a/Jellyfin.Server.Implementations/Devices/DeviceManager.cs +++ b/Jellyfin.Server.Implementations/Devices/DeviceManager.cs @@ -7,9 +7,10 @@ using Jellyfin.Data; using Jellyfin.Data.Dtos; using Jellyfin.Data.Entities; using Jellyfin.Data.Entities.Security; -using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Devices; diff --git a/Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs b/Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs index b0e4567a7..fbbb5bca7 100644 --- a/Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs +++ b/Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs @@ -1,14 +1,15 @@ using System; using System.Collections.Generic; using System.Reflection; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.DbConfiguration; using Jellyfin.Database.Providers.Sqlite; -using Jellyfin.Server.Implementations.DatabaseConfiguration; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using JellyfinDbProviderFactory = System.Func; +using JellyfinDbProviderFactory = System.Func; namespace Jellyfin.Server.Implementations.Extensions; diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs index bea69b282..1f04b2829 100644 --- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs +++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs @@ -18,6 +18,8 @@ using System.Text.Json; using System.Threading; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using Jellyfin.Extensions.Json; using MediaBrowser.Common; diff --git a/Jellyfin.Server.Implementations/Item/ChapterRepository.cs b/Jellyfin.Server.Implementations/Item/ChapterRepository.cs index fc6f04d56..48b94a5f3 100644 --- a/Jellyfin.Server.Implementations/Item/ChapterRepository.cs +++ b/Jellyfin.Server.Implementations/Item/ChapterRepository.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller.Chapters; using MediaBrowser.Controller.Drawing; using MediaBrowser.Model.Dto; diff --git a/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs b/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs index 155798209..18167cc53 100644 --- a/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs +++ b/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Linq; using System.Threading; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs b/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs index f47e3fdfd..f70071884 100644 --- a/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs +++ b/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Linq; using System.Threading; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; diff --git a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs index a8dfd4cd3..01a0ade63 100644 --- a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs +++ b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Linq; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations; using Jellyfin.Extensions; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Persistence; diff --git a/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs b/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs index 59ec418ce..fa507ad04 100644 --- a/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs +++ b/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs @@ -6,7 +6,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; diff --git a/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs b/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs index 1c9f54ab0..534e80f4e 100644 --- a/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs +++ b/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Jellyfin.Data.Entities.Security; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller.Security; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs b/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs index 9e225393c..e3fe517c4 100644 --- a/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs +++ b/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Net; using System.Threading.Tasks; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations; using Jellyfin.Extensions; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; diff --git a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs index 6949ec1a8..b55d2271a 100644 --- a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs +++ b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; diff --git a/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs b/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs index 27222a183..02a52e5f2 100644 --- a/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs +++ b/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs @@ -2,9 +2,9 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Session; diff --git a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs index e204a16a6..3f9491038 100644 --- a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs +++ b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 79fa70c0b..0105f8162 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -12,6 +12,8 @@ using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using Jellyfin.Data.Events.Users; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index 9788119a5..f3bf6b805 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -4,10 +4,10 @@ using System.Reflection; using Emby.Server.Implementations; using Emby.Server.Implementations.Session; using Jellyfin.Api.WebSocketListeners; +using Jellyfin.Database.Implementations; using Jellyfin.Drawing; using Jellyfin.Drawing.Skia; using Jellyfin.LiveTv; -using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Activity; using Jellyfin.Server.Implementations.Devices; using Jellyfin.Server.Implementations.Events; diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index 597643ed1..c3b02ad4e 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -19,6 +19,7 @@ using Jellyfin.Api.Controllers; using Jellyfin.Api.Formatters; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions.Json; using Jellyfin.Server.Configuration; using Jellyfin.Server.Filters; diff --git a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs index 2f23cb1f8..933d85de0 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs index c845beef2..a50990ac5 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities.Security; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; using Microsoft.Data.Sqlite; diff --git a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs index 502a37cde..4f6c5100d 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs @@ -6,8 +6,8 @@ using System.Text.Json; using System.Text.Json.Serialization; using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; diff --git a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs index f183bce10..490daae42 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs @@ -12,8 +12,8 @@ using System.Text; using System.Threading; using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using Jellyfin.Extensions; -using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Item; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index f126230fb..bd5bf98e0 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -3,9 +3,9 @@ using System.IO; using Emby.Server.Implementations.Data; using Jellyfin.Data; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions.Json; -using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Users; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index d8684f6da..32814393c 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -8,9 +8,9 @@ using System.Threading; using System.Threading.Tasks; using CommandLine; using Emby.Server.Implementations; +using Jellyfin.Database.Implementations; using Jellyfin.Server.Extensions; using Jellyfin.Server.Helpers; -using Jellyfin.Server.Implementations; using Jellyfin.Server.ServerSetupApp; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs index fa21d2566..688b16935 100644 --- a/Jellyfin.Server/Startup.cs +++ b/Jellyfin.Server/Startup.cs @@ -6,6 +6,7 @@ using System.Net.Mime; using System.Text; using Emby.Server.Implementations.EntryPoints; using Jellyfin.Api.Middleware; +using Jellyfin.Database.Implementations; using Jellyfin.LiveTv.Extensions; using Jellyfin.LiveTv.Recordings; using Jellyfin.MediaEncoding.Hls.Extensions; @@ -13,7 +14,6 @@ using Jellyfin.Networking; using Jellyfin.Networking.HappyEyeballs; using Jellyfin.Server.Extensions; using Jellyfin.Server.HealthChecks; -using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Extensions; using Jellyfin.Server.Infrastructure; using MediaBrowser.Common.Net; diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index 49f8df508..f6cbf5a00 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -9,7 +9,7 @@ using System.Text.Json.Serialization; using System.Threading; using Jellyfin.Data; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Querying; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 3b0938ea7..d6e659242 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index e99479ee1..39dc90963 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index e20679084..29481481c 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -15,6 +15,7 @@ using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Channels; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index b2f23cc11..d3e9da622 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -16,6 +16,7 @@ using J2N.Collections.Generic.Extensions; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Collections; diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 0bd28154d..57a8a0113 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -6,6 +6,7 @@ using System.Linq; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 07def2e0f..a252b7a25 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -10,6 +10,7 @@ using System.Text.Json.Serialization; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Querying; diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index f3c252dec..470702f3e 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 367080867..18845ab9f 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -9,6 +9,7 @@ using System.Linq; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.TV; diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index e4490bca3..13915dc5c 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 1c5d2f4e5..cf76f336c 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -15,6 +15,7 @@ using System.Text.RegularExpressions; using System.Threading; using Jellyfin.Data; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Extensions; diff --git a/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs b/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs index 570d2bace..1e75446e1 100644 --- a/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs +++ b/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.MediaSegments; diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 491acdc9c..53e04066f 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; diff --git a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs index d35ed57b8..85bb862c7 100644 --- a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs +++ b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs @@ -11,7 +11,7 @@ using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; using Jellyfin.Data; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index b477f2593..fe4b2de65 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 using System; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace MediaBrowser.Model.Configuration { diff --git a/MediaBrowser.Model/Dto/DisplayPreferencesDto.cs b/MediaBrowser.Model/Dto/DisplayPreferencesDto.cs index 90163ae91..54cbe65f6 100644 --- a/MediaBrowser.Model/Dto/DisplayPreferencesDto.cs +++ b/MediaBrowser.Model/Dto/DisplayPreferencesDto.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace MediaBrowser.Model.Dto { diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs index d872572b7..38e273176 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs @@ -3,6 +3,7 @@ using System; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace MediaBrowser.Model.LiveTv { diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs b/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs index dae885775..e93ad81d3 100644 --- a/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs +++ b/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs @@ -1,6 +1,6 @@ #pragma warning disable CS1591 -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace MediaBrowser.Model.LiveTv { diff --git a/MediaBrowser.Model/MediaSegments/MediaSegmentDto.cs b/MediaBrowser.Model/MediaSegments/MediaSegmentDto.cs index a0433fee1..6e5c7885c 100644 --- a/MediaBrowser.Model/MediaSegments/MediaSegmentDto.cs +++ b/MediaBrowser.Model/MediaSegments/MediaSegmentDto.cs @@ -1,5 +1,5 @@ using System; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace MediaBrowser.Model.MediaSegments; diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index 951e05763..ba0eaf21c 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -6,6 +6,7 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Xml.Serialization; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using AccessSchedule = Jellyfin.Data.Entities.AccessSchedule; namespace MediaBrowser.Model.Users diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs index af2ede701..b481a106f 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs @@ -1,6 +1,4 @@ -using System; - -namespace Jellyfin.Server.Implementations.DatabaseConfiguration; +namespace Jellyfin.Database.Implementations.DbConfiguration; /// /// Options to configure jellyfins managed database. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs index f534e49f3..909e8750f 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations.Schema; using System.Xml.Serialization; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs index 51dd0ffb8..3a7678405 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; using Microsoft.Extensions.Logging; namespace Jellyfin.Data.Entities diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs index e3e0e0861..42be5b3b9 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs @@ -3,8 +3,6 @@ using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs index 37723df11..ac6b72ace 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs @@ -1,7 +1,6 @@ #pragma warning disable CA2227 using System; -using System.Collections.Generic; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs index 9a1565728..c0c5e3147 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs index f0be65769..82bf007a8 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs index 09f237289..4b343c164 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Linq; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs index 8dd6e647e..edffec4ab 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs @@ -1,5 +1,5 @@ using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs index 93e6664ea..7e75a200b 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs index 94db6a011..e80a9aec3 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs index fc3c1036f..b529da8fa 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs @@ -1,8 +1,8 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs index a838686d0..54c30d92c 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs index 4a350d200..7b1a68bb5 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs index f068338f9..cbcb9a5f5 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs index 7de601969..8da9793f9 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs index 15b356a74..4bd99d83a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs index 1abbee445..5dc1039a1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs index e27d01d86..92307afec 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs index ce2f0c617..637975526 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs index 3b822ee82..329b8973f 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs index fa9276c66..401d58ff2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs index 0db42a1c7..17673cb1d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs index d889b871e..975614be1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs index 7b5a3af64..0913f95be 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs @@ -2,8 +2,8 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs index e24e73ecb..3170653fe 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs index b38d6a4f1..afaebb8e8 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs index a198f53ba..fa36e58db 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs index 499fafd0e..beae325ec 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs index 44b5f34d7..df48ebf27 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs index 90dc55b70..d9609f1cc 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs index 7d40bdf44..627f74140 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs index 4b459432b..094d57139 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs index 58c8fa49e..6b792ffb4 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs index 0f3a07324..91ee8caa1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs index e68ab9105..40466def1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs index 42115802c..28da91e47 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs index d35400033..6d6a92022 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs index 90120d772..8c1c071e6 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs @@ -1,6 +1,6 @@ using System; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs index 77816565a..b16b62b10 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs @@ -1,7 +1,6 @@ #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using System; -using System.Diagnostics.CodeAnalysis; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs index 6d2e68077..c488b90e1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs @@ -3,8 +3,8 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs index a6ab275d3..f4f9dd17a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs @@ -1,8 +1,8 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs index f3398eeea..aafa92b4a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs @@ -1,12 +1,10 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; using System.Text.Json.Serialization; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs index 05ab6dd2d..ced12b9e6 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs @@ -1,5 +1,4 @@ using System; -using System.ComponentModel.DataAnnotations.Schema; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ArtKind.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ArtKind.cs index f7a73848c..218e97bcc 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ArtKind.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ArtKind.cs @@ -1,33 +1,32 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing types of art. +/// +public enum ArtKind { /// - /// An enum representing types of art. + /// Another type of art, not covered by the other members. /// - public enum ArtKind - { - /// - /// Another type of art, not covered by the other members. - /// - Other = 0, + Other = 0, - /// - /// A poster. - /// - Poster = 1, + /// + /// A poster. + /// + Poster = 1, - /// - /// A banner. - /// - Banner = 2, + /// + /// A banner. + /// + Banner = 2, - /// - /// A thumbnail. - /// - Thumbnail = 3, + /// + /// A thumbnail. + /// + Thumbnail = 3, - /// - /// A logo. - /// - Logo = 4 - } + /// + /// A logo. + /// + Logo = 4 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ChromecastVersion.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ChromecastVersion.cs index c9c8a4a62..123f2fe43 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ChromecastVersion.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ChromecastVersion.cs @@ -1,18 +1,17 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing the version of Chromecast to be used by clients. +/// +public enum ChromecastVersion { /// - /// An enum representing the version of Chromecast to be used by clients. + /// Stable Chromecast version. /// - public enum ChromecastVersion - { - /// - /// Stable Chromecast version. - /// - Stable = 0, + Stable = 0, - /// - /// Unstable Chromecast version. - /// - Unstable = 1 - } + /// + /// Unstable Chromecast version. + /// + Unstable = 1 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/DynamicDayOfWeek.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/DynamicDayOfWeek.cs index d3d8dd822..69a9b5816 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/DynamicDayOfWeek.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/DynamicDayOfWeek.cs @@ -1,58 +1,57 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum that represents a day of the week, weekdays, weekends, or all days. +/// +public enum DynamicDayOfWeek { /// - /// An enum that represents a day of the week, weekdays, weekends, or all days. - /// - public enum DynamicDayOfWeek - { - /// - /// Sunday. - /// - Sunday = 0, - - /// - /// Monday. - /// - Monday = 1, - - /// - /// Tuesday. - /// - Tuesday = 2, - - /// - /// Wednesday. - /// - Wednesday = 3, - - /// - /// Thursday. - /// - Thursday = 4, - - /// - /// Friday. - /// - Friday = 5, - - /// - /// Saturday. - /// - Saturday = 6, - - /// - /// All days of the week. - /// - Everyday = 7, - - /// - /// A week day, or Monday-Friday. - /// - Weekday = 8, - - /// - /// Saturday and Sunday. - /// - Weekend = 9 - } + /// Sunday. + /// + Sunday = 0, + + /// + /// Monday. + /// + Monday = 1, + + /// + /// Tuesday. + /// + Tuesday = 2, + + /// + /// Wednesday. + /// + Wednesday = 3, + + /// + /// Thursday. + /// + Thursday = 4, + + /// + /// Friday. + /// + Friday = 5, + + /// + /// Saturday. + /// + Saturday = 6, + + /// + /// All days of the week. + /// + Everyday = 7, + + /// + /// A week day, or Monday-Friday. + /// + Weekday = 8, + + /// + /// Saturday and Sunday. + /// + Weekend = 9 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/HomeSectionType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/HomeSectionType.cs index 62da8c3ff..6ba57e74d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/HomeSectionType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/HomeSectionType.cs @@ -1,58 +1,57 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing the different options for the home screen sections. +/// +public enum HomeSectionType { /// - /// An enum representing the different options for the home screen sections. - /// - public enum HomeSectionType - { - /// - /// None. - /// - None = 0, - - /// - /// My Media. - /// - SmallLibraryTiles = 1, - - /// - /// My Media Small. - /// - LibraryButtons = 2, - - /// - /// Active Recordings. - /// - ActiveRecordings = 3, - - /// - /// Continue Watching. - /// - Resume = 4, - - /// - /// Continue Listening. - /// - ResumeAudio = 5, - - /// - /// Latest Media. - /// - LatestMedia = 6, - - /// - /// Next Up. - /// - NextUp = 7, - - /// - /// Live TV. - /// - LiveTv = 8, - - /// - /// Continue Reading. - /// - ResumeBook = 9 - } + /// None. + /// + None = 0, + + /// + /// My Media. + /// + SmallLibraryTiles = 1, + + /// + /// My Media Small. + /// + LibraryButtons = 2, + + /// + /// Active Recordings. + /// + ActiveRecordings = 3, + + /// + /// Continue Watching. + /// + Resume = 4, + + /// + /// Continue Listening. + /// + ResumeAudio = 5, + + /// + /// Latest Media. + /// + LatestMedia = 6, + + /// + /// Next Up. + /// + NextUp = 7, + + /// + /// Live TV. + /// + LiveTv = 8, + + /// + /// Continue Reading. + /// + ResumeBook = 9 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/IndexingKind.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/IndexingKind.cs index 3967712b0..72ac1140c 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/IndexingKind.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/IndexingKind.cs @@ -1,23 +1,22 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing a type of indexing in a user's display preferences. +/// +public enum IndexingKind { /// - /// An enum representing a type of indexing in a user's display preferences. + /// Index by the premiere date. /// - public enum IndexingKind - { - /// - /// Index by the premiere date. - /// - PremiereDate = 0, + PremiereDate = 0, - /// - /// Index by the production year. - /// - ProductionYear = 1, + /// + /// Index by the production year. + /// + ProductionYear = 1, - /// - /// Index by the community rating. - /// - CommunityRating = 2 - } + /// + /// Index by the community rating. + /// + CommunityRating = 2 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaFileKind.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaFileKind.cs index 797c26ec2..8e6f677dc 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaFileKind.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaFileKind.cs @@ -1,33 +1,32 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing the type of media file. +/// +public enum MediaFileKind { /// - /// An enum representing the type of media file. + /// The main file. /// - public enum MediaFileKind - { - /// - /// The main file. - /// - Main = 0, + Main = 0, - /// - /// A sidecar file. - /// - Sidecar = 1, + /// + /// A sidecar file. + /// + Sidecar = 1, - /// - /// An additional part to the main file. - /// - AdditionalPart = 2, + /// + /// An additional part to the main file. + /// + AdditionalPart = 2, - /// - /// An alternative format to the main file. - /// - AlternativeFormat = 3, + /// + /// An alternative format to the main file. + /// + AlternativeFormat = 3, - /// - /// An additional stream for the main file. - /// - AdditionalStream = 4 - } + /// + /// An additional stream for the main file. + /// + AdditionalStream = 4 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs index 458635450..fed092b97 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs @@ -1,6 +1,6 @@ using Jellyfin.Data.Entities; -namespace Jellyfin.Data.Enums; +namespace Jellyfin.Database.Implementations.Enums; /// /// Defines the types of content an individual represents. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PermissionKind.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PermissionKind.cs index c3d6705c2..081863963 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PermissionKind.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PermissionKind.cs @@ -1,128 +1,127 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// The types of user permissions. +/// +public enum PermissionKind { /// - /// The types of user permissions. - /// - public enum PermissionKind - { - /// - /// Whether the user is an administrator. - /// - IsAdministrator = 0, - - /// - /// Whether the user is hidden. - /// - IsHidden = 1, - - /// - /// Whether the user is disabled. - /// - IsDisabled = 2, - - /// - /// Whether the user can control shared devices. - /// - EnableSharedDeviceControl = 3, - - /// - /// Whether the user can access the server remotely. - /// - EnableRemoteAccess = 4, - - /// - /// Whether the user can manage live tv. - /// - EnableLiveTvManagement = 5, - - /// - /// Whether the user can access live tv. - /// - EnableLiveTvAccess = 6, - - /// - /// Whether the user can play media. - /// - EnableMediaPlayback = 7, - - /// - /// Whether the server should transcode audio for the user if requested. - /// - EnableAudioPlaybackTranscoding = 8, - - /// - /// Whether the server should transcode video for the user if requested. - /// - EnableVideoPlaybackTranscoding = 9, - - /// - /// Whether the user can delete content. - /// - EnableContentDeletion = 10, - - /// - /// Whether the user can download content. - /// - EnableContentDownloading = 11, - - /// - /// Whether to enable sync transcoding for the user. - /// - EnableSyncTranscoding = 12, - - /// - /// Whether the user can do media conversion. - /// - EnableMediaConversion = 13, - - /// - /// Whether the user has access to all devices. - /// - EnableAllDevices = 14, - - /// - /// Whether the user has access to all channels. - /// - EnableAllChannels = 15, - - /// - /// Whether the user has access to all folders. - /// - EnableAllFolders = 16, - - /// - /// Whether to enable public sharing for the user. - /// - EnablePublicSharing = 17, - - /// - /// Whether the user can remotely control other users. - /// - EnableRemoteControlOfOtherUsers = 18, - - /// - /// Whether the user is permitted to do playback remuxing. - /// - EnablePlaybackRemuxing = 19, - - /// - /// Whether the server should force transcoding on remote connections for the user. - /// - ForceRemoteSourceTranscoding = 20, - - /// - /// Whether the user can create, modify and delete collections. - /// - EnableCollectionManagement = 21, - - /// - /// Whether the user can edit subtitles. - /// - EnableSubtitleManagement = 22, - - /// - /// Whether the user can edit lyrics. - /// - EnableLyricManagement = 23, - } + /// Whether the user is an administrator. + /// + IsAdministrator = 0, + + /// + /// Whether the user is hidden. + /// + IsHidden = 1, + + /// + /// Whether the user is disabled. + /// + IsDisabled = 2, + + /// + /// Whether the user can control shared devices. + /// + EnableSharedDeviceControl = 3, + + /// + /// Whether the user can access the server remotely. + /// + EnableRemoteAccess = 4, + + /// + /// Whether the user can manage live tv. + /// + EnableLiveTvManagement = 5, + + /// + /// Whether the user can access live tv. + /// + EnableLiveTvAccess = 6, + + /// + /// Whether the user can play media. + /// + EnableMediaPlayback = 7, + + /// + /// Whether the server should transcode audio for the user if requested. + /// + EnableAudioPlaybackTranscoding = 8, + + /// + /// Whether the server should transcode video for the user if requested. + /// + EnableVideoPlaybackTranscoding = 9, + + /// + /// Whether the user can delete content. + /// + EnableContentDeletion = 10, + + /// + /// Whether the user can download content. + /// + EnableContentDownloading = 11, + + /// + /// Whether to enable sync transcoding for the user. + /// + EnableSyncTranscoding = 12, + + /// + /// Whether the user can do media conversion. + /// + EnableMediaConversion = 13, + + /// + /// Whether the user has access to all devices. + /// + EnableAllDevices = 14, + + /// + /// Whether the user has access to all channels. + /// + EnableAllChannels = 15, + + /// + /// Whether the user has access to all folders. + /// + EnableAllFolders = 16, + + /// + /// Whether to enable public sharing for the user. + /// + EnablePublicSharing = 17, + + /// + /// Whether the user can remotely control other users. + /// + EnableRemoteControlOfOtherUsers = 18, + + /// + /// Whether the user is permitted to do playback remuxing. + /// + EnablePlaybackRemuxing = 19, + + /// + /// Whether the server should force transcoding on remote connections for the user. + /// + ForceRemoteSourceTranscoding = 20, + + /// + /// Whether the user can create, modify and delete collections. + /// + EnableCollectionManagement = 21, + + /// + /// Whether the user can edit subtitles. + /// + EnableSubtitleManagement = 22, + + /// + /// Whether the user can edit lyrics. + /// + EnableLyricManagement = 23, } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PersonRoleType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PersonRoleType.cs index 1e619f5ee..5b913385e 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PersonRoleType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PersonRoleType.cs @@ -1,68 +1,67 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing a person's role in a specific media item. +/// +public enum PersonRoleType { /// - /// An enum representing a person's role in a specific media item. + /// Another role, not covered by the other types. /// - public enum PersonRoleType - { - /// - /// Another role, not covered by the other types. - /// - Other = 0, + Other = 0, - /// - /// The director of the media. - /// - Director = 1, + /// + /// The director of the media. + /// + Director = 1, - /// - /// An artist. - /// - Artist = 2, + /// + /// An artist. + /// + Artist = 2, - /// - /// The original artist. - /// - OriginalArtist = 3, + /// + /// The original artist. + /// + OriginalArtist = 3, - /// - /// An actor. - /// - Actor = 4, + /// + /// An actor. + /// + Actor = 4, - /// - /// A voice actor. - /// - VoiceActor = 5, + /// + /// A voice actor. + /// + VoiceActor = 5, - /// - /// A producer. - /// - Producer = 6, + /// + /// A producer. + /// + Producer = 6, - /// - /// A remixer. - /// - Remixer = 7, + /// + /// A remixer. + /// + Remixer = 7, - /// - /// A conductor. - /// - Conductor = 8, + /// + /// A conductor. + /// + Conductor = 8, - /// - /// A composer. - /// - Composer = 9, + /// + /// A composer. + /// + Composer = 9, - /// - /// An author. - /// - Author = 10, + /// + /// An author. + /// + Author = 10, - /// - /// An editor. - /// - Editor = 11 - } + /// + /// An editor. + /// + Editor = 11 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PreferenceKind.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PreferenceKind.cs index d2b412e45..f70e3e2c2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PreferenceKind.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PreferenceKind.cs @@ -1,73 +1,72 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// The types of user preferences. +/// +public enum PreferenceKind { /// - /// The types of user preferences. + /// A list of blocked tags. /// - public enum PreferenceKind - { - /// - /// A list of blocked tags. - /// - BlockedTags = 0, + BlockedTags = 0, - /// - /// A list of blocked channels. - /// - BlockedChannels = 1, + /// + /// A list of blocked channels. + /// + BlockedChannels = 1, - /// - /// A list of blocked media folders. - /// - BlockedMediaFolders = 2, + /// + /// A list of blocked media folders. + /// + BlockedMediaFolders = 2, - /// - /// A list of enabled devices. - /// - EnabledDevices = 3, + /// + /// A list of enabled devices. + /// + EnabledDevices = 3, - /// - /// A list of enabled channels. - /// - EnabledChannels = 4, + /// + /// A list of enabled channels. + /// + EnabledChannels = 4, - /// - /// A list of enabled folders. - /// - EnabledFolders = 5, + /// + /// A list of enabled folders. + /// + EnabledFolders = 5, - /// - /// A list of folders to allow content deletion from. - /// - EnableContentDeletionFromFolders = 6, + /// + /// A list of folders to allow content deletion from. + /// + EnableContentDeletionFromFolders = 6, - /// - /// A list of latest items to exclude. - /// - LatestItemExcludes = 7, + /// + /// A list of latest items to exclude. + /// + LatestItemExcludes = 7, - /// - /// A list of media to exclude. - /// - MyMediaExcludes = 8, + /// + /// A list of media to exclude. + /// + MyMediaExcludes = 8, - /// - /// A list of grouped folders. - /// - GroupedFolders = 9, + /// + /// A list of grouped folders. + /// + GroupedFolders = 9, - /// - /// A list of unrated items to block. - /// - BlockUnratedItems = 10, + /// + /// A list of unrated items to block. + /// + BlockUnratedItems = 10, - /// - /// A list of ordered views. - /// - OrderedViews = 11, + /// + /// A list of ordered views. + /// + OrderedViews = 11, - /// - /// A list of allowed tags. - /// - AllowedTags = 12 - } + /// + /// A list of allowed tags. + /// + AllowedTags = 12 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ScrollDirection.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ScrollDirection.cs index 29c50e2c4..3ff3c45fa 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ScrollDirection.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ScrollDirection.cs @@ -1,18 +1,17 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing the axis that should be scrolled. +/// +public enum ScrollDirection { /// - /// An enum representing the axis that should be scrolled. + /// Horizontal scrolling direction. /// - public enum ScrollDirection - { - /// - /// Horizontal scrolling direction. - /// - Horizontal = 0, + Horizontal = 0, - /// - /// Vertical scrolling direction. - /// - Vertical = 1 - } + /// + /// Vertical scrolling direction. + /// + Vertical = 1 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SortOrder.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SortOrder.cs index 4151448e4..c865b75f1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SortOrder.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SortOrder.cs @@ -1,18 +1,17 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing the sorting order. +/// +public enum SortOrder { /// - /// An enum representing the sorting order. + /// Sort in increasing order. /// - public enum SortOrder - { - /// - /// Sort in increasing order. - /// - Ascending = 0, + Ascending = 0, - /// - /// Sort in decreasing order. - /// - Descending = 1 - } + /// + /// Sort in decreasing order. + /// + Descending = 1 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SubtitlePlaybackMode.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SubtitlePlaybackMode.cs index 79693d321..c394c209b 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SubtitlePlaybackMode.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SubtitlePlaybackMode.cs @@ -1,33 +1,32 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing a subtitle playback mode. +/// +public enum SubtitlePlaybackMode { /// - /// An enum representing a subtitle playback mode. + /// The default subtitle playback mode. /// - public enum SubtitlePlaybackMode - { - /// - /// The default subtitle playback mode. - /// - Default = 0, + Default = 0, - /// - /// Always show subtitles. - /// - Always = 1, + /// + /// Always show subtitles. + /// + Always = 1, - /// - /// Only show forced subtitles. - /// - OnlyForced = 2, + /// + /// Only show forced subtitles. + /// + OnlyForced = 2, - /// - /// Don't show subtitles. - /// - None = 3, + /// + /// Don't show subtitles. + /// + None = 3, - /// - /// Only show subtitles when the current audio stream is in a different language. - /// - Smart = 4 - } + /// + /// Only show subtitles when the current audio stream is in a different language. + /// + Smart = 4 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SyncPlayUserAccessType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SyncPlayUserAccessType.cs index 030d16fb9..311642e0d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SyncPlayUserAccessType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SyncPlayUserAccessType.cs @@ -1,23 +1,22 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// Enum SyncPlayUserAccessType. +/// +public enum SyncPlayUserAccessType { /// - /// Enum SyncPlayUserAccessType. + /// User can create groups and join them. /// - public enum SyncPlayUserAccessType - { - /// - /// User can create groups and join them. - /// - CreateAndJoinGroups = 0, + CreateAndJoinGroups = 0, - /// - /// User can only join already existing groups. - /// - JoinGroups = 1, + /// + /// User can only join already existing groups. + /// + JoinGroups = 1, - /// - /// SyncPlay is disabled for the user. - /// - None = 2 - } + /// + /// SyncPlay is disabled for the user. + /// + None = 2 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ViewType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ViewType.cs index c0fd7d448..b2bcbf2bb 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ViewType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ViewType.cs @@ -1,113 +1,112 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing the type of view for a library or collection. +/// +public enum ViewType { /// - /// An enum representing the type of view for a library or collection. - /// - public enum ViewType - { - /// - /// Shows albums. - /// - Albums = 0, - - /// - /// Shows album artists. - /// - AlbumArtists = 1, - - /// - /// Shows artists. - /// - Artists = 2, - - /// - /// Shows channels. - /// - Channels = 3, - - /// - /// Shows collections. - /// - Collections = 4, - - /// - /// Shows episodes. - /// - Episodes = 5, - - /// - /// Shows favorites. - /// - Favorites = 6, - - /// - /// Shows genres. - /// - Genres = 7, - - /// - /// Shows guide. - /// - Guide = 8, - - /// - /// Shows movies. - /// - Movies = 9, - - /// - /// Shows networks. - /// - Networks = 10, - - /// - /// Shows playlists. - /// - Playlists = 11, - - /// - /// Shows programs. - /// - Programs = 12, - - /// - /// Shows recordings. - /// - Recordings = 13, - - /// - /// Shows schedule. - /// - Schedule = 14, - - /// - /// Shows series. - /// - Series = 15, - - /// - /// Shows shows. - /// - Shows = 16, - - /// - /// Shows songs. - /// - Songs = 17, - - /// - /// Shows songs. - /// - Suggestions = 18, - - /// - /// Shows trailers. - /// - Trailers = 19, - - /// - /// Shows upcoming. - /// - Upcoming = 20 - } + /// Shows albums. + /// + Albums = 0, + + /// + /// Shows album artists. + /// + AlbumArtists = 1, + + /// + /// Shows artists. + /// + Artists = 2, + + /// + /// Shows channels. + /// + Channels = 3, + + /// + /// Shows collections. + /// + Collections = 4, + + /// + /// Shows episodes. + /// + Episodes = 5, + + /// + /// Shows favorites. + /// + Favorites = 6, + + /// + /// Shows genres. + /// + Genres = 7, + + /// + /// Shows guide. + /// + Guide = 8, + + /// + /// Shows movies. + /// + Movies = 9, + + /// + /// Shows networks. + /// + Networks = 10, + + /// + /// Shows playlists. + /// + Playlists = 11, + + /// + /// Shows programs. + /// + Programs = 12, + + /// + /// Shows recordings. + /// + Recordings = 13, + + /// + /// Shows schedule. + /// + Schedule = 14, + + /// + /// Shows series. + /// + Series = 15, + + /// + /// Shows shows. + /// + Shows = 16, + + /// + /// Shows songs. + /// + Songs = 17, + + /// + /// Shows songs. + /// + Suggestions = 18, + + /// + /// Shows trailers. + /// + Trailers = 19, + + /// + /// Shows upcoming. + /// + Upcoming = 20 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs index cc96792e6..074016553 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs @@ -1,9 +1,8 @@ -using System; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; -namespace Jellyfin.Server.Implementations; +namespace Jellyfin.Database.Implementations; /// /// Defines the type and extension points for multi database support. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs index a4d9c54af..03c2ca4a4 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Jellyfin.Data.Entities.Libraries; -namespace Jellyfin.Data.Interfaces +namespace Jellyfin.Database.Implementations.Interfaces { /// /// An interface abstracting an entity that has artwork. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs index 8f19ce04f..ed449a8f1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Jellyfin.Data.Entities.Libraries; -namespace Jellyfin.Data.Interfaces +namespace Jellyfin.Database.Implementations.Interfaces { /// /// An abstraction representing an entity that has companies. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasConcurrencyToken.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasConcurrencyToken.cs index 2c4091493..196d2680d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasConcurrencyToken.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasConcurrencyToken.cs @@ -1,18 +1,17 @@ -namespace Jellyfin.Data.Interfaces +namespace Jellyfin.Database.Implementations.Interfaces; + +/// +/// An interface abstracting an entity that has a concurrency token. +/// +public interface IHasConcurrencyToken { /// - /// An interface abstracting an entity that has a concurrency token. + /// Gets the version of this row. Acts as a concurrency token. /// - public interface IHasConcurrencyToken - { - /// - /// Gets the version of this row. Acts as a concurrency token. - /// - uint RowVersion { get; } + uint RowVersion { get; } - /// - /// Called when saving changes to this entity. - /// - void OnSavingChanges(); - } + /// + /// Called when saving changes to this entity. + /// + void OnSavingChanges(); } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs index 6d1eb59f6..606b1169b 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs @@ -1,17 +1,15 @@ using System.Collections.Generic; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; -namespace Jellyfin.Data.Interfaces +namespace Jellyfin.Database.Implementations.Interfaces; + +/// +/// An abstraction representing an entity that has permissions. +/// +public interface IHasPermissions { /// - /// An abstraction representing an entity that has permissions. + /// Gets a collection containing this entity's permissions. /// - public interface IHasPermissions - { - /// - /// Gets a collection containing this entity's permissions. - /// - ICollection Permissions { get; } - } + ICollection Permissions { get; } } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs index 3b615893e..653572b6e 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs @@ -1,16 +1,15 @@ using System.Collections.Generic; using Jellyfin.Data.Entities.Libraries; -namespace Jellyfin.Data.Interfaces +namespace Jellyfin.Database.Implementations.Interfaces; + +/// +/// An abstraction representing an entity that has releases. +/// +public interface IHasReleases { /// - /// An abstraction representing an entity that has releases. + /// Gets a collection containing this entity's releases. /// - public interface IHasReleases - { - /// - /// Gets a collection containing this entity's releases. - /// - ICollection Releases { get; } - } + ICollection Releases { get; } } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDatabaseProviderKeyAttribute.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDatabaseProviderKeyAttribute.cs index b3ab3d094..778aca373 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDatabaseProviderKeyAttribute.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDatabaseProviderKeyAttribute.cs @@ -1,4 +1,4 @@ -namespace Jellyfin.Server.Implementations; +namespace Jellyfin.Database.Implementations; /// /// Defines the key of the database provider. @@ -16,7 +16,7 @@ public sealed class JellyfinDatabaseProviderKeyAttribute : System.Attribute /// The key on which to identify the annotated provider. public JellyfinDatabaseProviderKeyAttribute(string databaseProviderKey) { - this._databaseProviderKey = databaseProviderKey; + _databaseProviderKey = databaseProviderKey; } /// diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs index 024d595d5..5cdc85331 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs @@ -2,13 +2,11 @@ using System; using System.Linq; using Jellyfin.Data.Entities; using Jellyfin.Data.Entities.Security; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Microsoft.EntityFrameworkCore.Metadata.Conventions; using Microsoft.Extensions.Logging; -namespace Jellyfin.Server.Implementations; +namespace Jellyfin.Database.Implementations; /// /// diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs index 9a63ed9f2..be99b46d5 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// FluentAPI configuration for the ActivityLog entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs index 8cc817fb8..146df5546 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// AncestorId configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs index 3f19b6986..7c15f064d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities.Security; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the ApiKey entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs index 057b6689a..b5fae4053 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// FluentAPI configuration for the AttachmentStreamInfo entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs index 08f2a3356..67a071039 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// Configuration for BaseItem. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs index b4c6511bf..c101e0085 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// Provides configuration for the BaseItemMetadataField entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs index d15049a1f..175a82e09 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// BaseItemProvider configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs index e9564b854..c7efef239 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// Provides configuration for the BaseItemMetadataField entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs index 5a84f7750..5935b632a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// Chapter configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs index 779aec986..550fa5073 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the CustomItemDisplayPreferences entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs index a750b65c0..5f87c8d40 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities.Security; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the Device entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs index 038afd752..923a53aca 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities.Security; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the DeviceOptions entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs index 9b437861b..92068c8f2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the DisplayPreferencesConfiguration entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs index abeeb09c9..0e63c130e 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// itemvalues Configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs index 9c22b114c..3860b0e16 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// itemvalues Configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs index 7e572f9a3..37e15f5e7 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// People configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs index cdaee9161..125b9e92c 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// People configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs index f3cccb13f..fe25d3064 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// People configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs index 240e284c0..90a3ec5d0 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the Permission entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs index 49c869c6a..d6d3fadfc 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the Permission entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs index dc1c17e5e..a198c80f7 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the TrickplayInfo entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs index bcaa3634e..4e830801e 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the User entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs index 7bbb28d43..a7e223c43 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// FluentAPI configuration for the UserData entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200514181226_AddActivityLog.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200514181226_AddActivityLog.Designer.cs index 80fe784dd..789100643 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200514181226_AddActivityLog.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200514181226_AddActivityLog.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200613202153_AddUsers.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200613202153_AddUsers.Designer.cs index 7aa4479b3..eab3cd3e7 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200613202153_AddUsers.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200613202153_AddUsers.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200728005145_AddDisplayPreferences.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200728005145_AddDisplayPreferences.Designer.cs index 3860c851d..91dd0ff7a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200728005145_AddDisplayPreferences.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200728005145_AddDisplayPreferences.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs index 1134f7aa4..8ec923103 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs index 607310caa..499faa9c4 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs index 02c3fc753..7ab851689 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs index 1cfd7112c..e14ed9380 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs index ecf7af495..05f2c80a2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210814002109_AddDevices.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210814002109_AddDevices.Designer.cs index dccba6f77..c9f3cf696 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210814002109_AddDevices.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210814002109_AddDevices.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs index e821c106e..ab7781d15 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230526173516_RemoveEasyPassword.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230526173516_RemoveEasyPassword.Designer.cs index 360fa0376..8a2806113 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230526173516_RemoveEasyPassword.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230526173516_RemoveEasyPassword.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230626233818_AddTrickplayInfos.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230626233818_AddTrickplayInfos.Designer.cs index 17d33845f..a11507bd5 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230626233818_AddTrickplayInfos.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230626233818_AddTrickplayInfos.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230923170422_UserCastReceiver.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230923170422_UserCastReceiver.Designer.cs index 4c0917669..ddea37f6d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230923170422_UserCastReceiver.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230923170422_UserCastReceiver.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240729140605_AddMediaSegments.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240729140605_AddMediaSegments.Designer.cs index 35a3cdad2..ab7065ee6 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240729140605_AddMediaSegments.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240729140605_AddMediaSegments.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs index 8dba31a67..aa60bff32 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241020103111_LibraryDbMigration.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241020103111_LibraryDbMigration.Designer.cs index 27745f601..2ea6dafe1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241020103111_LibraryDbMigration.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241020103111_LibraryDbMigration.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111131257_AddedCustomDataKey.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111131257_AddedCustomDataKey.Designer.cs index 1fbf21492..d589a4afd 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111131257_AddedCustomDataKey.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111131257_AddedCustomDataKey.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs index bac6fd5b5..3d70bb029 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs index ad622d44c..1e0d3b129 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112232041_fixMediaStreams.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112232041_fixMediaStreams.Designer.cs index dc4c8212b..ccf67d899 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112232041_fixMediaStreams.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112232041_fixMediaStreams.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112234144_FixMediaStreams2.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112234144_FixMediaStreams2.Designer.cs index 5714120b5..d3ba8c96a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112234144_FixMediaStreams2.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112234144_FixMediaStreams2.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs index 855f02fd3..2c0058c72 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250202021306_FixedCollation.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250202021306_FixedCollation.Designer.cs index d7b806d7a..da4bab3fd 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250202021306_FixedCollation.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250202021306_FixedCollation.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250204092455_MakeStartEndDateNullable.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250204092455_MakeStartEndDateNullable.Designer.cs index a329f1ef1..9b72d9688 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250204092455_MakeStartEndDateNullable.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250204092455_MakeStartEndDateNullable.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250214031148_ChannelIdGuid.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250214031148_ChannelIdGuid.Designer.cs index 48919c9b5..f5cfe86c4 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250214031148_ChannelIdGuid.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250214031148_ChannelIdGuid.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs index 79587a9c3..5d8ddde08 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/SqliteDesignTimeJellyfinDbFactory.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/SqliteDesignTimeJellyfinDbFactory.cs index 448bd2fc8..1629c732c 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/SqliteDesignTimeJellyfinDbFactory.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/SqliteDesignTimeJellyfinDbFactory.cs @@ -1,3 +1,4 @@ +using Jellyfin.Database.Implementations; using Jellyfin.Database.Providers.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ModelBuilderExtensions.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ModelBuilderExtensions.cs index 79ae1661a..0d7568619 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ModelBuilderExtensions.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ModelBuilderExtensions.cs @@ -3,46 +3,45 @@ using Jellyfin.Server.Implementations.ValueConverters; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -namespace Jellyfin.Server.Implementations +namespace Jellyfin.Database.Providers.Sqlite; + +/// +/// Model builder extensions. +/// +public static class ModelBuilderExtensions { /// - /// Model builder extensions. + /// Specify value converter for the object type. /// - public static class ModelBuilderExtensions + /// The model builder. + /// The . + /// The type to convert. + /// The modified . + public static ModelBuilder UseValueConverterForType(this ModelBuilder modelBuilder, ValueConverter converter) { - /// - /// Specify value converter for the object type. - /// - /// The model builder. - /// The . - /// The type to convert. - /// The modified . - public static ModelBuilder UseValueConverterForType(this ModelBuilder modelBuilder, ValueConverter converter) + var type = typeof(T); + foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { - var type = typeof(T); - foreach (var entityType in modelBuilder.Model.GetEntityTypes()) + foreach (var property in entityType.GetProperties()) { - foreach (var property in entityType.GetProperties()) + if (property.ClrType == type) { - if (property.ClrType == type) - { - property.SetValueConverter(converter); - } + property.SetValueConverter(converter); } } - - return modelBuilder; } - /// - /// Specify the default . - /// - /// The model builder to extend. - /// The to specify. - public static void SetDefaultDateTimeKind(this ModelBuilder modelBuilder, DateTimeKind kind) - { - modelBuilder.UseValueConverterForType(new DateTimeKindValueConverter(kind)); - modelBuilder.UseValueConverterForType(new DateTimeKindValueConverter(kind)); - } + return modelBuilder; + } + + /// + /// Specify the default . + /// + /// The model builder to extend. + /// The to specify. + public static void SetDefaultDateTimeKind(this ModelBuilder modelBuilder, DateTimeKind kind) + { + modelBuilder.UseValueConverterForType(new DateTimeKindValueConverter(kind)); + modelBuilder.UseValueConverterForType(new DateTimeKindValueConverter(kind)); } } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs index 2aa3522d8..d9eb0ae7a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs @@ -2,7 +2,7 @@ using System; using System.IO; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using MediaBrowser.Common.Configuration; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; diff --git a/src/Jellyfin.LiveTv/Channels/ChannelManager.cs b/src/Jellyfin.LiveTv/Channels/ChannelManager.cs index 83f68ab50..402a3f3b0 100644 --- a/src/Jellyfin.LiveTv/Channels/ChannelManager.cs +++ b/src/Jellyfin.LiveTv/Channels/ChannelManager.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using AsyncKeyedLock; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using Jellyfin.Extensions.Json; using MediaBrowser.Common.Extensions; diff --git a/src/Jellyfin.LiveTv/DefaultLiveTvService.cs b/src/Jellyfin.LiveTv/DefaultLiveTvService.cs index 318cc7acd..d8f873abe 100644 --- a/src/Jellyfin.LiveTv/DefaultLiveTvService.cs +++ b/src/Jellyfin.LiveTv/DefaultLiveTvService.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using Jellyfin.LiveTv.Configuration; using Jellyfin.LiveTv.Timers; diff --git a/src/Jellyfin.LiveTv/LiveTvManager.cs b/src/Jellyfin.LiveTv/LiveTvManager.cs index da98606a4..7ebcc4883 100644 --- a/src/Jellyfin.LiveTv/LiveTvManager.cs +++ b/src/Jellyfin.LiveTv/LiveTvManager.cs @@ -12,6 +12,7 @@ using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.LiveTv.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Channels; diff --git a/src/Jellyfin.LiveTv/Recordings/RecordingNotifier.cs b/src/Jellyfin.LiveTv/Recordings/RecordingNotifier.cs index 1d571805b..a5d186ce1 100644 --- a/src/Jellyfin.LiveTv/Recordings/RecordingNotifier.cs +++ b/src/Jellyfin.LiveTv/Recordings/RecordingNotifier.cs @@ -3,8 +3,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data; -using Jellyfin.Data.Enums; using Jellyfin.Data.Events; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Session; diff --git a/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs b/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs index 2f4caa386..9ca5d7420 100644 --- a/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs +++ b/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.LiveTv.Configuration; using Jellyfin.LiveTv.IO; using Jellyfin.LiveTv.Timers; diff --git a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs index 6b3afc935..0a6489d0a 100644 --- a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs @@ -8,7 +8,7 @@ using Jellyfin.Api.Auth; using Jellyfin.Api.Constants; using Jellyfin.Data; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Authentication; diff --git a/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs index 31d2b486b..1fe9fc97e 100644 --- a/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs @@ -8,7 +8,7 @@ using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; using Jellyfin.Api.Auth.FirstTimeSetupPolicy; using Jellyfin.Api.Constants; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Library; using Microsoft.AspNetCore.Authorization; diff --git a/tests/Jellyfin.Api.Tests/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandlerTests.cs index 534d1863c..ed5235252 100644 --- a/tests/Jellyfin.Api.Tests/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandlerTests.cs @@ -6,7 +6,7 @@ using AutoFixture.AutoMoq; using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; using Jellyfin.Api.Constants; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Library; using Microsoft.AspNetCore.Authorization; diff --git a/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs index a2d1b3607..2851b08e6 100644 --- a/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs +++ b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs @@ -5,6 +5,7 @@ using System.Security.Claims; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Net; using Xunit; diff --git a/tests/Jellyfin.Api.Tests/TestHelpers.cs b/tests/Jellyfin.Api.Tests/TestHelpers.cs index d84da89e2..03884d775 100644 --- a/tests/Jellyfin.Api.Tests/TestHelpers.cs +++ b/tests/Jellyfin.Api.Tests/TestHelpers.cs @@ -6,7 +6,7 @@ using System.Security.Claims; using Jellyfin.Api.Constants; using Jellyfin.Data; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Server.Implementations.Users; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Library; -- cgit v1.2.3 From 181a37a8cd512a46dfc5af55c43ef1468d206d75 Mon Sep 17 00:00:00 2001 From: timminator <150205162+timminator@users.noreply.github.com> Date: Fri, 28 Mar 2025 00:59:08 +0100 Subject: Fix consumer count off by one when closing a browser tab with a livestream that is transcoding (#13220) Rework Implementation Fix review issues Add missing nullorempty check Fix closely related #13721 --- .../Session/SessionManager.cs | 87 +++++++++++++++++++--- MediaBrowser.Controller/Session/ISessionManager.cs | 8 ++ .../Transcoding/TranscodeManager.cs | 9 +-- 3 files changed, 87 insertions(+), 17 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 42f7deca1..ac3e10594 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -64,6 +64,9 @@ namespace Emby.Server.Implementations.Session private readonly ConcurrentDictionary _activeConnections = new(StringComparer.OrdinalIgnoreCase); + private readonly ConcurrentDictionary> _activeLiveStreamSessions + = new(StringComparer.OrdinalIgnoreCase); + private Timer _idleTimer; private Timer _inactiveTimer; @@ -311,13 +314,49 @@ namespace Emby.Server.Implementations.Session _activeConnections.TryRemove(key, out _); if (!string.IsNullOrEmpty(session.PlayState?.LiveStreamId)) { - await _mediaSourceManager.CloseLiveStream(session.PlayState.LiveStreamId).ConfigureAwait(false); + await CloseLiveStreamIfNeededAsync(session.PlayState.LiveStreamId, session.Id).ConfigureAwait(false); } await OnSessionEnded(session).ConfigureAwait(false); } } + /// + public async Task CloseLiveStreamIfNeededAsync(string liveStreamId, string sessionIdOrPlaySessionId) + { + bool liveStreamNeedsToBeClosed = false; + + if (_activeLiveStreamSessions.TryGetValue(liveStreamId, out var activeSessionMappings)) + { + if (activeSessionMappings.TryRemove(sessionIdOrPlaySessionId, out var correspondingId)) + { + if (!string.IsNullOrEmpty(correspondingId)) + { + activeSessionMappings.TryRemove(correspondingId, out _); + } + + liveStreamNeedsToBeClosed = true; + } + + if (activeSessionMappings.IsEmpty) + { + _activeLiveStreamSessions.TryRemove(liveStreamId, out _); + } + } + + if (liveStreamNeedsToBeClosed) + { + try + { + await _mediaSourceManager.CloseLiveStream(liveStreamId).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error closing live stream"); + } + } + } + /// public async ValueTask ReportSessionEnded(string sessionId) { @@ -737,6 +776,11 @@ namespace Emby.Server.Implementations.Session } } + if (!string.IsNullOrEmpty(info.LiveStreamId)) + { + UpdateLiveStreamActiveSessionMappings(info.LiveStreamId, info.SessionId, info.PlaySessionId); + } + var eventArgs = new PlaybackStartEventArgs { Item = libraryItem, @@ -794,6 +838,32 @@ namespace Emby.Server.Implementations.Session return OnPlaybackProgress(info, false); } + private void UpdateLiveStreamActiveSessionMappings(string liveStreamId, string sessionId, string playSessionId) + { + var activeSessionMappings = _activeLiveStreamSessions.GetOrAdd(liveStreamId, _ => new ConcurrentDictionary()); + + if (!string.IsNullOrEmpty(playSessionId)) + { + if (!activeSessionMappings.TryGetValue(sessionId, out var currentPlaySessionId) || currentPlaySessionId != playSessionId) + { + if (!string.IsNullOrEmpty(currentPlaySessionId)) + { + activeSessionMappings.TryRemove(currentPlaySessionId, out _); + } + + activeSessionMappings[sessionId] = playSessionId; + activeSessionMappings[playSessionId] = sessionId; + } + } + else + { + if (!activeSessionMappings.TryGetValue(sessionId, out _)) + { + activeSessionMappings[sessionId] = string.Empty; + } + } + } + /// /// Used to report playback progress for an item. /// @@ -834,6 +904,11 @@ namespace Emby.Server.Implementations.Session } } + if (!string.IsNullOrEmpty(info.LiveStreamId)) + { + UpdateLiveStreamActiveSessionMappings(info.LiveStreamId, info.SessionId, info.PlaySessionId); + } + var eventArgs = new PlaybackProgressEventArgs { Item = libraryItem, @@ -1016,14 +1091,7 @@ namespace Emby.Server.Implementations.Session if (!string.IsNullOrEmpty(info.LiveStreamId)) { - try - { - await _mediaSourceManager.CloseLiveStream(info.LiveStreamId).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error closing live stream"); - } + await CloseLiveStreamIfNeededAsync(info.LiveStreamId, session.Id).ConfigureAwait(false); } var eventArgs = new PlaybackStopEventArgs @@ -2071,6 +2139,7 @@ namespace Emby.Server.Implementations.Session } _activeConnections.Clear(); + _activeLiveStreamSessions.Clear(); } } } diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 21131e6b5..47bcfdb6e 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -342,5 +342,13 @@ namespace MediaBrowser.Controller.Session Task RevokeUserTokens(Guid userId, string currentAccessToken); Task CloseIfNeededAsync(SessionInfo session); + + /// + /// Used to close the livestream if needed. + /// + /// The livestream id. + /// The session id or playsession id. + /// Task. + Task CloseLiveStreamIfNeededAsync(string liveStreamId, string sessionIdOrPlaySessionId); } } diff --git a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs index 85bb862c7..c7f9cf2cc 100644 --- a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs +++ b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs @@ -242,14 +242,7 @@ public sealed class TranscodeManager : ITranscodeManager, IDisposable if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId)) { - try - { - await _mediaSourceManager.CloseLiveStream(job.LiveStreamId).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error closing live stream for {Path}", job.Path); - } + await _sessionManager.CloseLiveStreamIfNeededAsync(job.LiveStreamId, job.PlaySessionId).ConfigureAwait(false); } } -- cgit v1.2.3 From 384134fd25fec22792733ccaa9f10a23d5c98eac Mon Sep 17 00:00:00 2001 From: gnattu Date: Fri, 28 Mar 2025 21:22:00 +0800 Subject: Use string literal --- MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs b/MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs index ea2289bd7..76fc5f695 100644 --- a/MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs +++ b/MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs @@ -14,7 +14,7 @@ public static class ApplePlatformHelper { private static readonly string[] _av1DecodeBlacklistedCpuClass = ["M1", "M2"]; - private static string GetSysctlValue(string name) + private static string GetSysctlValue(ReadOnlySpan name) { IntPtr length = IntPtr.Zero; // Get length of the value @@ -22,7 +22,7 @@ public static class ApplePlatformHelper if (osStatus != 0) { - throw new NotSupportedException($"Failed to get sysctl value for {name} with error {osStatus}"); + throw new NotSupportedException($"Failed to get sysctl value for {System.Text.Encoding.UTF8.GetString(name)} with error {osStatus}"); } IntPtr buffer = Marshal.AllocHGlobal(length.ToInt32()); @@ -31,7 +31,7 @@ public static class ApplePlatformHelper osStatus = SysctlByName(name, buffer, ref length, IntPtr.Zero, 0); if (osStatus != 0) { - throw new NotSupportedException($"Failed to get sysctl value for {name} with error {osStatus}"); + throw new NotSupportedException($"Failed to get sysctl value for {System.Text.Encoding.UTF8.GetString(name)} with error {osStatus}"); } return Marshal.PtrToStringAnsi(buffer) ?? string.Empty; @@ -42,9 +42,9 @@ public static class ApplePlatformHelper } } - private static int SysctlByName(string name, IntPtr oldp, ref IntPtr oldlenp, IntPtr newp, uint newlen) + private static int SysctlByName(ReadOnlySpan name, IntPtr oldp, ref IntPtr oldlenp, IntPtr newp, uint newlen) { - return NativeMethods.SysctlByName(System.Text.Encoding.ASCII.GetBytes(name), oldp, ref oldlenp, newp, newlen); + return NativeMethods.SysctlByName(name.ToArray(), oldp, ref oldlenp, newp, newlen); } /// @@ -61,7 +61,7 @@ public static class ApplePlatformHelper try { - string cpuBrandString = GetSysctlValue("machdep.cpu.brand_string"); + string cpuBrandString = GetSysctlValue("machdep.cpu.brand_string"u8); return !_av1DecodeBlacklistedCpuClass.Any(blacklistedCpuClass => cpuBrandString.Contains(blacklistedCpuClass, StringComparison.OrdinalIgnoreCase)); } catch (NotSupportedException e) -- cgit v1.2.3 From c69e9d8f2cac26a832f0ee09bed2809aae1872bf Mon Sep 17 00:00:00 2001 From: gnattu Date: Fri, 28 Mar 2025 21:30:39 +0800 Subject: Gate the macOS only functions --- MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs | 2 ++ MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs | 2 ++ 2 files changed, 4 insertions(+) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs b/MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs index 76fc5f695..a8ff58b09 100644 --- a/MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs +++ b/MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs @@ -3,6 +3,7 @@ using System; using System.Linq; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using Microsoft.Extensions.Logging; namespace MediaBrowser.MediaEncoding.Encoder; @@ -10,6 +11,7 @@ namespace MediaBrowser.MediaEncoding.Encoder; /// /// Helper class for Apple platform specific operations. /// +[SupportedOSPlatform("macos")] public static class ApplePlatformHelper { private static readonly string[] _av1DecodeBlacklistedCpuClass = ["M1", "M2"]; diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 776b2ab42..54d0eb4b5 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; +using System.Runtime.Versioning; using System.Text.RegularExpressions; using Microsoft.Extensions.Logging; @@ -437,6 +438,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } } + [SupportedOSPlatform("macos")] public bool CheckIsVideoToolboxAv1DecodeAvailable() { return ApplePlatformHelper.HasAv1HardwareAccel(_logger); -- cgit v1.2.3 From 49ac705867234c48e79ceb1cd84bc4394c65313d Mon Sep 17 00:00:00 2001 From: gnattu Date: Thu, 3 Apr 2025 08:06:02 +0800 Subject: Improve dynamic HDR metadata handling (#13277) * Add support for bitstream filter to remove dynamic hdr metadata * Add support for ffprobe's only_first_vframe for HDR10+ detection * Add BitStreamFilterOptionType for metadata removal check * Map HDR10+ metadata to VideoRangeType.cs Current implementation uses a hack that abuses the EL flag to avoid database schema changes. Should add proper field once EFCore migration is merged. * Add more Dolby Vision Range types Out of spec ones are problematic and should be marked as a dedicated invalid type and handled by the server to not crash the player. Profile 7 videos should not be treated as normal HDR10 videos at all and should remove the metadata before serving. * Remove dynamic hdr metadata when necessary * Allow direct playback of HDR10+ videos on HDR10 clients * Only use dovi codec tag when dovi metadata is not removed * Handle DV Profile 7 Videos better * Fix HDR10+ with new bitmask * Indicate the presence of HDR10+ in HLS SUPPLEMENTAL-CODECS * Fix Dovi 8.4 not labeled as HLG in HLS * Fallback to dovi_rpu bsf for av1 when possible * Fix dovi_rpu cli for av1 * Use correct EFCore db column for HDR10+ * Undo outdated migration * Add proper hdr10+ migration * Remove outdated migration * Rebase to new db code * Add migrations for Hdr10PlusPresentFlag * Directly use bsf enum * Add xmldocs for SupportsBitStreamFilterWithOption * Make `VideoRangeType.Unknown` explicitly default on api models. * Unset default for non-api model class * Use tuples for bsf dictionary for now --- Jellyfin.Api/Controllers/DynamicHlsController.cs | 9 +- Jellyfin.Api/Helpers/DynamicHlsHelper.cs | 85 +- Jellyfin.Data/Enums/VideoRangeType.cs | 21 + .../Item/MediaStreamRepository.cs | 4 +- .../MediaEncoding/BitStreamFilterOptionType.cs | 32 + .../MediaEncoding/EncodingHelper.cs | 211 ++- .../MediaEncoding/EncodingJobInfo.cs | 1 + .../MediaEncoding/IMediaEncoder.cs | 7 + .../Encoder/EncoderValidator.cs | 46 + MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 20 + .../Probing/InternalMediaInfoResult.cs | 7 + .../Probing/MediaFrameInfo.cs | 184 +++ .../Probing/MediaFrameSideDataInfo.cs | 16 + .../Probing/ProbeResultNormalizer.cs | 15 +- MediaBrowser.Model/Dlna/ConditionProcessor.cs | 9 + MediaBrowser.Model/Dlna/StreamInfo.cs | 1 + MediaBrowser.Model/Entities/MediaStream.cs | 37 +- .../Entities/MediaStreamInfo.cs | 2 + .../20250327171413_AddHdr10PlusFlag.Designer.cs | 1655 ++++++++++++++++++++ .../Migrations/20250327171413_AddHdr10PlusFlag.cs | 28 + .../Migrations/JellyfinDbModelSnapshot.cs | 3 + 21 files changed, 2327 insertions(+), 66 deletions(-) create mode 100644 MediaBrowser.Controller/MediaEncoding/BitStreamFilterOptionType.cs create mode 100644 MediaBrowser.MediaEncoding/Probing/MediaFrameInfo.cs create mode 100644 MediaBrowser.MediaEncoding/Probing/MediaFrameSideDataInfo.cs create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250327171413_AddHdr10PlusFlag.Designer.cs create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250327171413_AddHdr10PlusFlag.cs (limited to 'MediaBrowser.MediaEncoding') diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 51291ec62..31b96972e 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -1675,7 +1675,7 @@ public class DynamicHlsController : BaseJellyfinApiController } var audioCodec = _encodingHelper.GetAudioEncoder(state); - var bitStreamArgs = EncodingHelper.GetAudioBitStreamArguments(state, state.Request.SegmentContainer, state.MediaSource.Container); + var bitStreamArgs = _encodingHelper.GetAudioBitStreamArguments(state, state.Request.SegmentContainer, state.MediaSource.Container); // opus, dts, truehd and flac (in FFmpeg 5 and older) are experimental in mp4 muxer var strictArgs = string.Empty; @@ -1822,10 +1822,11 @@ public class DynamicHlsController : BaseJellyfinApiController // Clients reporting Dolby Vision capabilities with fallbacks may only support the fallback layer. // Only enable Dolby Vision remuxing if the client explicitly declares support for profiles without fallbacks. var clientSupportsDoVi = requestedRange.Contains(VideoRangeType.DOVI.ToString(), StringComparison.OrdinalIgnoreCase); - var videoIsDoVi = state.VideoStream.VideoRangeType is VideoRangeType.DOVI or VideoRangeType.DOVIWithHDR10 or VideoRangeType.DOVIWithHLG or VideoRangeType.DOVIWithSDR; + var videoIsDoVi = EncodingHelper.IsDovi(state.VideoStream); if (EncodingHelper.IsCopyCodec(codec) - && (videoIsDoVi && clientSupportsDoVi)) + && (videoIsDoVi && clientSupportsDoVi) + && !_encodingHelper.IsDoviRemoved(state)) { if (isActualOutputVideoCodecHevc) { @@ -1855,7 +1856,7 @@ public class DynamicHlsController : BaseJellyfinApiController // If h264_mp4toannexb is ever added, do not use it for live tv. if (state.VideoStream is not null && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase)) { - string bitStreamArgs = EncodingHelper.GetBitStreamArgs(state.VideoStream); + string bitStreamArgs = _encodingHelper.GetBitStreamArgs(state, MediaStreamType.Video); if (!string.IsNullOrEmpty(bitStreamArgs)) { args += " " + bitStreamArgs; diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs index ebd0288ca..a38ad379c 100644 --- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs +++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs @@ -345,13 +345,15 @@ public class DynamicHlsHelper if (videoRange == VideoRange.HDR) { - if (videoRangeType == VideoRangeType.HLG) + switch (videoRangeType) { - builder.Append(",VIDEO-RANGE=HLG"); - } - else - { - builder.Append(",VIDEO-RANGE=PQ"); + case VideoRangeType.HLG: + case VideoRangeType.DOVIWithHLG: + builder.Append(",VIDEO-RANGE=HLG"); + break; + default: + builder.Append(",VIDEO-RANGE=PQ"); + break; } } } @@ -418,36 +420,67 @@ public class DynamicHlsHelper /// StreamState of the current stream. private void AppendPlaylistSupplementalCodecsField(StringBuilder builder, StreamState state) { - // Dolby Vision currently cannot exist when transcoding + // HDR dynamic metadata currently cannot exist when transcoding if (!EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) { return; } - var dvProfile = state.VideoStream.DvProfile; - var dvLevel = state.VideoStream.DvLevel; - var dvRangeString = state.VideoStream.VideoRangeType switch + if (EncodingHelper.IsDovi(state.VideoStream) && !_encodingHelper.IsDoviRemoved(state)) { - VideoRangeType.DOVIWithHDR10 => "db1p", - VideoRangeType.DOVIWithHLG => "db4h", - _ => string.Empty - }; + AppendDvString(); + } + else if (EncodingHelper.IsHdr10Plus(state.VideoStream) && !_encodingHelper.IsHdr10PlusRemoved(state)) + { + AppendHdr10PlusString(); + } - if (dvProfile is null || dvLevel is null || string.IsNullOrEmpty(dvRangeString)) + return; + + void AppendDvString() { - return; + var dvProfile = state.VideoStream.DvProfile; + var dvLevel = state.VideoStream.DvLevel; + var dvRangeString = state.VideoStream.VideoRangeType switch + { + VideoRangeType.DOVIWithHDR10 => "db1p", + VideoRangeType.DOVIWithHLG => "db4h", + VideoRangeType.DOVIWithHDR10Plus => "db1p", // The HDR10+ metadata would be removed if Dovi metadata is not removed + _ => string.Empty // Don't label Dovi with EL and SDR due to compatability issues, ignore invalid configurations + }; + + if (dvProfile is null || dvLevel is null || string.IsNullOrEmpty(dvRangeString)) + { + return; + } + + var dvFourCc = string.Equals(state.ActualOutputVideoCodec, "av1", StringComparison.OrdinalIgnoreCase) ? "dav1" : "dvh1"; + builder.Append(",SUPPLEMENTAL-CODECS=\"") + .Append(dvFourCc) + .Append('.') + .Append(dvProfile.Value.ToString("D2", CultureInfo.InvariantCulture)) + .Append('.') + .Append(dvLevel.Value.ToString("D2", CultureInfo.InvariantCulture)) + .Append('/') + .Append(dvRangeString) + .Append('"'); } - var dvFourCc = string.Equals(state.ActualOutputVideoCodec, "av1", StringComparison.OrdinalIgnoreCase) ? "dav1" : "dvh1"; - builder.Append(",SUPPLEMENTAL-CODECS=\"") - .Append(dvFourCc) - .Append('.') - .Append(dvProfile.Value.ToString("D2", CultureInfo.InvariantCulture)) - .Append('.') - .Append(dvLevel.Value.ToString("D2", CultureInfo.InvariantCulture)) - .Append('/') - .Append(dvRangeString) - .Append('"'); + void AppendHdr10PlusString() + { + var videoCodecLevel = GetOutputVideoCodecLevel(state); + if (string.IsNullOrEmpty(state.ActualOutputVideoCodec) || videoCodecLevel is null) + { + return; + } + + var videoCodecString = GetPlaylistVideoCodecs(state, state.ActualOutputVideoCodec, videoCodecLevel.Value); + builder.Append(",SUPPLEMENTAL-CODECS=\"") + .Append(videoCodecString) + .Append('/') + .Append("cdm4") + .Append('"'); + } } /// diff --git a/Jellyfin.Data/Enums/VideoRangeType.cs b/Jellyfin.Data/Enums/VideoRangeType.cs index 853c2c73d..ce232d73c 100644 --- a/Jellyfin.Data/Enums/VideoRangeType.cs +++ b/Jellyfin.Data/Enums/VideoRangeType.cs @@ -45,6 +45,27 @@ public enum VideoRangeType /// DOVIWithSDR, + /// + /// Dolby Vision with Enhancment Layer (Profile 7). + /// + DOVIWithEL, + + /// + /// Dolby Vision and HDR10+ Metadata coexists. + /// + DOVIWithHDR10Plus, + + /// + /// Dolby Vision with Enhancment Layer (Profile 7) and HDR10+ Metadata coexists. + /// + DOVIWithELHDR10Plus, + + /// + /// Dolby Vision with invalid configuration. e.g. Profile 8 compat id 6. + /// When using this range, the server would assume the video is still HDR10 after removing the Dolby Vision metadata. + /// + DOVIInvalid, + /// /// HDR10+ video range type (10bit to 16bit). /// diff --git a/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs b/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs index 36c3b9e56..1be31db72 100644 --- a/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs +++ b/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs @@ -140,6 +140,7 @@ public class MediaStreamRepository : IMediaStreamRepository dto.DvBlSignalCompatibilityId = entity.DvBlSignalCompatibilityId; dto.IsHearingImpaired = entity.IsHearingImpaired.GetValueOrDefault(); dto.Rotation = entity.Rotation; + dto.Hdr10PlusPresentFlag = entity.Hdr10PlusPresentFlag; if (dto.Type is MediaStreamType.Audio or MediaStreamType.Subtitle) { @@ -207,7 +208,8 @@ public class MediaStreamRepository : IMediaStreamRepository BlPresentFlag = dto.BlPresentFlag, DvBlSignalCompatibilityId = dto.DvBlSignalCompatibilityId, IsHearingImpaired = dto.IsHearingImpaired, - Rotation = dto.Rotation + Rotation = dto.Rotation, + Hdr10PlusPresentFlag = dto.Hdr10PlusPresentFlag, }; return entity; } diff --git a/MediaBrowser.Controller/MediaEncoding/BitStreamFilterOptionType.cs b/MediaBrowser.Controller/MediaEncoding/BitStreamFilterOptionType.cs new file mode 100644 index 000000000..41d21e440 --- /dev/null +++ b/MediaBrowser.Controller/MediaEncoding/BitStreamFilterOptionType.cs @@ -0,0 +1,32 @@ +namespace MediaBrowser.Controller.MediaEncoding; + +/// +/// Enum BitStreamFilterOptionType. +/// +public enum BitStreamFilterOptionType +{ + /// + /// hevc_metadata bsf with remove_dovi option. + /// + HevcMetadataRemoveDovi = 0, + + /// + /// hevc_metadata bsf with remove_hdr10plus option. + /// + HevcMetadataRemoveHdr10Plus = 1, + + /// + /// av1_metadata bsf with remove_dovi option. + /// + Av1MetadataRemoveDovi = 2, + + /// + /// av1_metadata bsf with remove_hdr10plus option. + /// + Av1MetadataRemoveHdr10Plus = 3, + + /// + /// dovi_rpu bsf with strip option. + /// + DoviRpuStrip = 4, +} diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index ed975af7f..afa962a41 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -162,6 +162,13 @@ namespace MediaBrowser.Controller.MediaEncoding _configurationManager = configurationManager; } + private enum DynamicHdrMetadataRemovalPlan + { + None, + RemoveDovi, + RemoveHdr10Plus, + } + [GeneratedRegex(@"\s+")] private static partial Regex WhiteSpaceRegex(); @@ -342,11 +349,8 @@ namespace MediaBrowser.Controller.MediaEncoding return isSwDecoder || isNvdecDecoder || isVaapiDecoder || isD3d11vaDecoder || isVideoToolBoxDecoder; } - return state.VideoStream.VideoRange == VideoRange.HDR - && (state.VideoStream.VideoRangeType == VideoRangeType.HDR10 - || state.VideoStream.VideoRangeType == VideoRangeType.HLG - || state.VideoStream.VideoRangeType == VideoRangeType.DOVIWithHDR10 - || state.VideoStream.VideoRangeType == VideoRangeType.DOVIWithHLG); + // GPU tonemapping supports all HDR RangeTypes + return state.VideoStream.VideoRange == VideoRange.HDR; } private bool IsVulkanHwTonemapAvailable(EncodingJobInfo state, EncodingOptions options) @@ -381,8 +385,7 @@ namespace MediaBrowser.Controller.MediaEncoding } return state.VideoStream.VideoRange == VideoRange.HDR - && (state.VideoStream.VideoRangeType == VideoRangeType.HDR10 - || state.VideoStream.VideoRangeType == VideoRangeType.DOVIWithHDR10); + && IsDoviWithHdr10Bl(state.VideoStream); } private bool IsVideoToolboxTonemapAvailable(EncodingJobInfo state, EncodingOptions options) @@ -397,7 +400,8 @@ namespace MediaBrowser.Controller.MediaEncoding // Certain DV profile 5 video works in Safari with direct playing, but the VideoToolBox does not produce correct mapping results with transcoding. // All other HDR formats working. return state.VideoStream.VideoRange == VideoRange.HDR - && state.VideoStream.VideoRangeType is VideoRangeType.HDR10 or VideoRangeType.HLG or VideoRangeType.HDR10Plus or VideoRangeType.DOVIWithHDR10 or VideoRangeType.DOVIWithHLG; + && (IsDoviWithHdr10Bl(state.VideoStream) + || state.VideoStream.VideoRangeType is VideoRangeType.HLG); } private bool IsVideoStreamHevcRext(EncodingJobInfo state) @@ -1301,6 +1305,13 @@ namespace MediaBrowser.Controller.MediaEncoding || codec.Contains("hevc", StringComparison.OrdinalIgnoreCase); } + public static bool IsAv1(MediaStream stream) + { + var codec = stream.Codec ?? string.Empty; + + return codec.Contains("av1", StringComparison.OrdinalIgnoreCase); + } + public static bool IsAAC(MediaStream stream) { var codec = stream.Codec ?? string.Empty; @@ -1308,8 +1319,125 @@ namespace MediaBrowser.Controller.MediaEncoding return codec.Contains("aac", StringComparison.OrdinalIgnoreCase); } - public static string GetBitStreamArgs(MediaStream stream) + public static bool IsDoviWithHdr10Bl(MediaStream stream) + { + var rangeType = stream?.VideoRangeType; + + return rangeType is VideoRangeType.DOVIWithHDR10 + or VideoRangeType.DOVIWithEL + or VideoRangeType.DOVIWithHDR10Plus + or VideoRangeType.DOVIWithELHDR10Plus + or VideoRangeType.DOVIInvalid; + } + + public static bool IsDovi(MediaStream stream) + { + var rangeType = stream?.VideoRangeType; + + return IsDoviWithHdr10Bl(stream) + || (rangeType is VideoRangeType.DOVI + or VideoRangeType.DOVIWithHLG + or VideoRangeType.DOVIWithSDR); + } + + public static bool IsHdr10Plus(MediaStream stream) + { + var rangeType = stream?.VideoRangeType; + + return rangeType is VideoRangeType.HDR10Plus + or VideoRangeType.DOVIWithHDR10Plus + or VideoRangeType.DOVIWithELHDR10Plus; + } + + /// + /// Check if dynamic HDR metadata should be removed during stream copy. + /// Please note this check assumes the range check has already been done + /// and trivial fallbacks like HDR10+ to HDR10, DOVIWithHDR10 to HDR10 is already checked. + /// + private static DynamicHdrMetadataRemovalPlan ShouldRemoveDynamicHdrMetadata(EncodingJobInfo state) + { + var videoStream = state.VideoStream; + if (videoStream.VideoRange is not VideoRange.HDR) + { + return DynamicHdrMetadataRemovalPlan.None; + } + + var requestedRangeTypes = state.GetRequestedRangeTypes(state.VideoStream.Codec); + if (requestedRangeTypes.Length == 0) + { + return DynamicHdrMetadataRemovalPlan.None; + } + + var requestHasHDR10 = requestedRangeTypes.Contains(VideoRangeType.HDR10.ToString(), StringComparison.OrdinalIgnoreCase); + var requestHasDOVI = requestedRangeTypes.Contains(VideoRangeType.DOVI.ToString(), StringComparison.OrdinalIgnoreCase); + var requestHasDOVIwithEL = requestedRangeTypes.Contains(VideoRangeType.DOVIWithEL.ToString(), StringComparison.OrdinalIgnoreCase); + var requestHasDOVIwithELHDR10plus = requestedRangeTypes.Contains(VideoRangeType.DOVIWithELHDR10Plus.ToString(), StringComparison.OrdinalIgnoreCase); + + var shouldRemoveHdr10Plus = false; + // Case 1: Client supports HDR10, does not support DOVI with EL but EL presets + var shouldRemoveDovi = (!requestHasDOVIwithEL && requestHasHDR10) && videoStream.VideoRangeType == VideoRangeType.DOVIWithEL; + + // Case 2: Client supports DOVI, does not support broken DOVI config + // Client does not report DOVI support should be allowed to copy bad data for remuxing as HDR10 players would not crash + shouldRemoveDovi = shouldRemoveDovi || (requestHasDOVI && videoStream.VideoRangeType == VideoRangeType.DOVIInvalid); + + // Special case: we have a video with both EL and HDR10+ + // If the client supports EL but not in the case of coexistence with HDR10+, remove HDR10+ for compatibility reasons. + // Otherwise, remove DOVI if the client is not a DOVI player + if (videoStream.VideoRangeType == VideoRangeType.DOVIWithELHDR10Plus) + { + shouldRemoveHdr10Plus = requestHasDOVIwithEL && !requestHasDOVIwithELHDR10plus; + shouldRemoveDovi = shouldRemoveDovi || !shouldRemoveHdr10Plus; + } + + if (shouldRemoveDovi) + { + return DynamicHdrMetadataRemovalPlan.RemoveDovi; + } + + // If the client is a Dolby Vision Player, remove the HDR10+ metadata to avoid playback issues + shouldRemoveHdr10Plus = shouldRemoveHdr10Plus || (requestHasDOVI && videoStream.VideoRangeType == VideoRangeType.DOVIWithHDR10Plus); + return shouldRemoveHdr10Plus ? DynamicHdrMetadataRemovalPlan.RemoveHdr10Plus : DynamicHdrMetadataRemovalPlan.None; + } + + private bool CanEncoderRemoveDynamicHdrMetadata(DynamicHdrMetadataRemovalPlan plan, MediaStream videoStream) { + return plan switch + { + DynamicHdrMetadataRemovalPlan.RemoveDovi => _mediaEncoder.SupportsBitStreamFilterWithOption(BitStreamFilterOptionType.DoviRpuStrip) + || (IsH265(videoStream) && _mediaEncoder.SupportsBitStreamFilterWithOption(BitStreamFilterOptionType.HevcMetadataRemoveDovi)) + || (IsAv1(videoStream) && _mediaEncoder.SupportsBitStreamFilterWithOption(BitStreamFilterOptionType.Av1MetadataRemoveDovi)), + DynamicHdrMetadataRemovalPlan.RemoveHdr10Plus => (IsH265(videoStream) && _mediaEncoder.SupportsBitStreamFilterWithOption(BitStreamFilterOptionType.HevcMetadataRemoveHdr10Plus)) + || (IsAv1(videoStream) && _mediaEncoder.SupportsBitStreamFilterWithOption(BitStreamFilterOptionType.Av1MetadataRemoveHdr10Plus)), + _ => true, + }; + } + + public bool IsDoviRemoved(EncodingJobInfo state) + { + return state?.VideoStream is not null && ShouldRemoveDynamicHdrMetadata(state) == DynamicHdrMetadataRemovalPlan.RemoveDovi + && CanEncoderRemoveDynamicHdrMetadata(DynamicHdrMetadataRemovalPlan.RemoveDovi, state.VideoStream); + } + + public bool IsHdr10PlusRemoved(EncodingJobInfo state) + { + return state?.VideoStream is not null && ShouldRemoveDynamicHdrMetadata(state) == DynamicHdrMetadataRemovalPlan.RemoveHdr10Plus + && CanEncoderRemoveDynamicHdrMetadata(DynamicHdrMetadataRemovalPlan.RemoveHdr10Plus, state.VideoStream); + } + + public string GetBitStreamArgs(EncodingJobInfo state, MediaStreamType streamType) + { + if (state is null) + { + return null; + } + + var stream = streamType switch + { + MediaStreamType.Audio => state.AudioStream, + MediaStreamType.Video => state.VideoStream, + _ => state.VideoStream + }; // TODO This is auto inserted into the mpegts mux so it might not be needed. // https://www.ffmpeg.org/ffmpeg-bitstream-filters.html#h264_005fmp4toannexb if (IsH264(stream)) @@ -1317,21 +1445,57 @@ namespace MediaBrowser.Controller.MediaEncoding return "-bsf:v h264_mp4toannexb"; } + if (IsAAC(stream)) + { + // Convert adts header(mpegts) to asc header(mp4). + return "-bsf:a aac_adtstoasc"; + } + if (IsH265(stream)) { - return "-bsf:v hevc_mp4toannexb"; + var filter = "-bsf:v hevc_mp4toannexb"; + + // The following checks are not complete because the copy would be rejected + // if the encoder cannot remove required metadata. + // And if bsf is used, we must already be using copy codec. + switch (ShouldRemoveDynamicHdrMetadata(state)) + { + default: + case DynamicHdrMetadataRemovalPlan.None: + break; + case DynamicHdrMetadataRemovalPlan.RemoveDovi: + filter += _mediaEncoder.SupportsBitStreamFilterWithOption(BitStreamFilterOptionType.HevcMetadataRemoveDovi) + ? ",hevc_metadata=remove_dovi=1" + : ",dovi_rpu=strip=1"; + break; + case DynamicHdrMetadataRemovalPlan.RemoveHdr10Plus: + filter += ",hevc_metadata=remove_hdr10plus=1"; + break; + } + + return filter; } - if (IsAAC(stream)) + if (IsAv1(stream)) { - // Convert adts header(mpegts) to asc header(mp4). - return "-bsf:a aac_adtstoasc"; + switch (ShouldRemoveDynamicHdrMetadata(state)) + { + default: + case DynamicHdrMetadataRemovalPlan.None: + return null; + case DynamicHdrMetadataRemovalPlan.RemoveDovi: + return _mediaEncoder.SupportsBitStreamFilterWithOption(BitStreamFilterOptionType.Av1MetadataRemoveDovi) + ? "-bsf:v av1_metadata=remove_dovi=1" + : "-bsf:v dovi_rpu=strip=1"; + case DynamicHdrMetadataRemovalPlan.RemoveHdr10Plus: + return "-bsf:v av1_metadata=remove_hdr10plus=1"; + } } return null; } - public static string GetAudioBitStreamArguments(EncodingJobInfo state, string segmentContainer, string mediaSourceContainer) + public string GetAudioBitStreamArguments(EncodingJobInfo state, string segmentContainer, string mediaSourceContainer) { var bitStreamArgs = string.Empty; var segmentFormat = GetSegmentFileExtension(segmentContainer).TrimStart('.'); @@ -1342,7 +1506,7 @@ namespace MediaBrowser.Controller.MediaEncoding || string.Equals(mediaSourceContainer, "aac", StringComparison.OrdinalIgnoreCase) || string.Equals(mediaSourceContainer, "hls", StringComparison.OrdinalIgnoreCase))) { - bitStreamArgs = GetBitStreamArgs(state.AudioStream); + bitStreamArgs = GetBitStreamArgs(state, MediaStreamType.Audio); bitStreamArgs = string.IsNullOrEmpty(bitStreamArgs) ? string.Empty : " " + bitStreamArgs; } @@ -2169,7 +2333,6 @@ namespace MediaBrowser.Controller.MediaEncoding } // DOVIWithHDR10 should be compatible with HDR10 supporting players. Same goes with HLG and of course SDR. So allow copy of those formats - var requestHasHDR10 = requestedRangeTypes.Contains(VideoRangeType.HDR10.ToString(), StringComparison.OrdinalIgnoreCase); var requestHasHLG = requestedRangeTypes.Contains(VideoRangeType.HLG.ToString(), StringComparison.OrdinalIgnoreCase); var requestHasSDR = requestedRangeTypes.Contains(VideoRangeType.SDR.ToString(), StringComparison.OrdinalIgnoreCase); @@ -2177,9 +2340,17 @@ namespace MediaBrowser.Controller.MediaEncoding if (!requestedRangeTypes.Contains(videoStream.VideoRangeType.ToString(), StringComparison.OrdinalIgnoreCase) && !((requestHasHDR10 && videoStream.VideoRangeType == VideoRangeType.DOVIWithHDR10) || (requestHasHLG && videoStream.VideoRangeType == VideoRangeType.DOVIWithHLG) - || (requestHasSDR && videoStream.VideoRangeType == VideoRangeType.DOVIWithSDR))) - { - return false; + || (requestHasSDR && videoStream.VideoRangeType == VideoRangeType.DOVIWithSDR) + || (requestHasHDR10 && videoStream.VideoRangeType == VideoRangeType.HDR10Plus))) + { + // Check complicated cases where we need to remove dynamic metadata + // Conservatively refuse to copy if the encoder can't remove dynamic metadata, + // but a removal is required for compatability reasons. + var dynamicHdrMetadataRemovalPlan = ShouldRemoveDynamicHdrMetadata(state); + if (!CanEncoderRemoveDynamicHdrMetadata(dynamicHdrMetadataRemovalPlan, videoStream)) + { + return false; + } } } @@ -7244,7 +7415,7 @@ namespace MediaBrowser.Controller.MediaEncoding && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase)) { - string bitStreamArgs = GetBitStreamArgs(state.VideoStream); + string bitStreamArgs = GetBitStreamArgs(state, MediaStreamType.Video); if (!string.IsNullOrEmpty(bitStreamArgs)) { args += " " + bitStreamArgs; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index 7586ac902..8d6211051 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Globalization; using System.Linq; using Jellyfin.Data.Enums; diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index a60f52340..de6353c4c 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -116,6 +116,13 @@ namespace MediaBrowser.Controller.MediaEncoding /// true if the filter is supported, false otherwise. bool SupportsFilterWithOption(FilterOptionType option); + /// + /// Whether the bitstream filter is supported with the given option. + /// + /// The option. + /// true if the bitstream filter is supported, false otherwise. + bool SupportsBitStreamFilterWithOption(BitStreamFilterOptionType option); + /// /// Extracts the audio image. /// diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 54d0eb4b5..d28cd70ef 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -7,6 +7,7 @@ using System.Globalization; using System.Linq; using System.Runtime.Versioning; using System.Text.RegularExpressions; +using MediaBrowser.Controller.MediaEncoding; using Microsoft.Extensions.Logging; namespace MediaBrowser.MediaEncoding.Encoder @@ -160,6 +161,15 @@ namespace MediaBrowser.MediaEncoding.Encoder { 6, new string[] { "transpose_opencl", "rotate by half-turn" } } }; + private static readonly Dictionary _bsfOptionsDict = new Dictionary + { + { BitStreamFilterOptionType.HevcMetadataRemoveDovi, ("hevc_metadata", "remove_dovi") }, + { BitStreamFilterOptionType.HevcMetadataRemoveHdr10Plus, ("hevc_metadata", "remove_hdr10plus") }, + { BitStreamFilterOptionType.Av1MetadataRemoveDovi, ("av1_metadata", "remove_dovi") }, + { BitStreamFilterOptionType.Av1MetadataRemoveHdr10Plus, ("av1_metadata", "remove_hdr10plus") }, + { BitStreamFilterOptionType.DoviRpuStrip, ("dovi_rpu", "strip") } + }; + // These are the library versions that corresponds to our minimum ffmpeg version 4.4 according to the version table below // Refers to the versions in https://ffmpeg.org/download.html private static readonly Dictionary _ffmpegMinimumLibraryVersions = new Dictionary @@ -286,6 +296,9 @@ namespace MediaBrowser.MediaEncoding.Encoder public IDictionary GetFiltersWithOption() => GetFFmpegFiltersWithOption(); + public IDictionary GetBitStreamFiltersWithOption() => _bsfOptionsDict + .ToDictionary(item => item.Key, item => CheckBitStreamFilterWithOption(item.Value.Item1, item.Value.Item2)); + public Version? GetFFmpegVersion() { string output; @@ -495,6 +508,34 @@ namespace MediaBrowser.MediaEncoding.Encoder return false; } + public bool CheckBitStreamFilterWithOption(string filter, string option) + { + if (string.IsNullOrEmpty(filter) || string.IsNullOrEmpty(option)) + { + return false; + } + + string output; + try + { + output = GetProcessOutput(_encoderPath, "-h bsf=" + filter, false, null); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error detecting the given bit stream filter"); + return false; + } + + if (output.Contains("Bit stream filter " + filter, StringComparison.Ordinal)) + { + return output.Contains(option, StringComparison.Ordinal); + } + + _logger.LogWarning("Bit stream filter: {Name} with option {Option} is not available", filter, option); + + return false; + } + public bool CheckSupportedRuntimeKey(string keyDesc, Version? ffmpegVersion) { if (string.IsNullOrEmpty(keyDesc)) @@ -523,6 +564,11 @@ namespace MediaBrowser.MediaEncoding.Encoder return !string.IsNullOrEmpty(flag) && GetProcessExitCode(_encoderPath, $"-loglevel quiet -hwaccel_flags +{flag} -hide_banner -f lavfi -i nullsrc=s=1x1:d=100 -f null -"); } + public bool CheckSupportedProberOption(string option, string proberPath) + { + return !string.IsNullOrEmpty(option) && GetProcessExitCode(proberPath, $"-loglevel quiet -f lavfi -i nullsrc=s=1x1:d=1 -{option}"); + } + private IEnumerable GetCodecs(Codec codec) { string codecstr = codec == Codec.Encoder ? "encoders" : "decoders"; diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index e96040506..9a759ba41 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -73,9 +73,11 @@ namespace MediaBrowser.MediaEncoding.Encoder private List _hwaccels = new List(); private List _filters = new List(); private IDictionary _filtersWithOption = new Dictionary(); + private IDictionary _bitStreamFiltersWithOption = new Dictionary(); private bool _isPkeyPauseSupported = false; private bool _isLowPriorityHwDecodeSupported = false; + private bool _proberSupportsFirstVideoFrame = false; private bool _isVaapiDeviceAmd = false; private bool _isVaapiDeviceInteliHD = false; @@ -222,6 +224,7 @@ namespace MediaBrowser.MediaEncoding.Encoder SetAvailableEncoders(validator.GetEncoders()); SetAvailableFilters(validator.GetFilters()); SetAvailableFiltersWithOption(validator.GetFiltersWithOption()); + SetAvailableBitStreamFiltersWithOption(validator.GetBitStreamFiltersWithOption()); SetAvailableHwaccels(validator.GetHwaccels()); SetMediaEncoderVersion(validator); @@ -229,6 +232,7 @@ namespace MediaBrowser.MediaEncoding.Encoder _isPkeyPauseSupported = validator.CheckSupportedRuntimeKey("p pause transcoding", _ffmpegVersion); _isLowPriorityHwDecodeSupported = validator.CheckSupportedHwaccelFlag("low_priority"); + _proberSupportsFirstVideoFrame = validator.CheckSupportedProberOption("only_first_vframe", _ffprobePath); // Check the Vaapi device vendor if (OperatingSystem.IsLinux() @@ -342,6 +346,11 @@ namespace MediaBrowser.MediaEncoding.Encoder _filtersWithOption = dict; } + public void SetAvailableBitStreamFiltersWithOption(IDictionary dict) + { + _bitStreamFiltersWithOption = dict; + } + public void SetMediaEncoderVersion(EncoderValidator validator) { _ffmpegVersion = validator.GetFFmpegVersion(); @@ -382,6 +391,11 @@ namespace MediaBrowser.MediaEncoding.Encoder return false; } + public bool SupportsBitStreamFilterWithOption(BitStreamFilterOptionType option) + { + return _bitStreamFiltersWithOption.TryGetValue(option, out var val) && val; + } + public bool CanEncodeToAudioCodec(string codec) { if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase)) @@ -501,6 +515,12 @@ namespace MediaBrowser.MediaEncoding.Encoder var args = extractChapters ? "{0} -i {1} -threads {2} -v warning -print_format json -show_streams -show_chapters -show_format" : "{0} -i {1} -threads {2} -v warning -print_format json -show_streams -show_format"; + + if (_proberSupportsFirstVideoFrame) + { + args += " -show_frames -only_first_vframe"; + } + args = string.Format(CultureInfo.InvariantCulture, args, probeSizeArgument, inputPath, _threads).Trim(); var process = new Process diff --git a/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs b/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs index d4d153b08..53eea64db 100644 --- a/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs +++ b/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs @@ -30,5 +30,12 @@ namespace MediaBrowser.MediaEncoding.Probing /// The chapters. [JsonPropertyName("chapters")] public IReadOnlyList Chapters { get; set; } + + /// + /// Gets or sets the frames. + /// + /// The streams. + [JsonPropertyName("frames")] + public IReadOnlyList Frames { get; set; } } } diff --git a/MediaBrowser.MediaEncoding/Probing/MediaFrameInfo.cs b/MediaBrowser.MediaEncoding/Probing/MediaFrameInfo.cs new file mode 100644 index 000000000..bed4368ed --- /dev/null +++ b/MediaBrowser.MediaEncoding/Probing/MediaFrameInfo.cs @@ -0,0 +1,184 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace MediaBrowser.MediaEncoding.Probing; + +/// +/// Class MediaFrameInfo. +/// +public class MediaFrameInfo +{ + /// + /// Gets or sets the media type. + /// + [JsonPropertyName("media_type")] + public string? MediaType { get; set; } + + /// + /// Gets or sets the StreamIndex. + /// + [JsonPropertyName("stream_index")] + public int? StreamIndex { get; set; } + + /// + /// Gets or sets the KeyFrame. + /// + [JsonPropertyName("key_frame")] + public int? KeyFrame { get; set; } + + /// + /// Gets or sets the Pts. + /// + [JsonPropertyName("pts")] + public long? Pts { get; set; } + + /// + /// Gets or sets the PtsTime. + /// + [JsonPropertyName("pts_time")] + public string? PtsTime { get; set; } + + /// + /// Gets or sets the BestEffortTimestamp. + /// + [JsonPropertyName("best_effort_timestamp")] + public long BestEffortTimestamp { get; set; } + + /// + /// Gets or sets the BestEffortTimestampTime. + /// + [JsonPropertyName("best_effort_timestamp_time")] + public string? BestEffortTimestampTime { get; set; } + + /// + /// Gets or sets the Duration. + /// + [JsonPropertyName("duration")] + public int Duration { get; set; } + + /// + /// Gets or sets the DurationTime. + /// + [JsonPropertyName("duration_time")] + public string? DurationTime { get; set; } + + /// + /// Gets or sets the PktPos. + /// + [JsonPropertyName("pkt_pos")] + public string? PktPos { get; set; } + + /// + /// Gets or sets the PktSize. + /// + [JsonPropertyName("pkt_size")] + public string? PktSize { get; set; } + + /// + /// Gets or sets the Width. + /// + [JsonPropertyName("width")] + public int? Width { get; set; } + + /// + /// Gets or sets the Height. + /// + [JsonPropertyName("height")] + public int? Height { get; set; } + + /// + /// Gets or sets the CropTop. + /// + [JsonPropertyName("crop_top")] + public int? CropTop { get; set; } + + /// + /// Gets or sets the CropBottom. + /// + [JsonPropertyName("crop_bottom")] + public int? CropBottom { get; set; } + + /// + /// Gets or sets the CropLeft. + /// + [JsonPropertyName("crop_left")] + public int? CropLeft { get; set; } + + /// + /// Gets or sets the CropRight. + /// + [JsonPropertyName("crop_right")] + public int? CropRight { get; set; } + + /// + /// Gets or sets the PixFmt. + /// + [JsonPropertyName("pix_fmt")] + public string? PixFmt { get; set; } + + /// + /// Gets or sets the SampleAspectRatio. + /// + [JsonPropertyName("sample_aspect_ratio")] + public string? SampleAspectRatio { get; set; } + + /// + /// Gets or sets the PictType. + /// + [JsonPropertyName("pict_type")] + public string? PictType { get; set; } + + /// + /// Gets or sets the InterlacedFrame. + /// + [JsonPropertyName("interlaced_frame")] + public int? InterlacedFrame { get; set; } + + /// + /// Gets or sets the TopFieldFirst. + /// + [JsonPropertyName("top_field_first")] + public int? TopFieldFirst { get; set; } + + /// + /// Gets or sets the RepeatPict. + /// + [JsonPropertyName("repeat_pict")] + public int? RepeatPict { get; set; } + + /// + /// Gets or sets the ColorRange. + /// + [JsonPropertyName("color_range")] + public string? ColorRange { get; set; } + + /// + /// Gets or sets the ColorSpace. + /// + [JsonPropertyName("color_space")] + public string? ColorSpace { get; set; } + + /// + /// Gets or sets the ColorPrimaries. + /// + [JsonPropertyName("color_primaries")] + public string? ColorPrimaries { get; set; } + + /// + /// Gets or sets the ColorTransfer. + /// + [JsonPropertyName("color_transfer")] + public string? ColorTransfer { get; set; } + + /// + /// Gets or sets the ChromaLocation. + /// + [JsonPropertyName("chroma_location")] + public string? ChromaLocation { get; set; } + + /// + /// Gets or sets the SideDataList. + /// + [JsonPropertyName("side_data_list")] + public IReadOnlyList? SideDataList { get; set; } +} diff --git a/MediaBrowser.MediaEncoding/Probing/MediaFrameSideDataInfo.cs b/MediaBrowser.MediaEncoding/Probing/MediaFrameSideDataInfo.cs new file mode 100644 index 000000000..3f7dd9a69 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Probing/MediaFrameSideDataInfo.cs @@ -0,0 +1,16 @@ +using System.Text.Json.Serialization; + +namespace MediaBrowser.MediaEncoding.Probing; + +/// +/// Class MediaFrameSideDataInfo. +/// Currently only records the SideDataType for HDR10+ detection. +/// +public class MediaFrameSideDataInfo +{ + /// + /// Gets or sets the SideDataType. + /// + [JsonPropertyName("side_data_type")] + public string? SideDataType { get; set; } +} diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 6b0fd9a14..a98dbe597 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -105,8 +105,9 @@ namespace MediaBrowser.MediaEncoding.Probing SetSize(data, info); var internalStreams = data.Streams ?? Array.Empty(); + var internalFrames = data.Frames ?? Array.Empty(); - info.MediaStreams = internalStreams.Select(s => GetMediaStream(isAudio, s, data.Format)) + info.MediaStreams = internalStreams.Select(s => GetMediaStream(isAudio, s, data.Format, internalFrames)) .Where(i => i is not null) // Drop subtitle streams if we don't know the codec because it will just cause failures if we don't know how to handle them .Where(i => i.Type != MediaStreamType.Subtitle || !string.IsNullOrWhiteSpace(i.Codec)) @@ -685,8 +686,9 @@ namespace MediaBrowser.MediaEncoding.Probing /// if set to true [is info]. /// The stream info. /// The format info. + /// The frame info. /// MediaStream. - private MediaStream GetMediaStream(bool isAudio, MediaStreamInfo streamInfo, MediaFormatInfo formatInfo) + private MediaStream GetMediaStream(bool isAudio, MediaStreamInfo streamInfo, MediaFormatInfo formatInfo, IReadOnlyList frameInfoList) { // These are mp4 chapters if (string.Equals(streamInfo.CodecName, "mov_text", StringComparison.OrdinalIgnoreCase)) @@ -904,6 +906,15 @@ namespace MediaBrowser.MediaEncoding.Probing } } } + + var frameInfo = frameInfoList?.FirstOrDefault(i => i.StreamIndex == stream.Index); + if (frameInfo?.SideDataList != null) + { + if (frameInfo.SideDataList.Any(data => string.Equals(data.SideDataType, "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)", StringComparison.OrdinalIgnoreCase))) + { + stream.Hdr10PlusPresentFlag = true; + } + } } else if (streamInfo.CodecType == CodecType.Data) { diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs index 09b966367..1b61bfe15 100644 --- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs +++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs @@ -345,6 +345,15 @@ namespace MediaBrowser.Model.Dlna return !condition.IsRequired; } + // Special case: HDR10 also satisfies if the video is HDR10Plus + if (currentValue.Value == VideoRangeType.HDR10Plus) + { + if (IsConditionSatisfied(condition, VideoRangeType.HDR10)) + { + return true; + } + } + var conditionType = condition.Condition; if (conditionType == ProfileConditionType.EqualsAny) { diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index d89386c1c..13acd15a3 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Globalization; using System.Linq; using System.Text; diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index dae3d84ae..95b5b43f8 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -153,6 +153,8 @@ namespace MediaBrowser.Model.Entities /// The title. public string Title { get; set; } + public bool? Hdr10PlusPresentFlag { get; set; } + /// /// Gets the video range. /// @@ -172,6 +174,7 @@ namespace MediaBrowser.Model.Entities /// Gets the video range type. /// /// The video range type. + [DefaultValue(VideoRangeType.Unknown)] public VideoRangeType VideoRangeType { get @@ -779,8 +782,8 @@ namespace MediaBrowser.Model.Entities var blPresentFlag = BlPresentFlag == 1; var dvBlCompatId = DvBlSignalCompatibilityId; - var isDoViProfile = dvProfile == 5 || dvProfile == 7 || dvProfile == 8 || dvProfile == 10; - var isDoViFlag = rpuPresentFlag && blPresentFlag && (dvBlCompatId == 0 || dvBlCompatId == 1 || dvBlCompatId == 4 || dvBlCompatId == 2 || dvBlCompatId == 6); + var isDoViProfile = dvProfile is 5 or 7 or 8 or 10; + var isDoViFlag = rpuPresentFlag && blPresentFlag && dvBlCompatId is 0 or 1 or 4 or 2 or 6; if ((isDoViProfile && isDoViFlag) || string.Equals(codecTag, "dovi", StringComparison.OrdinalIgnoreCase) @@ -788,7 +791,7 @@ namespace MediaBrowser.Model.Entities || string.Equals(codecTag, "dvhe", StringComparison.OrdinalIgnoreCase) || string.Equals(codecTag, "dav1", StringComparison.OrdinalIgnoreCase)) { - return dvProfile switch + var dvRangeSet = dvProfile switch { 5 => (VideoRange.HDR, VideoRangeType.DOVI), 8 => dvBlCompatId switch @@ -796,32 +799,40 @@ namespace MediaBrowser.Model.Entities 1 => (VideoRange.HDR, VideoRangeType.DOVIWithHDR10), 4 => (VideoRange.HDR, VideoRangeType.DOVIWithHLG), 2 => (VideoRange.SDR, VideoRangeType.DOVIWithSDR), - // While not in Dolby Spec, Profile 8 CCid 6 media are possible to create, and since CCid 6 stems from Bluray (Profile 7 originally) an HDR10 base layer is guaranteed to exist. - 6 => (VideoRange.HDR, VideoRangeType.DOVIWithHDR10), - // There is no other case to handle here as per Dolby Spec. Default case included for completeness and linting purposes - _ => (VideoRange.SDR, VideoRangeType.SDR) + // Out of Dolby Spec files should be marked as invalid + _ => (VideoRange.HDR, VideoRangeType.DOVIInvalid) }, - 7 => (VideoRange.HDR, VideoRangeType.HDR10), + 7 => (VideoRange.HDR, VideoRangeType.DOVIWithEL), 10 => dvBlCompatId switch { 0 => (VideoRange.HDR, VideoRangeType.DOVI), 1 => (VideoRange.HDR, VideoRangeType.DOVIWithHDR10), 2 => (VideoRange.SDR, VideoRangeType.DOVIWithSDR), 4 => (VideoRange.HDR, VideoRangeType.DOVIWithHLG), - // While not in Dolby Spec, Profile 8 CCid 6 media are possible to create, and since CCid 6 stems from Bluray (Profile 7 originally) an HDR10 base layer is guaranteed to exist. - 6 => (VideoRange.HDR, VideoRangeType.DOVIWithHDR10), - // There is no other case to handle here as per Dolby Spec. Default case included for completeness and linting purposes - _ => (VideoRange.SDR, VideoRangeType.SDR) + // Out of Dolby Spec files should be marked as invalid + _ => (VideoRange.HDR, VideoRangeType.DOVIInvalid) }, _ => (VideoRange.SDR, VideoRangeType.SDR) }; + + if (Hdr10PlusPresentFlag == true) + { + return dvRangeSet.Item2 switch + { + VideoRangeType.DOVIWithHDR10 => (VideoRange.HDR, VideoRangeType.DOVIWithHDR10Plus), + VideoRangeType.DOVIWithEL => (VideoRange.HDR, VideoRangeType.DOVIWithELHDR10Plus), + _ => dvRangeSet + }; + } + + return dvRangeSet; } var colorTransfer = ColorTransfer; if (string.Equals(colorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)) { - return (VideoRange.HDR, VideoRangeType.HDR10); + return Hdr10PlusPresentFlag == true ? (VideoRange.HDR, VideoRangeType.HDR10Plus) : (VideoRange.HDR, VideoRangeType.HDR10); } else if (string.Equals(colorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs index 207317376..b80b764ba 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs @@ -99,4 +99,6 @@ public class MediaStreamInfo public int? Rotation { get; set; } public string? KeyFrames { get; set; } + + public bool? Hdr10PlusPresentFlag { get; set; } } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250327171413_AddHdr10PlusFlag.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250327171413_AddHdr10PlusFlag.Designer.cs new file mode 100644 index 000000000..bad01778d --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250327171413_AddHdr10PlusFlag.Designer.cs @@ -0,0 +1,1655 @@ +// +using System; +using Jellyfin.Database.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20250327171413_AddHdr10PlusFlag")] + partial class AddHdr10PlusFlag + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "9.0.3"); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AncestorId", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ParentItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AttachmentStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("Filename") + .HasColumnType("TEXT"); + + b.Property("MimeType") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Album") + .HasColumnType("TEXT"); + + b.Property("AlbumArtists") + .HasColumnType("TEXT"); + + b.Property("Artists") + .HasColumnType("TEXT"); + + b.Property("Audio") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("TEXT"); + + b.Property("CleanName") + .HasColumnType("TEXT"); + + b.Property("CommunityRating") + .HasColumnType("REAL"); + + b.Property("CriticRating") + .HasColumnType("REAL"); + + b.Property("CustomRating") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastMediaAdded") + .HasColumnType("TEXT"); + + b.Property("DateLastRefreshed") + .HasColumnType("TEXT"); + + b.Property("DateLastSaved") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EpisodeTitle") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasColumnType("TEXT"); + + b.Property("ExternalSeriesId") + .HasColumnType("TEXT"); + + b.Property("ExternalServiceId") + .HasColumnType("TEXT"); + + b.Property("ExtraIds") + .HasColumnType("TEXT"); + + b.Property("ExtraType") + .HasColumnType("INTEGER"); + + b.Property("ForcedSortName") + .HasColumnType("TEXT"); + + b.Property("Genres") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IndexNumber") + .HasColumnType("INTEGER"); + + b.Property("InheritedParentalRatingValue") + .HasColumnType("INTEGER"); + + b.Property("IsFolder") + .HasColumnType("INTEGER"); + + b.Property("IsInMixedFolder") + .HasColumnType("INTEGER"); + + b.Property("IsLocked") + .HasColumnType("INTEGER"); + + b.Property("IsMovie") + .HasColumnType("INTEGER"); + + b.Property("IsRepeat") + .HasColumnType("INTEGER"); + + b.Property("IsSeries") + .HasColumnType("INTEGER"); + + b.Property("IsVirtualItem") + .HasColumnType("INTEGER"); + + b.Property("LUFS") + .HasColumnType("REAL"); + + b.Property("MediaType") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizationGain") + .HasColumnType("REAL"); + + b.Property("OfficialRating") + .HasColumnType("TEXT"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("ParentIndexNumber") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataCountryCode") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataLanguage") + .HasColumnType("TEXT"); + + b.Property("PremiereDate") + .HasColumnType("TEXT"); + + b.Property("PresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("PrimaryVersionId") + .HasColumnType("TEXT"); + + b.Property("ProductionLocations") + .HasColumnType("TEXT"); + + b.Property("ProductionYear") + .HasColumnType("INTEGER"); + + b.Property("RunTimeTicks") + .HasColumnType("INTEGER"); + + b.Property("SeasonId") + .HasColumnType("TEXT"); + + b.Property("SeasonName") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("TEXT"); + + b.Property("SeriesName") + .HasColumnType("TEXT"); + + b.Property("SeriesPresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("ShowId") + .HasColumnType("TEXT"); + + b.Property("Size") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("Studios") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Tags") + .HasColumnType("TEXT"); + + b.Property("TopParentId") + .HasColumnType("TEXT"); + + b.Property("TotalBitrate") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnratedType") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Blurhash") + .HasColumnType("BLOB"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("ImageType") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemMetadataField", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemProvider", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("ProviderValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemTrailerType", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Chapter", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ChapterIndex") + .HasColumnType("INTEGER"); + + b.Property("ImageDateModified") + .HasColumnType("TEXT"); + + b.Property("ImagePath") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("StartPositionTicks") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValue", b => + { + b.Property("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CleanValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue") + .IsUnique(); + + b.ToTable("ItemValues"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValueMap", b => + { + b.Property("ItemValueId") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EndTicks") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartTicks") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("StreamIndex") + .HasColumnType("INTEGER"); + + b.Property("AspectRatio") + .HasColumnType("TEXT"); + + b.Property("AverageFrameRate") + .HasColumnType("REAL"); + + b.Property("BitDepth") + .HasColumnType("INTEGER"); + + b.Property("BitRate") + .HasColumnType("INTEGER"); + + b.Property("BlPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("ChannelLayout") + .HasColumnType("TEXT"); + + b.Property("Channels") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("CodecTimeBase") + .HasColumnType("TEXT"); + + b.Property("ColorPrimaries") + .HasColumnType("TEXT"); + + b.Property("ColorSpace") + .HasColumnType("TEXT"); + + b.Property("ColorTransfer") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("DvBlSignalCompatibilityId") + .HasColumnType("INTEGER"); + + b.Property("DvLevel") + .HasColumnType("INTEGER"); + + b.Property("DvProfile") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMajor") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMinor") + .HasColumnType("INTEGER"); + + b.Property("ElPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("Hdr10PlusPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IsAnamorphic") + .HasColumnType("INTEGER"); + + b.Property("IsAvc") + .HasColumnType("INTEGER"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("IsExternal") + .HasColumnType("INTEGER"); + + b.Property("IsForced") + .HasColumnType("INTEGER"); + + b.Property("IsHearingImpaired") + .HasColumnType("INTEGER"); + + b.Property("IsInterlaced") + .HasColumnType("INTEGER"); + + b.Property("KeyFrames") + .HasColumnType("TEXT"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("REAL"); + + b.Property("NalLengthSize") + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PixelFormat") + .HasColumnType("TEXT"); + + b.Property("Profile") + .HasColumnType("TEXT"); + + b.Property("RealFrameRate") + .HasColumnType("REAL"); + + b.Property("RefFrames") + .HasColumnType("INTEGER"); + + b.Property("Rotation") + .HasColumnType("INTEGER"); + + b.Property("RpuPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("SampleRate") + .HasColumnType("INTEGER"); + + b.Property("StreamType") + .HasColumnType("INTEGER"); + + b.Property("TimeBase") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PersonType") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.PeopleBaseItemMap", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("PeopleId") + .HasColumnType("TEXT"); + + b.Property("ListOrder") + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.UserData", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("CustomDataKey") + .HasColumnType("TEXT"); + + b.Property("AudioStreamIndex") + .HasColumnType("INTEGER"); + + b.Property("IsFavorite") + .HasColumnType("INTEGER"); + + b.Property("LastPlayedDate") + .HasColumnType("TEXT"); + + b.Property("Likes") + .HasColumnType("INTEGER"); + + b.Property("PlayCount") + .HasColumnType("INTEGER"); + + b.Property("PlaybackPositionTicks") + .HasColumnType("INTEGER"); + + b.Property("Played") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("REAL"); + + b.Property("SubtitleStreamIndex") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "UserId", "CustomDataKey"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Children") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "ParentItem") + .WithMany("ParentAncestors") + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Database.Implementations.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Permission", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Preference", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.UserData", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => + { + b.Navigation("Chapters"); + + b.Navigation("Children"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("ParentAncestors"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250327171413_AddHdr10PlusFlag.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250327171413_AddHdr10PlusFlag.cs new file mode 100644 index 000000000..5766cd382 --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250327171413_AddHdr10PlusFlag.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class AddHdr10PlusFlag : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Hdr10PlusPresentFlag", + table: "MediaStreamInfos", + type: "INTEGER", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Hdr10PlusPresentFlag", + table: "MediaStreamInfos"); + } + } +} diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs index 8b2b26934..adc15684f 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs @@ -845,6 +845,9 @@ namespace Jellyfin.Server.Implementations.Migrations b.Property("ElPresentFlag") .HasColumnType("INTEGER"); + b.Property("Hdr10PlusPresentFlag") + .HasColumnType("INTEGER"); + b.Property("Height") .HasColumnType("INTEGER"); -- cgit v1.2.3 From 596b63551196f7ce9bcb8d8de617d3c79201a375 Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Thu, 3 Apr 2025 17:17:14 +0200 Subject: Cleanup extracted files (#13760) * Cleanup extracted files * Pagination and fixes * Add migration for attachments to MigrateLibraryDb * Unify attachment handling * Don't extract again if files were already extracted * Fix MKS attachment extraction * Always run full extraction on mks * Don't try to extract mjpeg streams as attachments * Fallback to check if attachments were extracted to cache folder * Fixup --- .../Data/CleanDatabaseScheduledTask.cs | 41 +- .../Library/LibraryManager.cs | 17 + Emby.Server.Implementations/Library/PathManager.cs | 40 +- Jellyfin.Server/Migrations/MigrationRunner.cs | 1 + .../Migrations/Routines/MigrateLibraryDb.cs | 66 + .../Migrations/Routines/MoveExtractedFiles.cs | 299 ++++ MediaBrowser.Controller/IO/IPathManager.cs | 32 + .../MediaEncoding/EncodingHelper.cs | 8 +- .../MediaEncoding/IAttachmentExtractor.cs | 47 +- .../Attachments/AttachmentExtractor.cs | 418 ++--- .../Subtitles/SubtitleEncoder.cs | 33 +- .../Transcoding/TranscodeManager.cs | 11 +- MediaBrowser.Model/Entities/MediaAttachment.cs | 80 +- .../Entities/AttachmentStreamInfo.cs | 2 +- ...250331182844_FixAttachmentMigration.Designer.cs | 1657 ++++++++++++++++++++ .../20250331182844_FixAttachmentMigration.cs | 36 + .../Migrations/JellyfinDbModelSnapshot.cs | 1 - 17 files changed, 2385 insertions(+), 404 deletions(-) create mode 100644 Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.Designer.cs create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.cs (limited to 'MediaBrowser.MediaEncoding') diff --git a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs index 63481b1f8..9a80eafe5 100644 --- a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs +++ b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs @@ -1,14 +1,14 @@ #pragma warning disable CS1591 using System; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Database.Implementations; -using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Trickplay; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -19,15 +19,18 @@ public class CleanDatabaseScheduledTask : ILibraryPostScanTask private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; private readonly IDbContextFactory _dbProvider; + private readonly IPathManager _pathManager; public CleanDatabaseScheduledTask( ILibraryManager libraryManager, ILogger logger, - IDbContextFactory dbProvider) + IDbContextFactory dbProvider, + IPathManager pathManager) { _libraryManager = libraryManager; _logger = logger; _dbProvider = dbProvider; + _pathManager = pathManager; } public async Task Run(IProgress progress, CancellationToken cancellationToken) @@ -56,6 +59,38 @@ public class CleanDatabaseScheduledTask : ILibraryPostScanTask { _logger.LogInformation("Cleaning item {Item} type: {Type} path: {Path}", item.Name, item.GetType().Name, item.Path ?? string.Empty); + foreach (var mediaSource in item.GetMediaSources(false)) + { + // Delete extracted subtitles + try + { + var subtitleFolder = _pathManager.GetSubtitleFolderPath(mediaSource.Id); + if (Directory.Exists(subtitleFolder)) + { + Directory.Delete(subtitleFolder, true); + } + } + catch (Exception e) + { + _logger.LogWarning("Failed to remove subtitle cache folder for {Item}: {Exception}", item.Id, e.Message); + } + + // Delete extracted attachments + try + { + var attachmentFolder = _pathManager.GetAttachmentFolderPath(mediaSource.Id); + if (Directory.Exists(attachmentFolder)) + { + Directory.Delete(attachmentFolder, true); + } + } + catch (Exception e) + { + _logger.LogWarning("Failed to remove attachment cache folder for {Item}: {Exception}", item.Id, e.Message); + } + } + + // Delete item _libraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index ab8884f17..1303bb3cb 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -492,7 +492,24 @@ namespace Emby.Server.Implementations.Library if (item is Video video) { + // Trickplay list.Add(_pathManager.GetTrickplayDirectory(video)); + + // Subtitles and attachments + foreach (var mediaSource in item.GetMediaSources(false)) + { + var subtitleFolder = _pathManager.GetSubtitleFolderPath(mediaSource.Id); + if (subtitleFolder is not null) + { + list.Add(subtitleFolder); + } + + var attachmentFolder = _pathManager.GetAttachmentFolderPath(mediaSource.Id); + if (attachmentFolder is not null) + { + list.Add(attachmentFolder); + } + } } return list; diff --git a/Emby.Server.Implementations/Library/PathManager.cs b/Emby.Server.Implementations/Library/PathManager.cs index c910abadb..ac004b413 100644 --- a/Emby.Server.Implementations/Library/PathManager.cs +++ b/Emby.Server.Implementations/Library/PathManager.cs @@ -1,5 +1,7 @@ +using System; using System.Globalization; using System.IO; +using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; @@ -12,22 +14,56 @@ namespace Emby.Server.Implementations.Library; public class PathManager : IPathManager { private readonly IServerConfigurationManager _config; + private readonly IApplicationPaths _appPaths; /// /// Initializes a new instance of the class. /// /// The server configuration manager. + /// The application paths. public PathManager( - IServerConfigurationManager config) + IServerConfigurationManager config, + IApplicationPaths appPaths) { _config = config; + _appPaths = appPaths; + } + + private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles"); + + private string AttachmentCachePath => Path.Combine(_appPaths.DataPath, "attachments"); + + /// + public string GetAttachmentPath(string mediaSourceId, string fileName) + { + return Path.Join(GetAttachmentFolderPath(mediaSourceId), fileName); + } + + /// + public string GetAttachmentFolderPath(string mediaSourceId) + { + var id = Guid.Parse(mediaSourceId); + return Path.Join(AttachmentCachePath, id.ToString("D", CultureInfo.InvariantCulture)); + } + + /// + public string GetSubtitleFolderPath(string mediaSourceId) + { + var id = Guid.Parse(mediaSourceId); + return Path.Join(SubtitleCachePath, id.ToString("D", CultureInfo.InvariantCulture)); + } + + /// + public string GetSubtitlePath(string mediaSourceId, int streamIndex, string extension) + { + return Path.Join(GetSubtitleFolderPath(mediaSourceId), streamIndex.ToString(CultureInfo.InvariantCulture) + extension); } /// public string GetTrickplayDirectory(BaseItem item, bool saveWithMedia = false) { var basePath = _config.ApplicationPaths.TrickplayPath; - var idString = item.Id.ToString("N", CultureInfo.InvariantCulture); + var idString = item.Id.ToString("D", CultureInfo.InvariantCulture); return saveWithMedia ? Path.Combine(item.ContainingFolderPath, Path.ChangeExtension(item.Path, ".trickplay")) diff --git a/Jellyfin.Server/Migrations/MigrationRunner.cs b/Jellyfin.Server/Migrations/MigrationRunner.cs index baeea2c14..c3a2e1bc4 100644 --- a/Jellyfin.Server/Migrations/MigrationRunner.cs +++ b/Jellyfin.Server/Migrations/MigrationRunner.cs @@ -54,6 +54,7 @@ namespace Jellyfin.Server.Migrations typeof(Routines.FixAudioData), typeof(Routines.RemoveDuplicatePlaylistChildren), typeof(Routines.MigrateLibraryDb), + typeof(Routines.MoveExtractedFiles), typeof(Routines.MigrateRatingLevels), typeof(Routines.MoveTrickplayFiles), typeof(Routines.MigrateKeyframeData), diff --git a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs index f414b6e39..3fc9bea84 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs @@ -80,6 +80,7 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine using (var operation = GetPreparedDbContext("Cleanup database")) { + operation.JellyfinDbContext.AttachmentStreamInfos.ExecuteDelete(); operation.JellyfinDbContext.BaseItems.ExecuteDelete(); operation.JellyfinDbContext.ItemValues.ExecuteDelete(); operation.JellyfinDbContext.UserData.ExecuteDelete(); @@ -251,6 +252,29 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine } } + using (var operation = GetPreparedDbContext("moving AttachmentStreamInfos")) + { + const string mediaAttachmentQuery = + """ + SELECT ItemId, AttachmentIndex, Codec, CodecTag, Comment, filename, MIMEType + FROM mediaattachments + WHERE EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = mediaattachments.ItemId) + """; + + using (new TrackedMigrationStep("loading AttachmentStreamInfos", _logger)) + { + foreach (SqliteDataReader dto in connection.Query(mediaAttachmentQuery)) + { + operation.JellyfinDbContext.AttachmentStreamInfos.Add(GetMediaAttachment(dto)); + } + } + + using (new TrackedMigrationStep($"saving {operation.JellyfinDbContext.AttachmentStreamInfos.Local.Count} AttachmentStreamInfos entries", _logger)) + { + operation.JellyfinDbContext.SaveChanges(); + } + } + using (var operation = GetPreparedDbContext("moving People")) { const string personsQuery = @@ -709,6 +733,48 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine return item; } + /// + /// Gets the attachment. + /// + /// The reader. + /// MediaAttachment. + private AttachmentStreamInfo GetMediaAttachment(SqliteDataReader reader) + { + var item = new AttachmentStreamInfo + { + Index = reader.GetInt32(1), + Item = null!, + ItemId = reader.GetGuid(0), + }; + + if (reader.TryGetString(2, out var codec)) + { + item.Codec = codec; + } + + if (reader.TryGetString(3, out var codecTag)) + { + item.CodecTag = codecTag; + } + + if (reader.TryGetString(4, out var comment)) + { + item.Comment = comment; + } + + if (reader.TryGetString(5, out var fileName)) + { + item.Filename = fileName; + } + + if (reader.TryGetString(6, out var mimeType)) + { + item.MimeType = mimeType; + } + + return item; + } + private (BaseItemEntity BaseItem, string[] LegacyUserDataKey) GetItem(SqliteDataReader reader) { var entity = new BaseItemEntity() diff --git a/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs b/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs new file mode 100644 index 000000000..f63c5fd40 --- /dev/null +++ b/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs @@ -0,0 +1,299 @@ +#pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms + +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using Jellyfin.Data.Enums; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.MediaInfo; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Migrations.Routines; + +/// +/// Migration to move extracted files to the new directories. +/// +public class MoveExtractedFiles : IDatabaseMigrationRoutine +{ + private readonly IApplicationPaths _appPaths; + private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; + private readonly IMediaSourceManager _mediaSourceManager; + private readonly IPathManager _pathManager; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// The logger. + /// Instance of the interface. + /// Instance of the interface. + public MoveExtractedFiles( + IApplicationPaths appPaths, + ILibraryManager libraryManager, + ILogger logger, + IMediaSourceManager mediaSourceManager, + IPathManager pathManager) + { + _appPaths = appPaths; + _libraryManager = libraryManager; + _logger = logger; + _mediaSourceManager = mediaSourceManager; + _pathManager = pathManager; + } + + private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles"); + + private string AttachmentCachePath => Path.Combine(_appPaths.DataPath, "attachments"); + + /// + public Guid Id => new("9063b0Ef-CFF1-4EDC-9A13-74093681A89B"); + + /// + public string Name => "MoveExtractedFiles"; + + /// + public bool PerformOnNewInstall => false; + + /// + public void Perform() + { + const int Limit = 500; + int itemCount = 0, offset = 0; + + var sw = Stopwatch.StartNew(); + var itemsQuery = new InternalItemsQuery + { + MediaTypes = [MediaType.Video], + SourceTypes = [SourceType.Library], + IsVirtualItem = false, + IsFolder = false, + Limit = Limit, + StartIndex = offset, + EnableTotalRecordCount = true, + }; + + var records = _libraryManager.GetItemsResult(itemsQuery).TotalRecordCount; + _logger.LogInformation("Checking {Count} items for movable extracted files.", records); + + // Make sure directories exist + Directory.CreateDirectory(SubtitleCachePath); + Directory.CreateDirectory(AttachmentCachePath); + + itemsQuery.EnableTotalRecordCount = false; + do + { + itemsQuery.StartIndex = offset; + var result = _libraryManager.GetItemsResult(itemsQuery); + + var items = result.Items; + foreach (var item in items) + { + if (MoveSubtitleAndAttachmentFiles(item)) + { + itemCount++; + } + } + + offset += Limit; + if (offset % 5_000 == 0) + { + _logger.LogInformation("Checked extracted files for {Count} items in {Time}.", offset, sw.Elapsed); + } + } while (offset < records); + + _logger.LogInformation("Checked {Checked} items - Moved files for {Items} items in {Time}.", records, itemCount, sw.Elapsed); + + // Get all subdirectories with 1 character names (those are the legacy directories) + var subdirectories = Directory.GetDirectories(SubtitleCachePath, "*", SearchOption.AllDirectories).Where(s => s.Length == SubtitleCachePath.Length + 2).ToList(); + subdirectories.AddRange(Directory.GetDirectories(AttachmentCachePath, "*", SearchOption.AllDirectories).Where(s => s.Length == AttachmentCachePath.Length + 2)); + + // Remove all legacy subdirectories + foreach (var subdir in subdirectories) + { + Directory.Delete(subdir, true); + } + + // Remove old cache path + var attachmentCachePath = Path.Join(_appPaths.CachePath, "attachments"); + if (Directory.Exists(attachmentCachePath)) + { + Directory.Delete(attachmentCachePath, true); + } + + _logger.LogInformation("Cleaned up left over subtitles and attachments."); + } + + private bool MoveSubtitleAndAttachmentFiles(BaseItem item) + { + var mediaStreams = item.GetMediaStreams().Where(s => s.Type == MediaStreamType.Subtitle && !s.IsExternal); + var itemIdString = item.Id.ToString("N", CultureInfo.InvariantCulture); + var modified = false; + foreach (var mediaStream in mediaStreams) + { + if (mediaStream.Codec is null) + { + continue; + } + + var mediaStreamIndex = mediaStream.Index; + var extension = GetSubtitleExtension(mediaStream.Codec); + var oldSubtitleCachePath = GetOldSubtitleCachePath(item.Path, mediaStream.Index, extension); + if (string.IsNullOrEmpty(oldSubtitleCachePath) || !File.Exists(oldSubtitleCachePath)) + { + continue; + } + + var newSubtitleCachePath = _pathManager.GetSubtitlePath(itemIdString, mediaStreamIndex, extension); + if (File.Exists(newSubtitleCachePath)) + { + File.Delete(oldSubtitleCachePath); + } + else + { + var newDirectory = Path.GetDirectoryName(newSubtitleCachePath); + if (newDirectory is not null) + { + Directory.CreateDirectory(newDirectory); + File.Move(oldSubtitleCachePath, newSubtitleCachePath, false); + _logger.LogDebug("Moved subtitle {Index} for {Item} from {Source} to {Destination}", mediaStreamIndex, item.Id, oldSubtitleCachePath, newSubtitleCachePath); + + modified = true; + } + } + } + + var attachments = _mediaSourceManager.GetMediaAttachments(item.Id).Where(a => !string.Equals(a.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)).ToList(); + var shouldExtractOneByOne = attachments.Any(a => !string.IsNullOrEmpty(a.FileName) + && (a.FileName.Contains('/', StringComparison.OrdinalIgnoreCase) || a.FileName.Contains('\\', StringComparison.OrdinalIgnoreCase))); + foreach (var attachment in attachments) + { + var attachmentIndex = attachment.Index; + var oldAttachmentPath = GetOldAttachmentDataPath(item.Path, attachmentIndex); + if (string.IsNullOrEmpty(oldAttachmentPath) || !File.Exists(oldAttachmentPath)) + { + oldAttachmentPath = GetOldAttachmentCachePath(itemIdString, attachment, shouldExtractOneByOne); + if (string.IsNullOrEmpty(oldAttachmentPath) || !File.Exists(oldAttachmentPath)) + { + continue; + } + } + + var newAttachmentPath = _pathManager.GetAttachmentPath(itemIdString, attachment.FileName ?? attachmentIndex.ToString(CultureInfo.InvariantCulture)); + if (File.Exists(newAttachmentPath)) + { + File.Delete(oldAttachmentPath); + } + else + { + var newDirectory = Path.GetDirectoryName(newAttachmentPath); + if (newDirectory is not null) + { + Directory.CreateDirectory(newDirectory); + File.Move(oldAttachmentPath, newAttachmentPath, false); + _logger.LogDebug("Moved attachment {Index} for {Item} from {Source} to {Destination}", attachmentIndex, item.Id, oldAttachmentPath, newAttachmentPath); + + modified = true; + } + } + } + + return modified; + } + + private string? GetOldAttachmentDataPath(string? mediaPath, int attachmentStreamIndex) + { + if (mediaPath is null) + { + return null; + } + + string filename; + var protocol = _mediaSourceManager.GetPathProtocol(mediaPath); + if (protocol == MediaProtocol.File) + { + DateTime? date; + try + { + date = File.GetLastWriteTimeUtc(mediaPath); + } + catch (IOException e) + { + _logger.LogDebug("Skipping attachment at index {Index} for {Path}: {Exception}", attachmentStreamIndex, mediaPath, e.Message); + + return null; + } + + filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Value.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture); + } + else + { + filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture); + } + + return Path.Join(_appPaths.DataPath, "attachments", filename[..1], filename); + } + + private string? GetOldAttachmentCachePath(string mediaSourceId, MediaAttachment attachment, bool shouldExtractOneByOne) + { + var attachmentFolderPath = Path.Join(_appPaths.CachePath, "attachments", mediaSourceId); + if (shouldExtractOneByOne) + { + return Path.Join(attachmentFolderPath, attachment.Index.ToString(CultureInfo.InvariantCulture)); + } + + if (string.IsNullOrEmpty(attachment.FileName)) + { + return null; + } + + return Path.Join(attachmentFolderPath, attachment.FileName); + } + + private string? GetOldSubtitleCachePath(string path, int streamIndex, string outputSubtitleExtension) + { + DateTime? date; + try + { + date = File.GetLastWriteTimeUtc(path); + } + catch (IOException e) + { + _logger.LogDebug("Skipping subtitle at index {Index} for {Path}: {Exception}", streamIndex, path, e.Message); + + return null; + } + + var ticksParam = string.Empty; + ReadOnlySpan filename = new Guid(MD5.HashData(Encoding.Unicode.GetBytes(path + "_" + streamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Value.Ticks.ToString(CultureInfo.InvariantCulture) + ticksParam))) + outputSubtitleExtension; + + return Path.Join(SubtitleCachePath, filename[..1], filename); + } + + private static string GetSubtitleExtension(string codec) + { + if (codec.ToLower(CultureInfo.InvariantCulture).Equals("ass", StringComparison.OrdinalIgnoreCase) + || codec.ToLower(CultureInfo.InvariantCulture).Equals("ssa", StringComparison.OrdinalIgnoreCase)) + { + return "." + codec; + } + else if (codec.Contains("pgs", StringComparison.OrdinalIgnoreCase)) + { + return ".sup"; + } + else + { + return ".srt"; + } + } +} diff --git a/MediaBrowser.Controller/IO/IPathManager.cs b/MediaBrowser.Controller/IO/IPathManager.cs index 036889810..7c20164a6 100644 --- a/MediaBrowser.Controller/IO/IPathManager.cs +++ b/MediaBrowser.Controller/IO/IPathManager.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Dto; namespace MediaBrowser.Controller.IO; @@ -14,4 +15,35 @@ public interface IPathManager /// Whether or not the tile should be saved next to the media file. /// The absolute path. public string GetTrickplayDirectory(BaseItem item, bool saveWithMedia = false); + + /// + /// Gets the path to the subtitle file. + /// + /// The media source id. + /// The stream index. + /// The subtitle file extension. + /// The absolute path. + public string GetSubtitlePath(string mediaSourceId, int streamIndex, string extension); + + /// + /// Gets the path to the subtitle file. + /// + /// The media source id. + /// The absolute path. + public string GetSubtitleFolderPath(string mediaSourceId); + + /// + /// Gets the path to the attachment file. + /// + /// The media source id. + /// The attachmentFileName index. + /// The absolute path. + public string GetAttachmentPath(string mediaSourceId, string fileName); + + /// + /// Gets the path to the attachment folder. + /// + /// The media source id. + /// The absolute path. + public string GetAttachmentFolderPath(string mediaSourceId); } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index afa962a41..75b3f151d 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -19,6 +19,7 @@ using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Extensions; +using MediaBrowser.Controller.IO; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; @@ -55,6 +56,7 @@ namespace MediaBrowser.Controller.MediaEncoding private readonly ISubtitleEncoder _subtitleEncoder; private readonly IConfiguration _config; private readonly IConfigurationManager _configurationManager; + private readonly IPathManager _pathManager; // i915 hang was fixed by linux 6.2 (3f882f2) private readonly Version _minKerneli915Hang = new Version(5, 18); @@ -153,13 +155,15 @@ namespace MediaBrowser.Controller.MediaEncoding IMediaEncoder mediaEncoder, ISubtitleEncoder subtitleEncoder, IConfiguration config, - IConfigurationManager configurationManager) + IConfigurationManager configurationManager, + IPathManager pathManager) { _appPaths = appPaths; _mediaEncoder = mediaEncoder; _subtitleEncoder = subtitleEncoder; _config = config; _configurationManager = configurationManager; + _pathManager = pathManager; } private enum DynamicHdrMetadataRemovalPlan @@ -1785,7 +1789,7 @@ namespace MediaBrowser.Controller.MediaEncoding var alphaParam = enableAlpha ? ":alpha=1" : string.Empty; var sub2videoParam = enableSub2video ? ":sub2video=1" : string.Empty; - var fontPath = Path.Combine(_appPaths.CachePath, "attachments", state.MediaSource.Id); + var fontPath = _pathManager.GetAttachmentFolderPath(state.MediaSource.Id); var fontParam = string.Format( CultureInfo.InvariantCulture, ":fontsdir='{0}'", diff --git a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs index 09840d2ee..d8d136472 100644 --- a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs +++ b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs @@ -9,26 +9,33 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -namespace MediaBrowser.Controller.MediaEncoding -{ - public interface IAttachmentExtractor - { - Task<(MediaAttachment Attachment, Stream Stream)> GetAttachment( - BaseItem item, - string mediaSourceId, - int attachmentStreamIndex, - CancellationToken cancellationToken); +namespace MediaBrowser.Controller.MediaEncoding; - Task ExtractAllAttachments( - string inputFile, - MediaSourceInfo mediaSource, - string outputPath, - CancellationToken cancellationToken); +public interface IAttachmentExtractor +{ + /// + /// Gets the path to the attachment file. + /// + /// The . + /// The media source id. + /// The attachment index. + /// The cancellation token. + /// The async task. + Task<(MediaAttachment Attachment, Stream Stream)> GetAttachment( + BaseItem item, + string mediaSourceId, + int attachmentStreamIndex, + CancellationToken cancellationToken); - Task ExtractAllAttachmentsExternal( - string inputArgument, - string id, - string outputPath, - CancellationToken cancellationToken); - } + /// + /// Gets the path to the attachment file. + /// + /// The input file path. + /// The source id. + /// The cancellation token. + /// The async task. + Task ExtractAllAttachments( + string inputFile, + MediaSourceInfo mediaSource, + CancellationToken cancellationToken); } diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 431fc0b17..89291c73b 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -1,7 +1,4 @@ -#pragma warning disable CS1591 - using System; -using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; @@ -9,28 +6,27 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; -using MediaBrowser.Common; -using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.MediaEncoding.Encoder; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; -using MediaBrowser.Model.MediaInfo; using Microsoft.Extensions.Logging; namespace MediaBrowser.MediaEncoding.Attachments { + /// public sealed class AttachmentExtractor : IAttachmentExtractor, IDisposable { private readonly ILogger _logger; - private readonly IApplicationPaths _appPaths; private readonly IFileSystem _fileSystem; private readonly IMediaEncoder _mediaEncoder; private readonly IMediaSourceManager _mediaSourceManager; + private readonly IPathManager _pathManager; private readonly AsyncKeyedLocker _semaphoreLocks = new(o => { @@ -38,18 +34,26 @@ namespace MediaBrowser.MediaEncoding.Attachments o.PoolInitialFill = 1; }); + /// + /// Initializes a new instance of the class. + /// + /// The . + /// The . + /// The . + /// The . + /// The . public AttachmentExtractor( ILogger logger, - IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, - IMediaSourceManager mediaSourceManager) + IMediaSourceManager mediaSourceManager, + IPathManager pathManager) { _logger = logger; - _appPaths = appPaths; _fileSystem = fileSystem; _mediaEncoder = mediaEncoder; _mediaSourceManager = mediaSourceManager; + _pathManager = pathManager; } /// @@ -77,350 +81,183 @@ namespace MediaBrowser.MediaEncoding.Attachments throw new ResourceNotFoundException($"MediaSource {mediaSourceId} has no attachment with stream index {attachmentStreamIndex}"); } + if (string.Equals(mediaAttachment.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)) + { + throw new ResourceNotFoundException($"Attachment with stream index {attachmentStreamIndex} can't be extracted for MediaSource {mediaSourceId}"); + } + var attachmentStream = await GetAttachmentStream(mediaSource, mediaAttachment, cancellationToken) .ConfigureAwait(false); return (mediaAttachment, attachmentStream); } + /// public async Task ExtractAllAttachments( string inputFile, MediaSourceInfo mediaSource, - string outputPath, CancellationToken cancellationToken) { var shouldExtractOneByOne = mediaSource.MediaAttachments.Any(a => !string.IsNullOrEmpty(a.FileName) && (a.FileName.Contains('/', StringComparison.OrdinalIgnoreCase) || a.FileName.Contains('\\', StringComparison.OrdinalIgnoreCase))); - if (shouldExtractOneByOne) - { - var attachmentIndexes = mediaSource.MediaAttachments.Select(a => a.Index); - foreach (var i in attachmentIndexes) - { - var newName = Path.Join(outputPath, i.ToString(CultureInfo.InvariantCulture)); - await ExtractAttachment(inputFile, mediaSource, i, newName, cancellationToken).ConfigureAwait(false); - } - } - else + if (shouldExtractOneByOne && !inputFile.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) { - using (await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false)) + foreach (var attachment in mediaSource.MediaAttachments) { - if (!Directory.Exists(outputPath)) + if (!string.Equals(attachment.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)) { - await ExtractAllAttachmentsInternal( - _mediaEncoder.GetInputArgument(inputFile, mediaSource), - outputPath, - false, - cancellationToken).ConfigureAwait(false); + await ExtractAttachment(inputFile, mediaSource, attachment, cancellationToken).ConfigureAwait(false); } } } - } - - public async Task ExtractAllAttachmentsExternal( - string inputArgument, - string id, - string outputPath, - CancellationToken cancellationToken) - { - using (await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false)) + else { - if (!File.Exists(Path.Join(outputPath, id))) - { - await ExtractAllAttachmentsInternal( - inputArgument, - outputPath, - true, - cancellationToken).ConfigureAwait(false); - - if (Directory.Exists(outputPath)) - { - File.Create(Path.Join(outputPath, id)); - } - } + await ExtractAllAttachmentsInternal( + inputFile, + mediaSource, + false, + cancellationToken).ConfigureAwait(false); } } private async Task ExtractAllAttachmentsInternal( - string inputPath, - string outputPath, + string inputFile, + MediaSourceInfo mediaSource, bool isExternal, CancellationToken cancellationToken) { - ArgumentException.ThrowIfNullOrEmpty(inputPath); - ArgumentException.ThrowIfNullOrEmpty(outputPath); - - Directory.CreateDirectory(outputPath); - - var processArgs = string.Format( - CultureInfo.InvariantCulture, - "-dump_attachment:t \"\" -y {0} -i {1} -t 0 -f null null", - inputPath.EndsWith(".concat\"", StringComparison.OrdinalIgnoreCase) ? "-f concat -safe 0" : string.Empty, - inputPath); - - int exitCode; - - using (var process = new Process - { - StartInfo = new ProcessStartInfo - { - Arguments = processArgs, - FileName = _mediaEncoder.EncoderPath, - UseShellExecute = false, - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - WorkingDirectory = outputPath, - ErrorDialog = false - }, - EnableRaisingEvents = true - }) - { - _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments); - - process.Start(); + var inputPath = _mediaEncoder.GetInputArgument(inputFile, mediaSource); - try - { - await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false); - exitCode = process.ExitCode; - } - catch (OperationCanceledException) - { - process.Kill(true); - exitCode = -1; - } - } - - var failed = false; + ArgumentException.ThrowIfNullOrEmpty(inputPath); - if (exitCode != 0) + var outputFolder = _pathManager.GetAttachmentFolderPath(mediaSource.Id); + using (await _semaphoreLocks.LockAsync(outputFolder, cancellationToken).ConfigureAwait(false)) { - if (isExternal && exitCode == 1) + if (!Directory.Exists(outputFolder)) { - // ffmpeg returns exitCode 1 because there is no video or audio stream - // this can be ignored + Directory.CreateDirectory(outputFolder); } else { - failed = true; - - _logger.LogWarning("Deleting extracted attachments {Path} due to failure: {ExitCode}", outputPath, exitCode); - try + var fileNames = Directory.GetFiles(outputFolder, "*", SearchOption.TopDirectoryOnly).Select(f => Path.GetFileName(f)); + var missingFiles = mediaSource.MediaAttachments.Where(a => !fileNames.Contains(a.FileName) && !string.Equals(a.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)); + if (!missingFiles.Any()) { - Directory.Delete(outputPath); - } - catch (IOException ex) - { - _logger.LogError(ex, "Error deleting extracted attachments {Path}", outputPath); + // Skip extraction if all files already exist + return; } } - } - else if (!Directory.Exists(outputPath)) - { - failed = true; - } - - if (failed) - { - _logger.LogError("ffmpeg attachment extraction failed for {InputPath} to {OutputPath}", inputPath, outputPath); - - throw new InvalidOperationException( - string.Format(CultureInfo.InvariantCulture, "ffmpeg attachment extraction failed for {0} to {1}", inputPath, outputPath)); - } - - _logger.LogInformation("ffmpeg attachment extraction completed for {InputPath} to {OutputPath}", inputPath, outputPath); - } - private async Task GetAttachmentStream( - MediaSourceInfo mediaSource, - MediaAttachment mediaAttachment, - CancellationToken cancellationToken) - { - var attachmentPath = await GetReadableFile(mediaSource.Path, mediaSource.Path, mediaSource, mediaAttachment, cancellationToken).ConfigureAwait(false); - return AsyncFile.OpenRead(attachmentPath); - } - - private async Task GetReadableFile( - string mediaPath, - string inputFile, - MediaSourceInfo mediaSource, - MediaAttachment mediaAttachment, - CancellationToken cancellationToken) - { - await CacheAllAttachments(mediaPath, inputFile, mediaSource, cancellationToken).ConfigureAwait(false); - - var outputPath = GetAttachmentCachePath(mediaPath, mediaSource, mediaAttachment.Index); - await ExtractAttachment(inputFile, mediaSource, mediaAttachment.Index, outputPath, cancellationToken) - .ConfigureAwait(false); - - return outputPath; - } + var processArgs = string.Format( + CultureInfo.InvariantCulture, + "-dump_attachment:t \"\" -y {0} -i {1} -t 0 -f null null", + inputPath.EndsWith(".concat\"", StringComparison.OrdinalIgnoreCase) ? "-f concat -safe 0" : string.Empty, + inputPath); - private async Task CacheAllAttachments( - string mediaPath, - string inputFile, - MediaSourceInfo mediaSource, - CancellationToken cancellationToken) - { - var outputFileLocks = new List(); - var extractableAttachmentIds = new List(); + int exitCode; - try - { - foreach (var attachment in mediaSource.MediaAttachments) + using (var process = new Process + { + StartInfo = new ProcessStartInfo + { + Arguments = processArgs, + FileName = _mediaEncoder.EncoderPath, + UseShellExecute = false, + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, + WorkingDirectory = outputFolder, + ErrorDialog = false + }, + EnableRaisingEvents = true + }) { - var outputPath = GetAttachmentCachePath(mediaPath, mediaSource, attachment.Index); + _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments); - var releaser = await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false); + process.Start(); - if (File.Exists(outputPath)) + try { - releaser.Dispose(); - continue; + await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false); + exitCode = process.ExitCode; } - - outputFileLocks.Add(releaser); - extractableAttachmentIds.Add(attachment.Index); - } - - if (extractableAttachmentIds.Count > 0) - { - await CacheAllAttachmentsInternal(mediaPath, _mediaEncoder.GetInputArgument(inputFile, mediaSource), mediaSource, extractableAttachmentIds, cancellationToken).ConfigureAwait(false); - } - } - catch (Exception ex) - { - _logger.LogWarning(ex, "Unable to cache media attachments for File:{File}", mediaPath); - } - finally - { - outputFileLocks.ForEach(x => x.Dispose()); - } - } - - private async Task CacheAllAttachmentsInternal( - string mediaPath, - string inputFile, - MediaSourceInfo mediaSource, - List extractableAttachmentIds, - CancellationToken cancellationToken) - { - var outputPaths = new List(); - var processArgs = string.Empty; - - foreach (var attachmentId in extractableAttachmentIds) - { - var outputPath = GetAttachmentCachePath(mediaPath, mediaSource, attachmentId); - - Directory.CreateDirectory(Path.GetDirectoryName(outputPath) ?? throw new FileNotFoundException($"Calculated path ({outputPath}) is not valid.")); - - outputPaths.Add(outputPath); - processArgs += string.Format( - CultureInfo.InvariantCulture, - " -dump_attachment:{0} \"{1}\"", - attachmentId, - EncodingUtils.NormalizePath(outputPath)); - } - - processArgs += string.Format( - CultureInfo.InvariantCulture, - " -i {0} -t 0 -f null null", - inputFile); - - int exitCode; - - using (var process = new Process - { - StartInfo = new ProcessStartInfo + catch (OperationCanceledException) { - Arguments = processArgs, - FileName = _mediaEncoder.EncoderPath, - UseShellExecute = false, - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - }, - EnableRaisingEvents = true - }) - { - _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments); - - process.Start(); - - try - { - await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false); - exitCode = process.ExitCode; - } - catch (OperationCanceledException) - { - process.Kill(true); - exitCode = -1; + process.Kill(true); + exitCode = -1; + } } - } - var failed = false; + var failed = false; - if (exitCode == -1) - { - failed = true; - - foreach (var outputPath in outputPaths) + if (exitCode != 0) { - try + if (isExternal && exitCode == 1) { - _logger.LogWarning("Deleting extracted media attachment due to failure: {Path}", outputPath); - _fileSystem.DeleteFile(outputPath); - } - catch (FileNotFoundException) - { - // ffmpeg failed, so it is normal that one or more expected output files do not exist. - // There is no need to log anything for the user here. + // ffmpeg returns exitCode 1 because there is no video or audio stream + // this can be ignored } - catch (IOException ex) + else { - _logger.LogError(ex, "Error deleting extracted media attachment {Path}", outputPath); + failed = true; + + _logger.LogWarning("Deleting extracted attachments {Path} due to failure: {ExitCode}", outputFolder, exitCode); + try + { + Directory.Delete(outputFolder); + } + catch (IOException ex) + { + _logger.LogError(ex, "Error deleting extracted attachments {Path}", outputFolder); + } } } - } - else - { - foreach (var outputPath in outputPaths) + else if (!Directory.Exists(outputFolder)) { - if (!File.Exists(outputPath)) - { - _logger.LogError("ffmpeg media attachment extraction failed for {InputPath} to {OutputPath}", inputFile, outputPath); - failed = true; - continue; - } + failed = true; + } - _logger.LogInformation("ffmpeg media attachment extraction completed for {InputPath} to {OutputPath}", inputFile, outputPath); + if (failed) + { + _logger.LogError("ffmpeg attachment extraction failed for {InputPath} to {OutputPath}", inputPath, outputFolder); + + throw new InvalidOperationException( + string.Format(CultureInfo.InvariantCulture, "ffmpeg attachment extraction failed for {0} to {1}", inputPath, outputFolder)); } - } - if (failed) - { - throw new FfmpegException( - string.Format(CultureInfo.InvariantCulture, "ffmpeg media attachment extraction failed for {0}", inputFile)); + _logger.LogInformation("ffmpeg attachment extraction completed for {InputPath} to {OutputPath}", inputPath, outputFolder); } } - private async Task ExtractAttachment( + private async Task GetAttachmentStream( + MediaSourceInfo mediaSource, + MediaAttachment mediaAttachment, + CancellationToken cancellationToken) + { + var attachmentPath = await ExtractAttachment(mediaSource.Path, mediaSource, mediaAttachment, cancellationToken) + .ConfigureAwait(false); + return AsyncFile.OpenRead(attachmentPath); + } + + private async Task ExtractAttachment( string inputFile, MediaSourceInfo mediaSource, - int attachmentStreamIndex, - string outputPath, + MediaAttachment mediaAttachment, CancellationToken cancellationToken) { - using (await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false)) + var attachmentFolderPath = _pathManager.GetAttachmentFolderPath(mediaSource.Id); + using (await _semaphoreLocks.LockAsync(attachmentFolderPath, cancellationToken).ConfigureAwait(false)) { - if (!File.Exists(outputPath)) + var attachmentPath = _pathManager.GetAttachmentPath(mediaSource.Id, mediaAttachment.FileName ?? mediaAttachment.Index.ToString(CultureInfo.InvariantCulture)); + if (!File.Exists(attachmentPath)) { await ExtractAttachmentInternal( _mediaEncoder.GetInputArgument(inputFile, mediaSource), - attachmentStreamIndex, - outputPath, + mediaAttachment.Index, + attachmentPath, cancellationToken).ConfigureAwait(false); } + + return attachmentPath; } } @@ -510,23 +347,6 @@ namespace MediaBrowser.MediaEncoding.Attachments _logger.LogInformation("ffmpeg attachment extraction completed for {InputPath} to {OutputPath}", inputPath, outputPath); } - private string GetAttachmentCachePath(string mediaPath, MediaSourceInfo mediaSource, int attachmentStreamIndex) - { - string filename; - if (mediaSource.Protocol == MediaProtocol.File) - { - var date = _fileSystem.GetLastWriteTimeUtc(mediaPath); - filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture); - } - else - { - filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture); - } - - var prefix = filename.AsSpan(0, 1); - return Path.Join(_appPaths.DataPath, "attachments", prefix, filename); - } - /// public void Dispose() { diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index a731d4785..777e33587 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -13,10 +13,10 @@ using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; using MediaBrowser.Common; -using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dto; @@ -31,12 +31,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles public sealed class SubtitleEncoder : ISubtitleEncoder, IDisposable { private readonly ILogger _logger; - private readonly IApplicationPaths _appPaths; private readonly IFileSystem _fileSystem; private readonly IMediaEncoder _mediaEncoder; private readonly IHttpClientFactory _httpClientFactory; private readonly IMediaSourceManager _mediaSourceManager; private readonly ISubtitleParser _subtitleParser; + private readonly IPathManager _pathManager; /// /// The _semaphoreLocks. @@ -49,24 +49,22 @@ namespace MediaBrowser.MediaEncoding.Subtitles public SubtitleEncoder( ILogger logger, - IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IHttpClientFactory httpClientFactory, IMediaSourceManager mediaSourceManager, - ISubtitleParser subtitleParser) + ISubtitleParser subtitleParser, + IPathManager pathManager) { _logger = logger; - _appPaths = appPaths; _fileSystem = fileSystem; _mediaEncoder = mediaEncoder; _httpClientFactory = httpClientFactory; _mediaSourceManager = mediaSourceManager; _subtitleParser = subtitleParser; + _pathManager = pathManager; } - private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles"); - private MemoryStream ConvertSubtitles( Stream stream, string inputFormat, @@ -830,26 +828,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles private string GetSubtitleCachePath(MediaSourceInfo mediaSource, int subtitleStreamIndex, string outputSubtitleExtension) { - if (mediaSource.Protocol == MediaProtocol.File) - { - var ticksParam = string.Empty; - - var date = _fileSystem.GetLastWriteTimeUtc(mediaSource.Path); - - ReadOnlySpan filename = (mediaSource.Path + "_" + subtitleStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture) + ticksParam).GetMD5() + outputSubtitleExtension; - - var prefix = filename.Slice(0, 1); - - return Path.Join(SubtitleCachePath, prefix, filename); - } - else - { - ReadOnlySpan filename = (mediaSource.Path + "_" + subtitleStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5() + outputSubtitleExtension; - - var prefix = filename.Slice(0, 1); - - return Path.Join(SubtitleCachePath, prefix, filename); - } + return _pathManager.GetSubtitlePath(mediaSource.Id, subtitleStreamIndex, outputSubtitleExtension); } /// diff --git a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs index c7f9cf2cc..0cda803d6 100644 --- a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs +++ b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs @@ -398,24 +398,19 @@ public sealed class TranscodeManager : ITranscodeManager, IDisposable // If subtitles get burned in fonts may need to be extracted from the media file if (state.SubtitleStream is not null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) { - var attachmentPath = Path.Combine(_appPaths.CachePath, "attachments", state.MediaSource.Id); if (state.MediaSource.VideoType == VideoType.Dvd || state.MediaSource.VideoType == VideoType.BluRay) { var concatPath = Path.Join(_appPaths.CachePath, "concat", state.MediaSource.Id + ".concat"); - await _attachmentExtractor.ExtractAllAttachments(concatPath, state.MediaSource, attachmentPath, cancellationTokenSource.Token).ConfigureAwait(false); + await _attachmentExtractor.ExtractAllAttachments(concatPath, state.MediaSource, cancellationTokenSource.Token).ConfigureAwait(false); } else { - await _attachmentExtractor.ExtractAllAttachments(state.MediaPath, state.MediaSource, attachmentPath, cancellationTokenSource.Token).ConfigureAwait(false); + await _attachmentExtractor.ExtractAllAttachments(state.MediaPath, state.MediaSource, cancellationTokenSource.Token).ConfigureAwait(false); } if (state.SubtitleStream.IsExternal && Path.GetExtension(state.SubtitleStream.Path.AsSpan()).Equals(".mks", StringComparison.OrdinalIgnoreCase)) { - string subtitlePath = state.SubtitleStream.Path; - string subtitlePathArgument = string.Format(CultureInfo.InvariantCulture, "file:\"{0}\"", subtitlePath.Replace("\"", "\\\"", StringComparison.Ordinal)); - string subtitleId = subtitlePath.GetMD5().ToString("N", CultureInfo.InvariantCulture); - - await _attachmentExtractor.ExtractAllAttachmentsExternal(subtitlePathArgument, subtitleId, attachmentPath, cancellationTokenSource.Token).ConfigureAwait(false); + await _attachmentExtractor.ExtractAllAttachments(state.SubtitleStream.Path, state.MediaSource, cancellationTokenSource.Token).ConfigureAwait(false); } } diff --git a/MediaBrowser.Model/Entities/MediaAttachment.cs b/MediaBrowser.Model/Entities/MediaAttachment.cs index 34e3eabc9..f8f7ad0f9 100644 --- a/MediaBrowser.Model/Entities/MediaAttachment.cs +++ b/MediaBrowser.Model/Entities/MediaAttachment.cs @@ -1,51 +1,49 @@ -#nullable disable -namespace MediaBrowser.Model.Entities +namespace MediaBrowser.Model.Entities; + +/// +/// Class MediaAttachment. +/// +public class MediaAttachment { /// - /// Class MediaAttachment. + /// Gets or sets the codec. /// - public class MediaAttachment - { - /// - /// Gets or sets the codec. - /// - /// The codec. - public string Codec { get; set; } + /// The codec. + public string? Codec { get; set; } - /// - /// Gets or sets the codec tag. - /// - /// The codec tag. - public string CodecTag { get; set; } + /// + /// Gets or sets the codec tag. + /// + /// The codec tag. + public string? CodecTag { get; set; } - /// - /// Gets or sets the comment. - /// - /// The comment. - public string Comment { get; set; } + /// + /// Gets or sets the comment. + /// + /// The comment. + public string? Comment { get; set; } - /// - /// Gets or sets the index. - /// - /// The index. - public int Index { get; set; } + /// + /// Gets or sets the index. + /// + /// The index. + public int Index { get; set; } - /// - /// Gets or sets the filename. - /// - /// The filename. - public string FileName { get; set; } + /// + /// Gets or sets the filename. + /// + /// The filename. + public string? FileName { get; set; } - /// - /// Gets or sets the MIME type. - /// - /// The MIME type. - public string MimeType { get; set; } + /// + /// Gets or sets the MIME type. + /// + /// The MIME type. + public string? MimeType { get; set; } - /// - /// Gets or sets the delivery URL. - /// - /// The delivery URL. - public string DeliveryUrl { get; set; } - } + /// + /// Gets or sets the delivery URL. + /// + /// The delivery URL. + public string? DeliveryUrl { get; set; } } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs index aab3082b3..2f27d9389 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs @@ -25,7 +25,7 @@ public class AttachmentStreamInfo /// /// Gets or Sets the codec of the attachment. /// - public required string Codec { get; set; } + public string? Codec { get; set; } /// /// Gets or Sets the codec tag of the attachment. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.Designer.cs new file mode 100644 index 000000000..d668eea92 --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.Designer.cs @@ -0,0 +1,1657 @@ +// +using System; +using Jellyfin.Database.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20250331182844_FixAttachmentMigration")] + partial class FixAttachmentMigration + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "9.0.3"); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AncestorId", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ParentItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AttachmentStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("Filename") + .HasColumnType("TEXT"); + + b.Property("MimeType") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Album") + .HasColumnType("TEXT"); + + b.Property("AlbumArtists") + .HasColumnType("TEXT"); + + b.Property("Artists") + .HasColumnType("TEXT"); + + b.Property("Audio") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("TEXT"); + + b.Property("CleanName") + .HasColumnType("TEXT"); + + b.Property("CommunityRating") + .HasColumnType("REAL"); + + b.Property("CriticRating") + .HasColumnType("REAL"); + + b.Property("CustomRating") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastMediaAdded") + .HasColumnType("TEXT"); + + b.Property("DateLastRefreshed") + .HasColumnType("TEXT"); + + b.Property("DateLastSaved") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EpisodeTitle") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasColumnType("TEXT"); + + b.Property("ExternalSeriesId") + .HasColumnType("TEXT"); + + b.Property("ExternalServiceId") + .HasColumnType("TEXT"); + + b.Property("ExtraIds") + .HasColumnType("TEXT"); + + b.Property("ExtraType") + .HasColumnType("INTEGER"); + + b.Property("ForcedSortName") + .HasColumnType("TEXT"); + + b.Property("Genres") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IndexNumber") + .HasColumnType("INTEGER"); + + b.Property("InheritedParentalRatingSubValue") + .HasColumnType("INTEGER"); + + b.Property("InheritedParentalRatingValue") + .HasColumnType("INTEGER"); + + b.Property("IsFolder") + .HasColumnType("INTEGER"); + + b.Property("IsInMixedFolder") + .HasColumnType("INTEGER"); + + b.Property("IsLocked") + .HasColumnType("INTEGER"); + + b.Property("IsMovie") + .HasColumnType("INTEGER"); + + b.Property("IsRepeat") + .HasColumnType("INTEGER"); + + b.Property("IsSeries") + .HasColumnType("INTEGER"); + + b.Property("IsVirtualItem") + .HasColumnType("INTEGER"); + + b.Property("LUFS") + .HasColumnType("REAL"); + + b.Property("MediaType") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizationGain") + .HasColumnType("REAL"); + + b.Property("OfficialRating") + .HasColumnType("TEXT"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("ParentIndexNumber") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataCountryCode") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataLanguage") + .HasColumnType("TEXT"); + + b.Property("PremiereDate") + .HasColumnType("TEXT"); + + b.Property("PresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("PrimaryVersionId") + .HasColumnType("TEXT"); + + b.Property("ProductionLocations") + .HasColumnType("TEXT"); + + b.Property("ProductionYear") + .HasColumnType("INTEGER"); + + b.Property("RunTimeTicks") + .HasColumnType("INTEGER"); + + b.Property("SeasonId") + .HasColumnType("TEXT"); + + b.Property("SeasonName") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("TEXT"); + + b.Property("SeriesName") + .HasColumnType("TEXT"); + + b.Property("SeriesPresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("ShowId") + .HasColumnType("TEXT"); + + b.Property("Size") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("Studios") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Tags") + .HasColumnType("TEXT"); + + b.Property("TopParentId") + .HasColumnType("TEXT"); + + b.Property("TotalBitrate") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnratedType") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Blurhash") + .HasColumnType("BLOB"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("ImageType") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemMetadataField", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemProvider", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("ProviderValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemTrailerType", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Chapter", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ChapterIndex") + .HasColumnType("INTEGER"); + + b.Property("ImageDateModified") + .HasColumnType("TEXT"); + + b.Property("ImagePath") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("StartPositionTicks") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValue", b => + { + b.Property("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CleanValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue") + .IsUnique(); + + b.ToTable("ItemValues"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValueMap", b => + { + b.Property("ItemValueId") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EndTicks") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartTicks") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("StreamIndex") + .HasColumnType("INTEGER"); + + b.Property("AspectRatio") + .HasColumnType("TEXT"); + + b.Property("AverageFrameRate") + .HasColumnType("REAL"); + + b.Property("BitDepth") + .HasColumnType("INTEGER"); + + b.Property("BitRate") + .HasColumnType("INTEGER"); + + b.Property("BlPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("ChannelLayout") + .HasColumnType("TEXT"); + + b.Property("Channels") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("CodecTimeBase") + .HasColumnType("TEXT"); + + b.Property("ColorPrimaries") + .HasColumnType("TEXT"); + + b.Property("ColorSpace") + .HasColumnType("TEXT"); + + b.Property("ColorTransfer") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("DvBlSignalCompatibilityId") + .HasColumnType("INTEGER"); + + b.Property("DvLevel") + .HasColumnType("INTEGER"); + + b.Property("DvProfile") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMajor") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMinor") + .HasColumnType("INTEGER"); + + b.Property("ElPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IsAnamorphic") + .HasColumnType("INTEGER"); + + b.Property("IsAvc") + .HasColumnType("INTEGER"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("IsExternal") + .HasColumnType("INTEGER"); + + b.Property("IsForced") + .HasColumnType("INTEGER"); + + b.Property("IsHearingImpaired") + .HasColumnType("INTEGER"); + + b.Property("IsInterlaced") + .HasColumnType("INTEGER"); + + b.Property("KeyFrames") + .HasColumnType("TEXT"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("REAL"); + + b.Property("NalLengthSize") + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PixelFormat") + .HasColumnType("TEXT"); + + b.Property("Profile") + .HasColumnType("TEXT"); + + b.Property("RealFrameRate") + .HasColumnType("REAL"); + + b.Property("RefFrames") + .HasColumnType("INTEGER"); + + b.Property("Rotation") + .HasColumnType("INTEGER"); + + b.Property("RpuPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("SampleRate") + .HasColumnType("INTEGER"); + + b.Property("StreamType") + .HasColumnType("INTEGER"); + + b.Property("TimeBase") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PersonType") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.PeopleBaseItemMap", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("PeopleId") + .HasColumnType("TEXT"); + + b.Property("ListOrder") + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalRatingScore") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalRatingSubScore") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.UserData", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("CustomDataKey") + .HasColumnType("TEXT"); + + b.Property("AudioStreamIndex") + .HasColumnType("INTEGER"); + + b.Property("IsFavorite") + .HasColumnType("INTEGER"); + + b.Property("LastPlayedDate") + .HasColumnType("TEXT"); + + b.Property("Likes") + .HasColumnType("INTEGER"); + + b.Property("PlayCount") + .HasColumnType("INTEGER"); + + b.Property("PlaybackPositionTicks") + .HasColumnType("INTEGER"); + + b.Property("Played") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("REAL"); + + b.Property("SubtitleStreamIndex") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "UserId", "CustomDataKey"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Children") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "ParentItem") + .WithMany("ParentAncestors") + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Database.Implementations.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Permission", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Preference", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.UserData", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => + { + b.Navigation("Chapters"); + + b.Navigation("Children"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("ParentAncestors"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.cs new file mode 100644 index 000000000..f921856a2 --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class FixAttachmentMigration : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Codec", + table: "AttachmentStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Codec", + table: "AttachmentStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + } + } +} diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs index 0bb4b31b0..08c73217f 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs @@ -120,7 +120,6 @@ namespace Jellyfin.Server.Implementations.Migrations .HasColumnType("INTEGER"); b.Property("Codec") - .IsRequired() .HasColumnType("TEXT"); b.Property("CodecTag") -- cgit v1.2.3 From e84826297d53745c6aad2c39b9d3b096384ba07c Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Sat, 19 Apr 2025 16:41:30 +0000 Subject: Fix thumbnail extraction of mpegts videos in FFmpeg 7.1+ (#13942) --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 9a759ba41..39c0bfed4 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -720,13 +720,11 @@ namespace MediaBrowser.MediaEncoding.Encoder filters.Add(scaler); - // Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case. - // mpegts need larger batch size otherwise the corrupted thumbnail will be created. Larger batch size will lower the processing speed. + // Use ffmpeg to sample N frames and pick the best thumbnail. Have a fall back just in case. var enableThumbnail = !useTradeoff && useIFrame && !string.Equals("wtv", container, StringComparison.OrdinalIgnoreCase); if (enableThumbnail) { - var useLargerBatchSize = string.Equals("mpegts", container, StringComparison.OrdinalIgnoreCase); - filters.Add("thumbnail=n=" + (useLargerBatchSize ? "50" : "24")); + filters.Add("thumbnail=n=24"); } // Use SW tonemap on HDR video stream only when the zscale or tonemapx filter is available. @@ -750,14 +748,26 @@ namespace MediaBrowser.MediaEncoding.Encoder var vf = string.Join(',', filters); var mapArg = imageStreamIndex.HasValue ? (" -map 0:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty; - var args = string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads {4} -v quiet -vframes 1 -vf {2}{5} -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, _threads, isAudio ? string.Empty : GetImageResolutionParameter()); + var args = string.Format( + CultureInfo.InvariantCulture, + "-i {0}{1} -threads {2} -v quiet -vframes 1 -vf {3}{4}{5} -f image2 \"{6}\"", + inputPath, + mapArg, + _threads, + vf, + isAudio ? string.Empty : GetImageResolutionParameter(), + EncodingHelper.GetVideoSyncOption("0", EncoderVersion).Trim(), // passthrough timestamp + tempExtractPath); if (offset.HasValue) { args = string.Format(CultureInfo.InvariantCulture, "-ss {0} ", GetTimeParameter(offset.Value)) + args; } - if (useIFrame && useTradeoff) + // The mpegts demuxer cannot seek to keyframes, so we have to let the + // decoder discard non-keyframes, which may contain corrupted images. + var seekMpegTs = offset.HasValue && string.Equals("mpegts", container, StringComparison.OrdinalIgnoreCase); + if ((useIFrame && useTradeoff) || seekMpegTs) { args = "-skip_frame nokey " + args; } -- cgit v1.2.3 From 74230131a199e33894cf1778cee3579cd3c75011 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Sat, 19 Apr 2025 21:08:29 +0200 Subject: Fix OverflowException when scanning media with a very short duration (#13949) --- .../Probing/ProbeResultNormalizer.cs | 2 +- .../Probing/ProbeResultNormalizerTests.cs | 34 ++++ .../Probing/video_single_frame_mjpeg.json | 209 +++++++++++++++++++++ 3 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_single_frame_mjpeg.json (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index a98dbe597..5784deacd 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -965,7 +965,7 @@ namespace MediaBrowser.MediaEncoding.Probing // Get average bitrate info from tag "NUMBER_OF_BYTES" and "DURATION" if possible. var durationInSeconds = GetRuntimeSecondsFromTags(streamInfo); var bytes = GetNumberOfBytesFromTags(streamInfo); - if (durationInSeconds is not null && bytes is not null) + if (durationInSeconds is not null && durationInSeconds.Value >= 1 && bytes is not null) { bps = Convert.ToInt32(bytes * 8 / durationInSeconds, CultureInfo.InvariantCulture); if (bps > 0) diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs index df51d39cb..94710a095 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs @@ -288,6 +288,40 @@ namespace Jellyfin.MediaEncoding.Tests.Probing Assert.True(res.VideoStream.IsDefault); } + [Fact] + public void GetMediaInfo_VideoWithSingleFrameMjpeg_Success() + { + var bytes = File.ReadAllBytes("Test Data/Probing/video_single_frame_mjpeg.json"); + + var internalMediaInfoResult = JsonSerializer.Deserialize(bytes, _jsonOptions); + MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, VideoType.VideoFile, false, "Test Data/Probing/video_interlaced.mp4", MediaProtocol.File); + + Assert.Equal(3, res.MediaStreams.Count); + + Assert.NotNull(res.VideoStream); + Assert.Equal(res.MediaStreams[0], res.VideoStream); + Assert.Equal(0, res.VideoStream.Index); + Assert.Equal("h264", res.VideoStream.Codec); + Assert.Equal("High", res.VideoStream.Profile); + Assert.Equal(MediaStreamType.Video, res.VideoStream.Type); + Assert.Equal(1080, res.VideoStream.Height); + Assert.Equal(1920, res.VideoStream.Width); + Assert.False(res.VideoStream.IsInterlaced); + Assert.Equal("16:9", res.VideoStream.AspectRatio); + Assert.Equal("yuv420p", res.VideoStream.PixelFormat); + Assert.Equal(42d, res.VideoStream.Level); + Assert.Equal(1, res.VideoStream.RefFrames); + Assert.True(res.VideoStream.IsAVC); + Assert.Equal(50f, res.VideoStream.RealFrameRate); + Assert.Equal("1/1000", res.VideoStream.TimeBase); + Assert.Equal(8, res.VideoStream.BitDepth); + Assert.True(res.VideoStream.IsDefault); + + var mjpeg = res.MediaStreams[2]; + Assert.NotNull(mjpeg); + Assert.Equal("mjpeg", mjpeg.Codec); + } + [Fact] public void GetMediaInfo_MusicVideo_Success() { diff --git a/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_single_frame_mjpeg.json b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_single_frame_mjpeg.json new file mode 100644 index 000000000..261f044bb --- /dev/null +++ b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_single_frame_mjpeg.json @@ -0,0 +1,209 @@ +{ + "streams": [ + { + "index": 0, + "codec_name": "h264", + "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", + "profile": "High", + "codec_type": "video", + "codec_tag_string": "[0][0][0][0]", + "codec_tag": "0x0000", + "width": 1920, + "height": 1080, + "coded_width": 1920, + "coded_height": 1080, + "closed_captions": 0, + "film_grain": 0, + "has_b_frames": 0, + "sample_aspect_ratio": "1:1", + "display_aspect_ratio": "16:9", + "pix_fmt": "yuv420p", + "level": 42, + "chroma_location": "left", + "field_order": "progressive", + "refs": 1, + "is_avc": "true", + "nal_length_size": "4", + "r_frame_rate": "50/1", + "avg_frame_rate": "50/1", + "time_base": "1/1000", + "start_pts": 0, + "start_time": "0.000000", + "bits_per_raw_sample": "8", + "extradata_size": 55, + "disposition": { + "default": 1, + "dub": 0, + "original": 0, + "comment": 0, + "lyrics": 0, + "karaoke": 0, + "forced": 0, + "hearing_impaired": 0, + "visual_impaired": 0, + "clean_effects": 0, + "attached_pic": 0, + "timed_thumbnails": 0, + "non_diegetic": 0, + "captions": 0, + "descriptions": 0, + "metadata": 0, + "dependent": 0, + "still_image": 0 + }, + "tags": { + "language": "deu", + "HANDLER_NAME": "VideoHandler", + "VENDOR_ID": "[0][0][0][0]", + "BPS": "3950584", + "DURATION": "00:00:10.000000000", + "NUMBER_OF_FRAMES": "500", + "NUMBER_OF_BYTES": "4938231", + "_STATISTICS_WRITING_APP": "mkvpropedit v90.0 ('Hanging On') 64-bit", + "_STATISTICS_WRITING_DATE_UTC": "2025-04-19 10:37:57", + "_STATISTICS_TAGS": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES" + } + }, + { + "index": 1, + "codec_name": "aac", + "codec_long_name": "AAC (Advanced Audio Coding)", + "profile": "LC", + "codec_type": "audio", + "codec_tag_string": "[0][0][0][0]", + "codec_tag": "0x0000", + "sample_fmt": "fltp", + "sample_rate": "48000", + "channels": 2, + "channel_layout": "stereo", + "bits_per_sample": 0, + "initial_padding": 0, + "r_frame_rate": "0/0", + "avg_frame_rate": "0/0", + "time_base": "1/1000", + "start_pts": 0, + "start_time": "0.000000", + "extradata_size": 2, + "disposition": { + "default": 1, + "dub": 0, + "original": 0, + "comment": 0, + "lyrics": 0, + "karaoke": 0, + "forced": 0, + "hearing_impaired": 0, + "visual_impaired": 0, + "clean_effects": 0, + "attached_pic": 0, + "timed_thumbnails": 0, + "non_diegetic": 0, + "captions": 0, + "descriptions": 0, + "metadata": 0, + "dependent": 0, + "still_image": 0 + }, + "tags": { + "language": "deu", + "HANDLER_NAME": "SoundHandler", + "VENDOR_ID": "[0][0][0][0]", + "BPS": "255785", + "DURATION": "00:00:09.984000000", + "NUMBER_OF_FRAMES": "469", + "NUMBER_OF_BYTES": "319220", + "_STATISTICS_WRITING_APP": "mkvpropedit v90.0 ('Hanging On') 64-bit", + "_STATISTICS_WRITING_DATE_UTC": "2025-04-19 10:37:57", + "_STATISTICS_TAGS": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES" + } + }, + { + "index": 2, + "codec_name": "mjpeg", + "codec_long_name": "Motion JPEG", + "profile": "Baseline", + "codec_type": "video", + "codec_tag_string": "[0][0][0][0]", + "codec_tag": "0x0000", + "width": 960, + "height": 540, + "coded_width": 960, + "coded_height": 540, + "closed_captions": 0, + "film_grain": 0, + "has_b_frames": 0, + "sample_aspect_ratio": "1:1", + "display_aspect_ratio": "16:9", + "pix_fmt": "yuvj420p", + "level": -99, + "color_range": "pc", + "color_space": "bt470bg", + "chroma_location": "center", + "refs": 1, + "r_frame_rate": "1000/1", + "avg_frame_rate": "30000/1", + "time_base": "1/1000", + "start_pts": 0, + "start_time": "0.000000", + "bits_per_raw_sample": "8", + "disposition": { + "default": 0, + "dub": 0, + "original": 0, + "comment": 0, + "lyrics": 0, + "karaoke": 0, + "forced": 0, + "hearing_impaired": 0, + "visual_impaired": 0, + "clean_effects": 0, + "attached_pic": 0, + "timed_thumbnails": 0, + "non_diegetic": 0, + "captions": 0, + "descriptions": 0, + "metadata": 0, + "dependent": 0, + "still_image": 0 + }, + "tags": { + "BPS": "0", + "DURATION": "00:00:00.000011111", + "NUMBER_OF_FRAMES": "1", + "NUMBER_OF_BYTES": "155034", + "_STATISTICS_WRITING_APP": "mkvpropedit v90.0 ('Hanging On') 64-bit", + "_STATISTICS_WRITING_DATE_UTC": "2025-04-19 10:37:57", + "_STATISTICS_TAGS": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES" + } + } + ], + "chapters": [], + "format": { + "filename": "file:broken_mkv_covers - 01x03 - statistics added using mkvpropedit.mkv", + "nb_streams": 3, + "nb_programs": 0, + "nb_stream_groups": 0, + "format_name": "matroska,webm", + "format_long_name": "Matroska / WebM", + "start_time": "0.000000", + "duration": "10.005000", + "size": "5425928", + "bit_rate": "4338573", + "probe_score": 100, + "tags": { + "title": "Folge 1: Jackpot Immobilie · Wie wir klug vererben", + "EPISODE_SORT": "1", + "MAJOR_BRAND": "isom", + "MINOR_VERSION": "512", + "COMPATIBLE_BRANDS": "isomiso2avc1mp41", + "DATE": "20250318", + "SEASON_NUMBER": "1", + "COMMENT": "https://www.ardmediathek.de/video/Y3JpZDovL2JyLmRlL2Jyb2FkY2FzdC8zZWFmYTcxOC1mZDJmLTRmZTMtYWE4Ny03ZjdlNWViNTk1NDhfb25saW5lYnJvYWRjYXN0", + "DESCRIPTION": "Jeder kennt es: Enge Familienmitglieder sprechen plötzlich nicht mehr miteinander, der Streit ums Erbe entzweit die Familie. Was steht im Testament? Kann sich die Erbengemeinschaft einigen? Wie läuft das mit der Erbschaftssteuer und was sagt das Erbrecht?\n\nDas \"Lohnt sich das?\"-Team hat zwei Familien gefunden, die das Tabu rund ums Erben brechen. Sie erzählen, um wie viel Geld es geht, aber auch, was dieses Immobilienerbe mit ihrer Familie gemacht hat. Warum es einmal gelingt, Häuser in Millionenhöhe ohne jegliche Erbschaftssteuer zu vererben, während andere Geschwister sich über ihr Elternhaus komplett zerstritten haben. Erbfolge, Freibeträge, Nießbrauch - für alle Basics rund ums Erben ist Ralph Caspers zuständig, der kompetent erklärt. ", + "SYNOPSIS": "Jeder kennt es: Enge Familienmitglieder sprechen plötzlich nicht mehr miteinander, der Streit ums Erbe entzweit die Familie. Was steht im Testament? Kann sich die Erbengemeinschaft einigen? Wie läuft das mit der Erbschaftssteuer und was sagt das Erbrecht?\n\nDas \"Lohnt sich das?\"-Team hat zwei Familien gefunden, die das Tabu rund ums Erben brechen. Sie erzählen, um wie viel Geld es geht, aber auch, was dieses Immobilienerbe mit ihrer Familie gemacht hat. Warum es einmal gelingt, Häuser in Millionenhöhe ohne jegliche Erbschaftssteuer zu vererben, während andere Geschwister sich über ihr Elternhaus komplett zerstritten haben. Erbfolge, Freibeträge, Nießbrauch - für alle Basics rund ums Erben ist Ralph Caspers zuständig, der kompetent erklärt. ", + "SHOW": "Generation Wohnkrise. Lohnt sich das?", + "EPISODE_ID": "Folge 1: Jackpot Immobilie · Wie wir klug vererben", + "ENCODER": "Lavf61.7.100" + } + } +} -- cgit v1.2.3 From 9092130350024331a1c3b34cd4f9d3932a1348c7 Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Sat, 26 Apr 2025 17:36:17 +0200 Subject: Optimize migrations (#13855) --- .../Migrations/Routines/MigrateKeyframeData.cs | 60 +++----- .../Migrations/Routines/MoveExtractedFiles.cs | 158 ++++++++++----------- .../Migrations/Routines/MoveTrickplayFiles.cs | 31 ++-- MediaBrowser.Common/Plugins/BasePluginOfT.cs | 5 +- .../Attachments/AttachmentExtractor.cs | 18 +-- .../IJellyfinDatabaseProvider.cs | 4 +- .../SqliteDatabaseProvider.cs | 7 +- 7 files changed, 129 insertions(+), 154 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/Jellyfin.Server/Migrations/Routines/MigrateKeyframeData.cs b/Jellyfin.Server/Migrations/Routines/MigrateKeyframeData.cs index b8e69db8e..68d7a7b87 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateKeyframeData.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateKeyframeData.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -12,8 +11,6 @@ using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions.Json; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -24,8 +21,7 @@ namespace Jellyfin.Server.Migrations.Routines; /// public class MigrateKeyframeData : IDatabaseMigrationRoutine { - private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IApplicationPaths _appPaths; private readonly IDbContextFactory _dbProvider; private static readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; @@ -33,17 +29,14 @@ public class MigrateKeyframeData : IDatabaseMigrationRoutine /// /// Initializes a new instance of the class. /// - /// Instance of the interface. /// The logger. /// Instance of the interface. /// The EFCore db factory. public MigrateKeyframeData( - ILibraryManager libraryManager, - ILogger logger, + ILogger logger, IApplicationPaths appPaths, IDbContextFactory dbProvider) { - _libraryManager = libraryManager; _logger = logger; _appPaths = appPaths; _dbProvider = dbProvider; @@ -63,48 +56,34 @@ public class MigrateKeyframeData : IDatabaseMigrationRoutine /// public void Perform() { - const int Limit = 100; - int itemCount = 0, offset = 0, previousCount; + const int Limit = 5000; + int itemCount = 0, offset = 0; var sw = Stopwatch.StartNew(); - var itemsQuery = new InternalItemsQuery - { - MediaTypes = [MediaType.Video], - SourceTypes = [SourceType.Library], - IsVirtualItem = false, - IsFolder = false - }; using var context = _dbProvider.CreateDbContext(); + var baseQuery = context.BaseItems.Where(b => b.MediaType == MediaType.Video.ToString() && !b.IsVirtualItem && !b.IsFolder).OrderBy(e => e.Id); + var records = baseQuery.Count(); + _logger.LogInformation("Checking {Count} items for importable keyframe data.", records); + context.KeyframeData.ExecuteDelete(); using var transaction = context.Database.BeginTransaction(); - List keyframes = []; - do { - var result = _libraryManager.GetItemsResult(itemsQuery); - _logger.LogInformation("Importing keyframes for {Count} items", result.TotalRecordCount); - - var items = result.Items; - previousCount = items.Count; - offset += Limit; - foreach (var item in items) + var results = baseQuery.Skip(offset).Take(Limit).Select(b => new Tuple(b.Id, b.Path)).ToList(); + foreach (var result in results) { - if (TryGetKeyframeData(item, out var data)) + if (TryGetKeyframeData(result.Item1, result.Item2, out var data)) { - keyframes.Add(data); - } - - if (++itemCount % 10_000 == 0) - { - context.KeyframeData.AddRange(keyframes); - keyframes.Clear(); - _logger.LogInformation("Imported keyframes for {Count} items in {Time}", itemCount, sw.Elapsed); + itemCount++; + context.KeyframeData.Add(data); } } - } while (previousCount == Limit); - context.KeyframeData.AddRange(keyframes); + offset += Limit; + _logger.LogInformation("Checked: {Count} - Imported: {Items} - Time: {Time}", offset, itemCount, sw.Elapsed); + } while (offset < records); + context.SaveChanges(); transaction.Commit(); @@ -116,10 +95,9 @@ public class MigrateKeyframeData : IDatabaseMigrationRoutine } } - private bool TryGetKeyframeData(BaseItem item, [NotNullWhen(true)] out KeyframeData? data) + private bool TryGetKeyframeData(Guid id, string? path, [NotNullWhen(true)] out KeyframeData? data) { data = null; - var path = item.Path; if (!string.IsNullOrEmpty(path)) { var cachePath = GetCachePath(KeyframeCachePath, path); @@ -127,7 +105,7 @@ public class MigrateKeyframeData : IDatabaseMigrationRoutine { data = new() { - ItemId = item.Id, + ItemId = id, KeyframeTicks = keyframeData.KeyframeTicks.ToList(), TotalDuration = keyframeData.TotalDuration }; diff --git a/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs b/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs index f63c5fd40..c5bbcd6f9 100644 --- a/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs +++ b/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs @@ -1,6 +1,7 @@ #pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms using System; +using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; @@ -8,13 +9,14 @@ using System.Linq; using System.Security.Cryptography; using System.Text; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; -using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.IO; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace Jellyfin.Server.Migrations.Routines; @@ -22,34 +24,34 @@ namespace Jellyfin.Server.Migrations.Routines; /// /// Migration to move extracted files to the new directories. /// -public class MoveExtractedFiles : IDatabaseMigrationRoutine +public class MoveExtractedFiles : IMigrationRoutine { private readonly IApplicationPaths _appPaths; - private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; - private readonly IMediaSourceManager _mediaSourceManager; + private readonly IDbContextFactory _dbProvider; private readonly IPathManager _pathManager; + private readonly IFileSystem _fileSystem; /// /// Initializes a new instance of the class. /// /// Instance of the interface. - /// Instance of the interface. /// The logger. - /// Instance of the interface. + /// Instance of the interface. /// Instance of the interface. + /// Instance of the interface. public MoveExtractedFiles( IApplicationPaths appPaths, - ILibraryManager libraryManager, ILogger logger, - IMediaSourceManager mediaSourceManager, - IPathManager pathManager) + IPathManager pathManager, + IFileSystem fileSystem, + IDbContextFactory dbProvider) { _appPaths = appPaths; - _libraryManager = libraryManager; _logger = logger; - _mediaSourceManager = mediaSourceManager; _pathManager = pathManager; + _fileSystem = fileSystem; + _dbProvider = dbProvider; } private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles"); @@ -68,51 +70,41 @@ public class MoveExtractedFiles : IDatabaseMigrationRoutine /// public void Perform() { - const int Limit = 500; + const int Limit = 5000; int itemCount = 0, offset = 0; var sw = Stopwatch.StartNew(); - var itemsQuery = new InternalItemsQuery - { - MediaTypes = [MediaType.Video], - SourceTypes = [SourceType.Library], - IsVirtualItem = false, - IsFolder = false, - Limit = Limit, - StartIndex = offset, - EnableTotalRecordCount = true, - }; - - var records = _libraryManager.GetItemsResult(itemsQuery).TotalRecordCount; + + using var context = _dbProvider.CreateDbContext(); + var records = context.BaseItems.Count(b => b.MediaType == MediaType.Video.ToString() && !b.IsVirtualItem && !b.IsFolder); _logger.LogInformation("Checking {Count} items for movable extracted files.", records); // Make sure directories exist Directory.CreateDirectory(SubtitleCachePath); Directory.CreateDirectory(AttachmentCachePath); - - itemsQuery.EnableTotalRecordCount = false; do { - itemsQuery.StartIndex = offset; - var result = _libraryManager.GetItemsResult(itemsQuery); - - var items = result.Items; - foreach (var item in items) + var results = context.BaseItems + .Include(e => e.MediaStreams!.Where(s => s.StreamType == MediaStreamTypeEntity.Subtitle && !s.IsExternal)) + .Where(b => b.MediaType == MediaType.Video.ToString() && !b.IsVirtualItem && !b.IsFolder) + .OrderBy(e => e.Id) + .Skip(offset) + .Take(Limit) + .Select(b => new Tuple?>(b.Id, b.Path, b.MediaStreams)).ToList(); + + foreach (var result in results) { - if (MoveSubtitleAndAttachmentFiles(item)) + if (MoveSubtitleAndAttachmentFiles(result.Item1, result.Item2, result.Item3, context)) { itemCount++; } } offset += Limit; - if (offset % 5_000 == 0) - { - _logger.LogInformation("Checked extracted files for {Count} items in {Time}.", offset, sw.Elapsed); - } + _logger.LogInformation("Checked: {Count} - Moved: {Items} - Time: {Time}", offset, itemCount, sw.Elapsed); } while (offset < records); - _logger.LogInformation("Checked {Checked} items - Moved files for {Items} items in {Time}.", records, itemCount, sw.Elapsed); + _logger.LogInformation("Moved files for {Count} items in {Time}", itemCount, sw.Elapsed); // Get all subdirectories with 1 character names (those are the legacy directories) var subdirectories = Directory.GetDirectories(SubtitleCachePath, "*", SearchOption.AllDirectories).Where(s => s.Length == SubtitleCachePath.Length + 2).ToList(); @@ -134,52 +126,56 @@ public class MoveExtractedFiles : IDatabaseMigrationRoutine _logger.LogInformation("Cleaned up left over subtitles and attachments."); } - private bool MoveSubtitleAndAttachmentFiles(BaseItem item) + private bool MoveSubtitleAndAttachmentFiles(Guid id, string? path, ICollection? mediaStreams, JellyfinDbContext context) { - var mediaStreams = item.GetMediaStreams().Where(s => s.Type == MediaStreamType.Subtitle && !s.IsExternal); - var itemIdString = item.Id.ToString("N", CultureInfo.InvariantCulture); + var itemIdString = id.ToString("N", CultureInfo.InvariantCulture); var modified = false; - foreach (var mediaStream in mediaStreams) + if (mediaStreams is not null) { - if (mediaStream.Codec is null) + foreach (var mediaStream in mediaStreams) { - continue; - } - - var mediaStreamIndex = mediaStream.Index; - var extension = GetSubtitleExtension(mediaStream.Codec); - var oldSubtitleCachePath = GetOldSubtitleCachePath(item.Path, mediaStream.Index, extension); - if (string.IsNullOrEmpty(oldSubtitleCachePath) || !File.Exists(oldSubtitleCachePath)) - { - continue; - } + if (mediaStream.Codec is null) + { + continue; + } - var newSubtitleCachePath = _pathManager.GetSubtitlePath(itemIdString, mediaStreamIndex, extension); - if (File.Exists(newSubtitleCachePath)) - { - File.Delete(oldSubtitleCachePath); - } - else - { - var newDirectory = Path.GetDirectoryName(newSubtitleCachePath); - if (newDirectory is not null) + var mediaStreamIndex = mediaStream.StreamIndex; + var extension = GetSubtitleExtension(mediaStream.Codec); + var oldSubtitleCachePath = GetOldSubtitleCachePath(path, mediaStreamIndex, extension); + if (string.IsNullOrEmpty(oldSubtitleCachePath) || !File.Exists(oldSubtitleCachePath)) { - Directory.CreateDirectory(newDirectory); - File.Move(oldSubtitleCachePath, newSubtitleCachePath, false); - _logger.LogDebug("Moved subtitle {Index} for {Item} from {Source} to {Destination}", mediaStreamIndex, item.Id, oldSubtitleCachePath, newSubtitleCachePath); + continue; + } - modified = true; + var newSubtitleCachePath = _pathManager.GetSubtitlePath(itemIdString, mediaStreamIndex, extension); + if (File.Exists(newSubtitleCachePath)) + { + File.Delete(oldSubtitleCachePath); + } + else + { + var newDirectory = Path.GetDirectoryName(newSubtitleCachePath); + if (newDirectory is not null) + { + Directory.CreateDirectory(newDirectory); + File.Move(oldSubtitleCachePath, newSubtitleCachePath, false); + _logger.LogDebug("Moved subtitle {Index} for {Item} from {Source} to {Destination}", mediaStreamIndex, id, oldSubtitleCachePath, newSubtitleCachePath); + + modified = true; + } } } } - var attachments = _mediaSourceManager.GetMediaAttachments(item.Id).Where(a => !string.Equals(a.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)).ToList(); - var shouldExtractOneByOne = attachments.Any(a => !string.IsNullOrEmpty(a.FileName) - && (a.FileName.Contains('/', StringComparison.OrdinalIgnoreCase) || a.FileName.Contains('\\', StringComparison.OrdinalIgnoreCase))); +#pragma warning disable CA1309 // Use ordinal string comparison + var attachments = context.AttachmentStreamInfos.Where(a => a.ItemId.Equals(id) && !string.Equals(a.Codec, "mjpeg")).ToList(); +#pragma warning restore CA1309 // Use ordinal string comparison + var shouldExtractOneByOne = attachments.Any(a => !string.IsNullOrEmpty(a.Filename) + && (a.Filename.Contains('/', StringComparison.OrdinalIgnoreCase) || a.Filename.Contains('\\', StringComparison.OrdinalIgnoreCase))); foreach (var attachment in attachments) { var attachmentIndex = attachment.Index; - var oldAttachmentPath = GetOldAttachmentDataPath(item.Path, attachmentIndex); + var oldAttachmentPath = GetOldAttachmentDataPath(path, attachmentIndex); if (string.IsNullOrEmpty(oldAttachmentPath) || !File.Exists(oldAttachmentPath)) { oldAttachmentPath = GetOldAttachmentCachePath(itemIdString, attachment, shouldExtractOneByOne); @@ -189,7 +185,7 @@ public class MoveExtractedFiles : IDatabaseMigrationRoutine } } - var newAttachmentPath = _pathManager.GetAttachmentPath(itemIdString, attachment.FileName ?? attachmentIndex.ToString(CultureInfo.InvariantCulture)); + var newAttachmentPath = _pathManager.GetAttachmentPath(itemIdString, attachment.Filename ?? attachmentIndex.ToString(CultureInfo.InvariantCulture)); if (File.Exists(newAttachmentPath)) { File.Delete(oldAttachmentPath); @@ -201,7 +197,7 @@ public class MoveExtractedFiles : IDatabaseMigrationRoutine { Directory.CreateDirectory(newDirectory); File.Move(oldAttachmentPath, newAttachmentPath, false); - _logger.LogDebug("Moved attachment {Index} for {Item} from {Source} to {Destination}", attachmentIndex, item.Id, oldAttachmentPath, newAttachmentPath); + _logger.LogDebug("Moved attachment {Index} for {Item} from {Source} to {Destination}", attachmentIndex, id, oldAttachmentPath, newAttachmentPath); modified = true; } @@ -219,8 +215,7 @@ public class MoveExtractedFiles : IDatabaseMigrationRoutine } string filename; - var protocol = _mediaSourceManager.GetPathProtocol(mediaPath); - if (protocol == MediaProtocol.File) + if (_fileSystem.IsPathFile(mediaPath)) { DateTime? date; try @@ -244,7 +239,7 @@ public class MoveExtractedFiles : IDatabaseMigrationRoutine return Path.Join(_appPaths.DataPath, "attachments", filename[..1], filename); } - private string? GetOldAttachmentCachePath(string mediaSourceId, MediaAttachment attachment, bool shouldExtractOneByOne) + private string? GetOldAttachmentCachePath(string mediaSourceId, AttachmentStreamInfo attachment, bool shouldExtractOneByOne) { var attachmentFolderPath = Path.Join(_appPaths.CachePath, "attachments", mediaSourceId); if (shouldExtractOneByOne) @@ -252,16 +247,21 @@ public class MoveExtractedFiles : IDatabaseMigrationRoutine return Path.Join(attachmentFolderPath, attachment.Index.ToString(CultureInfo.InvariantCulture)); } - if (string.IsNullOrEmpty(attachment.FileName)) + if (string.IsNullOrEmpty(attachment.Filename)) { return null; } - return Path.Join(attachmentFolderPath, attachment.FileName); + return Path.Join(attachmentFolderPath, attachment.Filename); } - private string? GetOldSubtitleCachePath(string path, int streamIndex, string outputSubtitleExtension) + private string? GetOldSubtitleCachePath(string? path, int streamIndex, string outputSubtitleExtension) { + if (path is null) + { + return null; + } + DateTime? date; try { diff --git a/Jellyfin.Server/Migrations/Routines/MoveTrickplayFiles.cs b/Jellyfin.Server/Migrations/Routines/MoveTrickplayFiles.cs index eeb11e14c..a278138ce 100644 --- a/Jellyfin.Server/Migrations/Routines/MoveTrickplayFiles.cs +++ b/Jellyfin.Server/Migrations/Routines/MoveTrickplayFiles.cs @@ -15,7 +15,7 @@ namespace Jellyfin.Server.Migrations.Routines; /// /// Migration to move trickplay files to the new directory. /// -public class MoveTrickplayFiles : IDatabaseMigrationRoutine +public class MoveTrickplayFiles : IMigrationRoutine { private readonly ITrickplayManager _trickplayManager; private readonly IFileSystem _fileSystem; @@ -29,7 +29,11 @@ public class MoveTrickplayFiles : IDatabaseMigrationRoutine /// Instance of the interface. /// Instance of the interface. /// The logger. - public MoveTrickplayFiles(ITrickplayManager trickplayManager, IFileSystem fileSystem, ILibraryManager libraryManager, ILogger logger) + public MoveTrickplayFiles( + ITrickplayManager trickplayManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + ILogger logger) { _trickplayManager = trickplayManager; _fileSystem = fileSystem; @@ -49,7 +53,7 @@ public class MoveTrickplayFiles : IDatabaseMigrationRoutine /// public void Perform() { - const int Limit = 100; + const int Limit = 5000; int itemCount = 0, offset = 0, previousCount; var sw = Stopwatch.StartNew(); @@ -64,9 +68,6 @@ public class MoveTrickplayFiles : IDatabaseMigrationRoutine do { var trickplayInfos = _trickplayManager.GetTrickplayItemsAsync(Limit, offset).GetAwaiter().GetResult(); - previousCount = trickplayInfos.Count; - offset += Limit; - trickplayQuery.ItemIds = trickplayInfos.Select(i => i.ItemId).Distinct().ToArray(); var items = _libraryManager.GetItemList(trickplayQuery); foreach (var trickplayInfo in trickplayInfos) @@ -77,24 +78,32 @@ public class MoveTrickplayFiles : IDatabaseMigrationRoutine continue; } - if (++itemCount % 1_000 == 0) - { - _logger.LogInformation("Moved {Count} items in {Time}", itemCount, sw.Elapsed); - } - + var moved = false; var oldPath = GetOldTrickplayDirectory(item, trickplayInfo.Width); var newPath = _trickplayManager.GetTrickplayDirectory(item, trickplayInfo.TileWidth, trickplayInfo.TileHeight, trickplayInfo.Width, false); if (_fileSystem.DirectoryExists(oldPath)) { _fileSystem.MoveDirectory(oldPath, newPath); + moved = true; } oldPath = GetNewOldTrickplayDirectory(item, trickplayInfo.TileWidth, trickplayInfo.TileHeight, trickplayInfo.Width, false); if (_fileSystem.DirectoryExists(oldPath)) { _fileSystem.MoveDirectory(oldPath, newPath); + moved = true; + } + + if (moved) + { + itemCount++; } } + + offset += Limit; + previousCount = trickplayInfos.Count; + + _logger.LogInformation("Checked: {Checked} - Moved: {Count} - Time: {Time}", itemCount, offset, sw.Elapsed); } while (previousCount == Limit); _logger.LogInformation("Moved {Count} items in {Time}", itemCount, sw.Elapsed); diff --git a/MediaBrowser.Common/Plugins/BasePluginOfT.cs b/MediaBrowser.Common/Plugins/BasePluginOfT.cs index 58992ecd7..30c67fa05 100644 --- a/MediaBrowser.Common/Plugins/BasePluginOfT.cs +++ b/MediaBrowser.Common/Plugins/BasePluginOfT.cs @@ -145,10 +145,7 @@ namespace MediaBrowser.Common.Plugins lock (_configurationSaveLock) { var folder = Path.GetDirectoryName(ConfigurationFilePath); - if (!Directory.Exists(folder)) - { - Directory.CreateDirectory(folder); - } + Directory.CreateDirectory(folder); XmlSerializer.SerializeToFile(config, ConfigurationFilePath); } diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 89291c73b..1f2bc2403 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -133,19 +133,13 @@ namespace MediaBrowser.MediaEncoding.Attachments var outputFolder = _pathManager.GetAttachmentFolderPath(mediaSource.Id); using (await _semaphoreLocks.LockAsync(outputFolder, cancellationToken).ConfigureAwait(false)) { - if (!Directory.Exists(outputFolder)) + Directory.CreateDirectory(outputFolder); + var fileNames = Directory.GetFiles(outputFolder, "*", SearchOption.TopDirectoryOnly).Select(f => Path.GetFileName(f)); + var missingFiles = mediaSource.MediaAttachments.Where(a => !fileNames.Contains(a.FileName) && !string.Equals(a.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)); + if (!missingFiles.Any()) { - Directory.CreateDirectory(outputFolder); - } - else - { - var fileNames = Directory.GetFiles(outputFolder, "*", SearchOption.TopDirectoryOnly).Select(f => Path.GetFileName(f)); - var missingFiles = mediaSource.MediaAttachments.Where(a => !fileNames.Contains(a.FileName) && !string.Equals(a.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)); - if (!missingFiles.Any()) - { - // Skip extraction if all files already exist - return; - } + // Skip extraction if all files already exist + return; } var processArgs = string.Format( diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs index 566b521dd..34ac7dc83 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs @@ -50,7 +50,7 @@ public interface IJellyfinDatabaseProvider /// /// Runs a full Database backup that can later be restored to. /// - /// A cancelation token. + /// A cancellation token. /// A key to identify the backup. /// May throw an NotImplementException if this operation is not supported for this database. Task MigrationBackupFast(CancellationToken cancellationToken); @@ -59,7 +59,7 @@ public interface IJellyfinDatabaseProvider /// Restores a backup that has been previously created by . /// /// The key to the backup from which the current database should be restored from. - /// A cancelation token. + /// A cancellation token. /// A representing the result of the asynchronous operation. Task RestoreBackupFast(string key, CancellationToken cancellationToken); } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs index 927ba63b9..ef1bf1769 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs @@ -98,10 +98,7 @@ public sealed class SqliteDatabaseProvider : IJellyfinDatabaseProvider var key = DateTime.UtcNow.ToString("yyyyMMddhhmmss", CultureInfo.InvariantCulture); var path = Path.Combine(_applicationPaths.DataPath, "jellyfin.db"); var backupFile = Path.Combine(_applicationPaths.DataPath, BackupFolderName); - if (!Directory.Exists(backupFile)) - { - Directory.CreateDirectory(backupFile); - } + Directory.CreateDirectory(backupFile); backupFile = Path.Combine(backupFile, $"{key}_jellyfin.db"); File.Copy(path, backupFile); @@ -118,7 +115,7 @@ public sealed class SqliteDatabaseProvider : IJellyfinDatabaseProvider if (!File.Exists(backupFile)) { - _logger.LogCritical("Tried to restore a backup that does not exist."); + _logger.LogCritical("Tried to restore a backup that does not exist: {Key}", key); return Task.CompletedTask; } -- cgit v1.2.3 From 2e467f29de1d33eaf7e59b1296c79fa1e8373d45 Mon Sep 17 00:00:00 2001 From: gnattu Date: Sat, 26 Apr 2025 23:36:40 +0800 Subject: Don't pass through timestamp for image extractor (#13999) --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 39c0bfed4..2c57cf871 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -756,7 +756,7 @@ namespace MediaBrowser.MediaEncoding.Encoder _threads, vf, isAudio ? string.Empty : GetImageResolutionParameter(), - EncodingHelper.GetVideoSyncOption("0", EncoderVersion).Trim(), // passthrough timestamp + EncodingHelper.GetVideoSyncOption("-1", EncoderVersion).Trim(), // auto decide fps mode tempExtractPath); if (offset.HasValue) -- cgit v1.2.3 From f576783ae11d66ab1c4437dd975eefeea638bb3f Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Sun, 27 Apr 2025 02:49:30 +0200 Subject: Fix distinction queries (#14007) --- Emby.Server.Implementations/IO/FileRefresher.cs | 2 +- Emby.Server.Implementations/IO/LibraryMonitor.cs | 2 +- .../Library/LibraryManager.cs | 6 ++-- Jellyfin.Api/Controllers/ItemUpdateController.cs | 8 ++--- Jellyfin.Api/Controllers/YearsController.cs | 2 +- MediaBrowser.Controller/Entities/BaseItem.cs | 2 +- MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 2 +- .../Encoder/EncoderValidator.cs | 30 +++++++++---------- MediaBrowser.Providers/Manager/MetadataService.cs | 8 ++--- .../Music/AlbumMetadataService.cs | 2 +- .../Music/AudioMetadataService.cs | 2 +- .../Music/MusicVideoMetadataService.cs | 3 +- .../Playlists/PlaylistItemsProvider.cs | 2 +- src/Jellyfin.LiveTv/LiveTvManager.cs | 34 +++++++++++----------- .../Recordings/RecordingsManager.cs | 2 +- 15 files changed, 54 insertions(+), 53 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs index 7378cf885..f63408403 100644 --- a/Emby.Server.Implementations/IO/FileRefresher.cs +++ b/Emby.Server.Implementations/IO/FileRefresher.cs @@ -130,7 +130,7 @@ namespace Emby.Server.Implementations.IO private void ProcessPathChanges(List paths) { IEnumerable itemsToRefresh = paths - .Distinct(StringComparer.OrdinalIgnoreCase) + .Distinct() .Select(GetAffectedBaseItem) .Where(item => item is not null) .DistinctBy(x => x!.Id)!; // Removed null values in the previous .Where() diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs index 6af2a553d..d87ad729e 100644 --- a/Emby.Server.Implementations/IO/LibraryMonitor.cs +++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs @@ -121,7 +121,7 @@ namespace Emby.Server.Implementations.IO .Where(IsLibraryMonitorEnabled) .OfType() .SelectMany(f => f.PhysicalLocations) - .Distinct(StringComparer.OrdinalIgnoreCase) + .Distinct() .Order(); foreach (var path in paths) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 21c953fb2..64a96c4e5 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -668,10 +668,10 @@ namespace Emby.Server.Implementations.Library var list = originalList.Where(i => i.IsDirectory) .Select(i => Path.TrimEndingDirectorySeparator(i.FullName)) - .Distinct(StringComparer.OrdinalIgnoreCase) + .Distinct() .ToList(); - var dupes = list.Where(subPath => !subPath.EndsWith(":\\", StringComparison.OrdinalIgnoreCase) && list.Any(i => _fileSystem.ContainsSubPath(i, subPath))) + var dupes = list.Where(subPath => !subPath.EndsWith(":\\", StringComparison.Ordinal) && list.Any(i => _fileSystem.ContainsSubPath(i, subPath))) .ToList(); foreach (var dupe in dupes) @@ -679,7 +679,7 @@ namespace Emby.Server.Implementations.Library _logger.LogInformation("Found duplicate path: {0}", dupe); } - var newList = list.Except(dupes, StringComparer.OrdinalIgnoreCase).Select(_fileSystem.GetDirectoryInfo).ToList(); + var newList = list.Except(dupes, StringComparer.Ordinal).Select(_fileSystem.GetDirectoryInfo).ToList(); newList.AddRange(originalList.Where(i => !i.IsDirectory)); return newList; } diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index d49e0753e..50eeaeac6 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -299,7 +299,7 @@ public class ItemUpdateController : BaseJellyfinApiController if (!season.LockedFields.Contains(MetadataField.Tags)) { - season.Tags = season.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + season.Tags = season.Tags.Concat(addedTags).Except(removedTags).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } season.OnMetadataChanged(); @@ -316,7 +316,7 @@ public class ItemUpdateController : BaseJellyfinApiController if (!ep.LockedFields.Contains(MetadataField.Tags)) { - ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } ep.OnMetadataChanged(); @@ -337,7 +337,7 @@ public class ItemUpdateController : BaseJellyfinApiController if (!ep.LockedFields.Contains(MetadataField.Tags)) { - ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } ep.OnMetadataChanged(); @@ -357,7 +357,7 @@ public class ItemUpdateController : BaseJellyfinApiController if (!track.LockedFields.Contains(MetadataField.Tags)) { - track.Tags = track.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + track.Tags = track.Tags.Concat(addedTags).Except(removedTags).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } track.OnMetadataChanged(); diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index ebf98da45..b60258586 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -223,6 +223,6 @@ public class YearsController : BaseJellyfinApiController .Select(i => i.ProductionYear ?? 0) .Where(i => i > 0) .Distinct() - .Select(year => _libraryManager.GetYear(year)); + .Select(_libraryManager.GetYear); } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index a7ff75bb1..b90ec8222 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1804,7 +1804,7 @@ namespace MediaBrowser.Controller.Entities public void SetStudios(IEnumerable names) { - Studios = names.Trimmed().Distinct().ToArray(); + Studios = names.Trimmed().Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } /// diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index d656fccb4..dd5852823 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -197,7 +197,7 @@ namespace MediaBrowser.Controller.Entities.Movies var expandedFolders = new List(); return FlattenItems(this, expandedFolders) - .SelectMany(i => LibraryManager.GetCollectionFolders(i)) + .SelectMany(LibraryManager.GetCollectionFolders) .Select(i => i.Id) .Distinct() .ToArray(); diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index d28cd70ef..5683de169 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -14,8 +14,8 @@ namespace MediaBrowser.MediaEncoding.Encoder { public partial class EncoderValidator { - private static readonly string[] _requiredDecoders = new[] - { + private static readonly string[] _requiredDecoders = + [ "h264", "hevc", "vp8", @@ -57,10 +57,10 @@ namespace MediaBrowser.MediaEncoding.Encoder "vp8_rkmpp", "vp9_rkmpp", "av1_rkmpp" - }; + ]; - private static readonly string[] _requiredEncoders = new[] - { + private static readonly string[] _requiredEncoders = + [ "libx264", "libx265", "libsvtav1", @@ -97,10 +97,10 @@ namespace MediaBrowser.MediaEncoding.Encoder "h264_rkmpp", "hevc_rkmpp", "mjpeg_rkmpp" - }; + ]; - private static readonly string[] _requiredFilters = new[] - { + private static readonly string[] _requiredFilters = + [ // sw "alphasrc", "zscale", @@ -148,7 +148,7 @@ namespace MediaBrowser.MediaEncoding.Encoder "scale_rkrga", "vpp_rkrga", "overlay_rkrga" - }; + ]; private static readonly Dictionary _filterOptionsDict = new Dictionary { @@ -471,10 +471,10 @@ namespace MediaBrowser.MediaEncoding.Encoder if (string.IsNullOrWhiteSpace(output)) { - return Enumerable.Empty(); + return []; } - var found = output.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Skip(1).Distinct().ToList(); + var found = output.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries).Skip(1).Distinct().ToList(); _logger.LogInformation("Available hwaccel types: {Types}", found); return found; @@ -580,12 +580,12 @@ namespace MediaBrowser.MediaEncoding.Encoder catch (Exception ex) { _logger.LogError(ex, "Error detecting available {Codec}", codecstr); - return Enumerable.Empty(); + return []; } if (string.IsNullOrWhiteSpace(output)) { - return Enumerable.Empty(); + return []; } var required = codec == Codec.Encoder ? _requiredEncoders : _requiredDecoders; @@ -610,12 +610,12 @@ namespace MediaBrowser.MediaEncoding.Encoder catch (Exception ex) { _logger.LogError(ex, "Error detecting available filters"); - return Enumerable.Empty(); + return []; } if (string.IsNullOrWhiteSpace(output)) { - return Enumerable.Empty(); + return []; } var found = FilterRegex() diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 413bf2d30..50bbf0974 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -1041,7 +1041,7 @@ namespace MediaBrowser.Providers.Manager } else { - target.Studios = target.Studios.Concat(source.Studios).Distinct().ToArray(); + target.Studios = target.Studios.Concat(source.Studios).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } } @@ -1053,7 +1053,7 @@ namespace MediaBrowser.Providers.Manager } else { - target.Tags = target.Tags.Concat(source.Tags).Distinct().ToArray(); + target.Tags = target.Tags.Concat(source.Tags).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } } @@ -1065,7 +1065,7 @@ namespace MediaBrowser.Providers.Manager } else { - target.ProductionLocations = target.ProductionLocations.Concat(source.ProductionLocations).Distinct().ToArray(); + target.ProductionLocations = target.ProductionLocations.Concat(source.ProductionLocations).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } } @@ -1214,7 +1214,7 @@ namespace MediaBrowser.Providers.Manager } else if (sourceHasAlbumArtist.AlbumArtists.Count > 0) { - targetHasAlbumArtist.AlbumArtists = targetHasAlbumArtist.AlbumArtists.Concat(sourceHasAlbumArtist.AlbumArtists).Distinct().ToArray(); + targetHasAlbumArtist.AlbumArtists = targetHasAlbumArtist.AlbumArtists.Concat(sourceHasAlbumArtist.AlbumArtists).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } } } diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs index 0bcc301cb..64b627367 100644 --- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs +++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs @@ -227,7 +227,7 @@ namespace MediaBrowser.Providers.Music } else { - targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct().ToArray(); + targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } if (replaceData || string.IsNullOrEmpty(targetItem.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist))) diff --git a/MediaBrowser.Providers/Music/AudioMetadataService.cs b/MediaBrowser.Providers/Music/AudioMetadataService.cs index 7b25bc0e4..71962d952 100644 --- a/MediaBrowser.Providers/Music/AudioMetadataService.cs +++ b/MediaBrowser.Providers/Music/AudioMetadataService.cs @@ -63,7 +63,7 @@ namespace MediaBrowser.Providers.Music } else { - targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct().ToArray(); + targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } if (replaceData || string.IsNullOrEmpty(targetItem.Album)) diff --git a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs index 24c4b5501..4022bedc1 100644 --- a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs +++ b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System; using System.Linq; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -48,7 +49,7 @@ namespace MediaBrowser.Providers.Music } else { - targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct().ToArray(); + targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } } } diff --git a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs index 51a3ba0c7..a986b0b69 100644 --- a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs +++ b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs @@ -99,7 +99,7 @@ public class PlaylistItemsProvider : ILocalMetadataProvider, .OfType() .Where(f => f.CollectionType.HasValue && !_ignoredCollections.Contains(f.CollectionType.Value)) .SelectMany(f => f.PhysicalLocations) - .Distinct(StringComparer.OrdinalIgnoreCase) + .Distinct() .ToList(); using (var stream = File.OpenRead(path)) diff --git a/src/Jellyfin.LiveTv/LiveTvManager.cs b/src/Jellyfin.LiveTv/LiveTvManager.cs index 40adb51a5..53bc6751f 100644 --- a/src/Jellyfin.LiveTv/LiveTvManager.cs +++ b/src/Jellyfin.LiveTv/LiveTvManager.cs @@ -125,8 +125,8 @@ namespace Jellyfin.LiveTv IsKids = query.IsKids, IsSports = query.IsSports, IsSeries = query.IsSeries, - IncludeItemTypes = new[] { BaseItemKind.LiveTvChannel }, - TopParentIds = new[] { topFolder.Id }, + IncludeItemTypes = [BaseItemKind.LiveTvChannel], + TopParentIds = [topFolder.Id], IsFavorite = query.IsFavorite, IsLiked = query.IsLiked, StartIndex = query.StartIndex, @@ -199,17 +199,17 @@ namespace Jellyfin.LiveTv if (query.OrderBy.Count == 0) { // Unless something else was specified, order by start date to take advantage of a specialized index - query.OrderBy = new[] - { + query.OrderBy = + [ (ItemSortBy.StartDate, SortOrder.Ascending) - }; + ]; } RemoveFields(options); var internalQuery = new InternalItemsQuery(user) { - IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram }, + IncludeItemTypes = [BaseItemKind.LiveTvProgram], MinEndDate = query.MinEndDate, MinStartDate = query.MinStartDate, MaxEndDate = query.MaxEndDate, @@ -226,7 +226,7 @@ namespace Jellyfin.LiveTv Limit = query.Limit, OrderBy = query.OrderBy, EnableTotalRecordCount = query.EnableTotalRecordCount, - TopParentIds = new[] { topFolder.Id }, + TopParentIds = [topFolder.Id], Name = query.Name, DtoOptions = options, HasAired = query.HasAired, @@ -272,7 +272,7 @@ namespace Jellyfin.LiveTv var internalQuery = new InternalItemsQuery(user) { - IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram }, + IncludeItemTypes = [BaseItemKind.LiveTvProgram], IsAiring = query.IsAiring, HasAired = query.HasAired, IsNews = query.IsNews, @@ -281,8 +281,8 @@ namespace Jellyfin.LiveTv IsSports = query.IsSports, IsKids = query.IsKids, EnableTotalRecordCount = query.EnableTotalRecordCount, - OrderBy = new[] { (ItemSortBy.StartDate, SortOrder.Ascending) }, - TopParentIds = new[] { topFolder.Id }, + OrderBy = [(ItemSortBy.StartDate, SortOrder.Ascending)], + TopParentIds = [topFolder.Id], DtoOptions = options, GenreIds = query.GenreIds }; @@ -497,19 +497,19 @@ namespace Jellyfin.LiveTv // TotalRecordCount = items.Length // }; - dtoOptions.Fields = dtoOptions.Fields.Concat(new[] { ItemFields.Tags }).Distinct().ToArray(); + dtoOptions.Fields = dtoOptions.Fields.Concat([ItemFields.Tags]).Distinct().ToArray(); } var result = _libraryManager.GetItemsResult(new InternalItemsQuery(user) { - MediaTypes = new[] { MediaType.Video }, + MediaTypes = [MediaType.Video], Recursive = true, AncestorIds = folderIds, IsFolder = false, IsVirtualItem = false, Limit = limit, StartIndex = query.StartIndex, - OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending) }, + OrderBy = [(ItemSortBy.DateCreated, SortOrder.Descending)], EnableTotalRecordCount = query.EnableTotalRecordCount, IncludeItemTypes = includeItemTypes.ToArray(), ExcludeItemTypes = excludeItemTypes.ToArray(), @@ -959,13 +959,13 @@ namespace Jellyfin.LiveTv var programs = options.AddCurrentProgram ? _libraryManager.GetItemList(new InternalItemsQuery(user) { - IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram }, + IncludeItemTypes = [BaseItemKind.LiveTvProgram], ChannelIds = channelIds, MaxStartDate = now, MinEndDate = now, Limit = channelIds.Length, - OrderBy = new[] { (ItemSortBy.StartDate, SortOrder.Ascending) }, - TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Id }, + OrderBy = [(ItemSortBy.StartDate, SortOrder.Ascending)], + TopParentIds = [GetInternalLiveTvFolder(CancellationToken.None).Id], DtoOptions = options }) : new List(); @@ -1269,7 +1269,7 @@ namespace Jellyfin.LiveTv { var folders = _recordingsManager.GetRecordingFolders() .SelectMany(i => i.Locations) - .Distinct(StringComparer.OrdinalIgnoreCase) + .Distinct() .Select(i => _libraryManager.FindByPath(i, true)) .Where(i => i is not null && i.IsVisibleStandalone(user)) .SelectMany(i => _libraryManager.GetCollectionFolders(i)) diff --git a/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs b/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs index 9ca5d7420..846f9baf7 100644 --- a/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs +++ b/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs @@ -230,7 +230,7 @@ public sealed class RecordingsManager : IRecordingsManager, IDisposable if (pathsAdded.Count > 0 || pathsToRemove.Count > 0) { pathsAdded.InsertRange(0, config.MediaLocationsCreated); - config.MediaLocationsCreated = pathsAdded.Except(pathsToRemove).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); + config.MediaLocationsCreated = pathsAdded.Except(pathsToRemove).Distinct().ToArray(); _config.SaveConfiguration("livetv", config); } -- cgit v1.2.3 From 66371021624223645db84858635fbf4f0112736d Mon Sep 17 00:00:00 2001 From: gnattu Date: Sun, 27 Apr 2025 21:30:02 +0800 Subject: Correctly handle retry when I frame only failed --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 2c57cf871..80dd080d5 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -767,7 +767,7 @@ namespace MediaBrowser.MediaEncoding.Encoder // The mpegts demuxer cannot seek to keyframes, so we have to let the // decoder discard non-keyframes, which may contain corrupted images. var seekMpegTs = offset.HasValue && string.Equals("mpegts", container, StringComparison.OrdinalIgnoreCase); - if ((useIFrame && useTradeoff) || seekMpegTs) + if (useIFrame && (useTradeoff || seekMpegTs)) { args = "-skip_frame nokey " + args; } -- cgit v1.2.3 From 77bb1a726e97e093d9249bf4f6efea30af30896c Mon Sep 17 00:00:00 2001 From: gnattu Date: Sun, 27 Apr 2025 21:36:57 +0800 Subject: Use full range output for image --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 80dd080d5..74d512256 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -737,12 +737,12 @@ namespace MediaBrowser.MediaEncoding.Encoder { var peak = videoStream.VideoRangeType == VideoRangeType.DOVI ? "400" : "100"; enableHdrExtraction = true; - filters.Add($"tonemapx=tonemap=bt2390:desat=0:peak={peak}:t=bt709:m=bt709:p=bt709:format=yuv420p"); + filters.Add($"tonemapx=tonemap=bt2390:desat=0:peak={peak}:t=bt709:m=bt709:p=bt709:format=yuv420p:range=full"); } else if (SupportsFilter("zscale") && videoStream.VideoRangeType != VideoRangeType.DOVI) { enableHdrExtraction = true; - filters.Add("zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0:peak=100,zscale=t=bt709:m=bt709,format=yuv420p"); + filters.Add("zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0:peak=100,zscale=t=bt709:m=bt709:out_range=full,format=yuv420p"); } } -- cgit v1.2.3 From f436743f9fc122ad8c247f2488c6e888e80cecff Mon Sep 17 00:00:00 2001 From: gnattu Date: Sun, 27 Apr 2025 21:37:44 +0800 Subject: Don't trim image extractor option --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 74d512256..bf574a06f 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -756,7 +756,7 @@ namespace MediaBrowser.MediaEncoding.Encoder _threads, vf, isAudio ? string.Empty : GetImageResolutionParameter(), - EncodingHelper.GetVideoSyncOption("-1", EncoderVersion).Trim(), // auto decide fps mode + EncodingHelper.GetVideoSyncOption("-1", EncoderVersion), // auto decide fps mode tempExtractPath); if (offset.HasValue) -- cgit v1.2.3 From 4199f7acc24c60942a68039b48fc272e8f767acf Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Sat, 3 May 2025 14:21:08 +0000 Subject: Fix the transparency issue of ASS subtitle rendering in HWA (#14024) --- .../MediaEncoding/EncodingHelper.cs | 15 ++++++++-- .../MediaEncoding/FilterOptionType.cs | 12 +++++++- .../Encoder/EncoderValidator.cs | 35 ++++++++-------------- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 11 ++----- 4 files changed, 38 insertions(+), 35 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 7c3138002..0bc922cbb 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -3947,6 +3947,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (hasSubs) { + var alphaFormatOpt = string.Empty; if (hasGraphicalSubs) { var subPreProcFilters = GetGraphicalSubPreProcessFilters(swpInW, swpInH, subW, subH, reqW, reqH, reqMaxW, reqMaxH); @@ -3964,10 +3965,13 @@ namespace MediaBrowser.Controller.MediaEncoding subFilters.Add(alphaSrcFilter); subFilters.Add("format=yuva420p"); subFilters.Add(subTextSubtitlesFilter); + + alphaFormatOpt = _mediaEncoder.SupportsFilterWithOption(FilterOptionType.OverlayCudaAlphaFormat) + ? ":alpha_format=premultiplied" : string.Empty; } subFilters.Add("hwupload=derive_device=cuda"); - overlayFilters.Add("overlay_cuda=eof_action=pass:repeatlast=0"); + overlayFilters.Add($"overlay_cuda=eof_action=pass:repeatlast=0{alphaFormatOpt}"); } } else @@ -4164,6 +4168,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (hasSubs) { + var alphaFormatOpt = string.Empty; if (hasGraphicalSubs) { var subPreProcFilters = GetGraphicalSubPreProcessFilters(swpInW, swpInH, subW, subH, reqW, reqH, reqMaxW, reqMaxH); @@ -4181,10 +4186,13 @@ namespace MediaBrowser.Controller.MediaEncoding subFilters.Add(alphaSrcFilter); subFilters.Add("format=yuva420p"); subFilters.Add(subTextSubtitlesFilter); + + alphaFormatOpt = _mediaEncoder.SupportsFilterWithOption(FilterOptionType.OverlayOpenclAlphaFormat) + ? ":alpha_format=premultiplied" : string.Empty; } subFilters.Add("hwupload=derive_device=opencl"); - overlayFilters.Add("overlay_opencl=eof_action=pass:repeatlast=0"); + overlayFilters.Add($"overlay_opencl=eof_action=pass:repeatlast=0{alphaFormatOpt}"); overlayFilters.Add("hwmap=derive_device=d3d11va:mode=write:reverse=1"); overlayFilters.Add("format=d3d11"); } @@ -6947,7 +6955,8 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(videoStream.Codec, "av1", StringComparison.OrdinalIgnoreCase)) { - return GetHwaccelType(state, options, "av1", bitDepth, hwSurface); + var accelType = GetHwaccelType(state, options, "av1", bitDepth, hwSurface); + return accelType + ((!string.IsNullOrEmpty(accelType) && isAfbcSupported) ? " -afbc rga" : string.Empty); } } diff --git a/MediaBrowser.Controller/MediaEncoding/FilterOptionType.cs b/MediaBrowser.Controller/MediaEncoding/FilterOptionType.cs index a2b6e1d73..6ad953023 100644 --- a/MediaBrowser.Controller/MediaEncoding/FilterOptionType.cs +++ b/MediaBrowser.Controller/MediaEncoding/FilterOptionType.cs @@ -38,6 +38,16 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// The transpose_opencl_reversal. /// - TransposeOpenclReversal = 6 + TransposeOpenclReversal = 6, + + /// + /// The overlay_opencl_alpha_format. + /// + OverlayOpenclAlphaFormat = 7, + + /// + /// The overlay_cuda_alpha_format. + /// + OverlayCudaAlphaFormat = 8 } } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 5683de169..77fd1bcd2 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -150,15 +150,17 @@ namespace MediaBrowser.MediaEncoding.Encoder "overlay_rkrga" ]; - private static readonly Dictionary _filterOptionsDict = new Dictionary + private static readonly Dictionary _filterOptionsDict = new Dictionary { - { 0, new string[] { "scale_cuda", "format" } }, - { 1, new string[] { "tonemap_cuda", "GPU accelerated HDR to SDR tonemapping" } }, - { 2, new string[] { "tonemap_opencl", "bt2390" } }, - { 3, new string[] { "overlay_opencl", "Action to take when encountering EOF from secondary input" } }, - { 4, new string[] { "overlay_vaapi", "Action to take when encountering EOF from secondary input" } }, - { 5, new string[] { "overlay_vulkan", "Action to take when encountering EOF from secondary input" } }, - { 6, new string[] { "transpose_opencl", "rotate by half-turn" } } + { FilterOptionType.ScaleCudaFormat, ("scale_cuda", "format") }, + { FilterOptionType.TonemapCudaName, ("tonemap_cuda", "GPU accelerated HDR to SDR tonemapping") }, + { FilterOptionType.TonemapOpenclBt2390, ("tonemap_opencl", "bt2390") }, + { FilterOptionType.OverlayOpenclFrameSync, ("overlay_opencl", "Action to take when encountering EOF from secondary input") }, + { FilterOptionType.OverlayVaapiFrameSync, ("overlay_vaapi", "Action to take when encountering EOF from secondary input") }, + { FilterOptionType.OverlayVulkanFrameSync, ("overlay_vulkan", "Action to take when encountering EOF from secondary input") }, + { FilterOptionType.TransposeOpenclReversal, ("transpose_opencl", "rotate by half-turn") }, + { FilterOptionType.OverlayOpenclAlphaFormat, ("overlay_opencl", "alpha_format") }, + { FilterOptionType.OverlayCudaAlphaFormat, ("overlay_cuda", "alpha_format") } }; private static readonly Dictionary _bsfOptionsDict = new Dictionary @@ -294,7 +296,8 @@ namespace MediaBrowser.MediaEncoding.Encoder public IEnumerable GetFilters() => GetFFmpegFilters(); - public IDictionary GetFiltersWithOption() => GetFFmpegFiltersWithOption(); + public IDictionary GetFiltersWithOption() => _filterOptionsDict + .ToDictionary(item => item.Key, item => CheckFilterWithOption(item.Value.Item1, item.Value.Item2)); public IDictionary GetBitStreamFiltersWithOption() => _bsfOptionsDict .ToDictionary(item => item.Key, item => CheckBitStreamFilterWithOption(item.Value.Item1, item.Value.Item2)); @@ -628,20 +631,6 @@ namespace MediaBrowser.MediaEncoding.Encoder return found; } - private Dictionary GetFFmpegFiltersWithOption() - { - Dictionary dict = new Dictionary(); - for (int i = 0; i < _filterOptionsDict.Count; i++) - { - if (_filterOptionsDict.TryGetValue(i, out var val) && val.Length == 2) - { - dict.Add(i, CheckFilterWithOption(val[0], val[1])); - } - } - - return dict; - } - private string GetProcessOutput(string path, string arguments, bool readStdErr, string? testKey) { var redirectStandardIn = !string.IsNullOrEmpty(testKey); diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index bf574a06f..897652fcd 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -72,7 +72,7 @@ namespace MediaBrowser.MediaEncoding.Encoder private List _decoders = new List(); private List _hwaccels = new List(); private List _filters = new List(); - private IDictionary _filtersWithOption = new Dictionary(); + private IDictionary _filtersWithOption = new Dictionary(); private IDictionary _bitStreamFiltersWithOption = new Dictionary(); private bool _isPkeyPauseSupported = false; @@ -341,7 +341,7 @@ namespace MediaBrowser.MediaEncoding.Encoder _filters = list.ToList(); } - public void SetAvailableFiltersWithOption(IDictionary dict) + public void SetAvailableFiltersWithOption(IDictionary dict) { _filtersWithOption = dict; } @@ -383,12 +383,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// public bool SupportsFilterWithOption(FilterOptionType option) { - if (_filtersWithOption.TryGetValue((int)option, out var val)) - { - return val; - } - - return false; + return _filtersWithOption.TryGetValue(option, out var val) && val; } public bool SupportsBitStreamFilterWithOption(BitStreamFilterOptionType option) -- cgit v1.2.3 From 0c3ba30de214eddcd6118c3b695b08e5482bf7ed Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Sun, 4 May 2025 16:40:34 +0200 Subject: Cleanup file related code (#14023) --- .../AppBase/BaseApplicationPaths.cs | 8 ++-- .../IO/ManagedFileSystem.cs | 8 ++-- .../Library/DotIgnoreIgnoreRule.cs | 2 +- .../Library/LibraryManager.cs | 2 +- .../Library/MediaSourceManager.cs | 12 +++--- .../Localization/LocalizationManager.cs | 2 +- Jellyfin.Api/Controllers/SyncPlayController.cs | 2 +- .../StorageHelpers/StorageHelper.cs | 5 +-- .../Trickplay/TrickplayManager.cs | 48 +++++++++++----------- .../Extensions/ApiServiceCollectionExtensions.cs | 2 +- .../Attachments/AttachmentExtractor.cs | 6 +-- MediaBrowser.Model/IO/AsyncFile.cs | 8 ++++ src/Jellyfin.Extensions/FileHelper.cs | 20 +++++++++ src/Jellyfin.LiveTv/Channels/ChannelManager.cs | 4 +- tests/Jellyfin.Extensions.Tests/FileHelperTests.cs | 23 +++++++++++ .../Plugins/PluginManagerTests.cs | 5 ++- .../OpenApiSpecTests.cs | 3 +- 17 files changed, 104 insertions(+), 56 deletions(-) create mode 100644 src/Jellyfin.Extensions/FileHelper.cs create mode 100644 tests/Jellyfin.Extensions.Tests/FileHelperTests.cs (limited to 'MediaBrowser.MediaEncoding') diff --git a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs index d1376f18a..18ebd628d 100644 --- a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs +++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; namespace Emby.Server.Implementations.AppBase @@ -91,10 +92,7 @@ namespace Emby.Server.Implementations.AppBase /// public void CreateAndCheckMarker(string path, string markerName, bool recursive = false) { - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } + Directory.CreateDirectory(path); CheckOrCreateMarker(path, $".jellyfin-{markerName}", recursive); } @@ -115,7 +113,7 @@ namespace Emby.Server.Implementations.AppBase var markerPath = Path.Combine(path, markerName); if (!File.Exists(markerPath)) { - File.Create(markerPath).Dispose(); + FileHelper.CreateEmpty(markerPath); } } } diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index ac5933a69..077eb7945 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -159,13 +159,13 @@ namespace Emby.Server.Implementations.IO catch (IOException) { // Cross device move requires a copy - Directory.CreateDirectory(destination); - foreach (string file in Directory.GetFiles(source)) + var directory = Directory.CreateDirectory(destination); + foreach (var file in directory.EnumerateFiles()) { - File.Copy(file, Path.Combine(destination, Path.GetFileName(file)), true); + file.CopyTo(Path.Combine(destination, file.Name), true); } - Directory.Delete(source, true); + directory.Delete(true); } } diff --git a/Emby.Server.Implementations/Library/DotIgnoreIgnoreRule.cs b/Emby.Server.Implementations/Library/DotIgnoreIgnoreRule.cs index 2c186c917..b0ed1de8d 100644 --- a/Emby.Server.Implementations/Library/DotIgnoreIgnoreRule.cs +++ b/Emby.Server.Implementations/Library/DotIgnoreIgnoreRule.cs @@ -20,7 +20,7 @@ public class DotIgnoreIgnoreRule : IResolverIgnoreRule } var parentDir = directory.Parent; - if (parentDir == null || parentDir.FullName == directory.FullName) + if (parentDir is null) { return null; } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 64a96c4e5..51f330746 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2945,7 +2945,7 @@ namespace Emby.Server.Implementations.Library { var path = Path.Combine(virtualFolderPath, collectionType.ToString()!.ToLowerInvariant() + ".collection"); // Can't be null with legal values? - await File.WriteAllBytesAsync(path, []).ConfigureAwait(false); + FileHelper.CreateEmpty(path); } CollectionFolder.SaveLibraryOptions(virtualFolderPath, options); diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index c6cfd5391..ab30971e2 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -681,17 +681,17 @@ namespace Emby.Server.Implementations.Library mediaInfo = await _mediaEncoder.GetMediaInfo( new MediaInfoRequest - { - MediaSource = mediaSource, - MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, - ExtractChapters = false - }, + { + MediaSource = mediaSource, + MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, + ExtractChapters = false + }, cancellationToken).ConfigureAwait(false); if (cacheFilePath is not null) { Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); - FileStream createStream = File.Create(cacheFilePath); + FileStream createStream = AsyncFile.Create(cacheFilePath); await using (createStream.ConfigureAwait(false)) { await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 17db7ad4c..242f2af56 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -520,7 +520,7 @@ namespace Emby.Server.Implementations.Localization public bool TryGetISO6392TFromB(string isoB, [NotNullWhen(true)] out string? isoT) { // Unlikely case the dictionary is not (yet) initialized properly - if (_iso6392BtoT == null) + if (_iso6392BtoT is null) { isoT = null; return false; diff --git a/Jellyfin.Api/Controllers/SyncPlayController.cs b/Jellyfin.Api/Controllers/SyncPlayController.cs index fbab2a784..3d6874079 100644 --- a/Jellyfin.Api/Controllers/SyncPlayController.cs +++ b/Jellyfin.Api/Controllers/SyncPlayController.cs @@ -125,7 +125,7 @@ public class SyncPlayController : BaseJellyfinApiController { var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(false); var group = _syncPlayManager.GetGroup(currentSession, id); - return group == null ? NotFound() : Ok(group); + return group is null ? NotFound() : Ok(group); } /// diff --git a/Jellyfin.Server.Implementations/StorageHelpers/StorageHelper.cs b/Jellyfin.Server.Implementations/StorageHelpers/StorageHelper.cs index e351160c1..b2f54be7e 100644 --- a/Jellyfin.Server.Implementations/StorageHelpers/StorageHelper.cs +++ b/Jellyfin.Server.Implementations/StorageHelpers/StorageHelper.cs @@ -72,10 +72,7 @@ public static class StorageHelper private static void TestDataDirectorySize(string path, ILogger logger, long threshold = -1) { logger.LogDebug("Check path {TestPath} for storage capacity", path); - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } + Directory.CreateDirectory(path); var drive = new DriveInfo(path); if (threshold != -1 && drive.AvailableFreeSpace < threshold) diff --git a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs index bf39f13a7..f7dd92e01 100644 --- a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs +++ b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs @@ -97,28 +97,28 @@ public class TrickplayManager : ITrickplayManager var existingResolution = resolution.Key; var tileWidth = resolution.Value.TileWidth; var tileHeight = resolution.Value.TileHeight; - var shouldBeSavedWithMedia = libraryOptions is null ? false : libraryOptions.SaveTrickplayWithMedia; - var localOutputDir = GetTrickplayDirectory(video, tileWidth, tileHeight, existingResolution, false); - var mediaOutputDir = GetTrickplayDirectory(video, tileWidth, tileHeight, existingResolution, true); - if (shouldBeSavedWithMedia && Directory.Exists(localOutputDir)) + var shouldBeSavedWithMedia = libraryOptions is not null && libraryOptions.SaveTrickplayWithMedia; + var localOutputDir = new DirectoryInfo(GetTrickplayDirectory(video, tileWidth, tileHeight, existingResolution, false)); + var mediaOutputDir = new DirectoryInfo(GetTrickplayDirectory(video, tileWidth, tileHeight, existingResolution, true)); + if (shouldBeSavedWithMedia && localOutputDir.Exists) { - var localDirFiles = Directory.GetFiles(localOutputDir); - var mediaDirExists = Directory.Exists(mediaOutputDir); - if (localDirFiles.Length > 0 && ((mediaDirExists && Directory.GetFiles(mediaOutputDir).Length == 0) || !mediaDirExists)) + var localDirFiles = localOutputDir.EnumerateFiles(); + var mediaDirExists = mediaOutputDir.Exists; + if (localDirFiles.Any() && ((mediaDirExists && mediaOutputDir.EnumerateFiles().Any()) || !mediaDirExists)) { // Move images from local dir to media dir - MoveContent(localOutputDir, mediaOutputDir); + MoveContent(localOutputDir.FullName, mediaOutputDir.FullName); _logger.LogInformation("Moved trickplay images for {ItemName} to {Location}", video.Name, mediaOutputDir); } } - else if (!shouldBeSavedWithMedia && Directory.Exists(mediaOutputDir)) + else if (!shouldBeSavedWithMedia && mediaOutputDir.Exists) { - var mediaDirFiles = Directory.GetFiles(mediaOutputDir); - var localDirExists = Directory.Exists(localOutputDir); - if (mediaDirFiles.Length > 0 && ((localDirExists && Directory.GetFiles(localOutputDir).Length == 0) || !localDirExists)) + var mediaDirFiles = mediaOutputDir.EnumerateFiles(); + var localDirExists = localOutputDir.Exists; + if (mediaDirFiles.Any() && ((localDirExists && localOutputDir.EnumerateFiles().Any()) || !localDirExists)) { // Move images from media dir to local dir - MoveContent(mediaOutputDir, localOutputDir); + MoveContent(mediaOutputDir.FullName, localOutputDir.FullName); _logger.LogInformation("Moved trickplay images for {ItemName} to {Location}", video.Name, localOutputDir); } } @@ -131,10 +131,10 @@ public class TrickplayManager : ITrickplayManager var parent = Directory.GetParent(sourceFolder); if (parent is not null) { - var parentContent = Directory.GetDirectories(parent.FullName); - if (parentContent.Length == 0) + var parentContent = parent.EnumerateDirectories(); + if (!parentContent.Any()) { - Directory.Delete(parent.FullName); + parent.Delete(); } } } @@ -220,13 +220,13 @@ public class TrickplayManager : ITrickplayManager var tileWidth = options.TileWidth; var tileHeight = options.TileHeight; - var saveWithMedia = libraryOptions is null ? false : libraryOptions.SaveTrickplayWithMedia; - var outputDir = GetTrickplayDirectory(video, tileWidth, tileHeight, actualWidth, saveWithMedia); + var saveWithMedia = libraryOptions is not null && libraryOptions.SaveTrickplayWithMedia; + var outputDir = new DirectoryInfo(GetTrickplayDirectory(video, tileWidth, tileHeight, actualWidth, saveWithMedia)); // Import existing trickplay tiles - if (!replace && Directory.Exists(outputDir)) + if (!replace && outputDir.Exists) { - var existingFiles = Directory.GetFiles(outputDir); + var existingFiles = outputDir.GetFiles(); if (existingFiles.Length > 0) { var hasTrickplayResolution = await HasTrickplayResolutionAsync(video.Id, actualWidth).ConfigureAwait(false); @@ -251,9 +251,9 @@ public class TrickplayManager : ITrickplayManager foreach (var tile in existingFiles) { - var image = _imageEncoder.GetImageSize(tile); + var image = _imageEncoder.GetImageSize(tile.FullName); localTrickplayInfo.Height = Math.Max(localTrickplayInfo.Height, (int)Math.Ceiling((double)image.Height / localTrickplayInfo.TileHeight)); - var bitrate = (int)Math.Ceiling((decimal)new FileInfo(tile).Length * 8 / localTrickplayInfo.TileWidth / localTrickplayInfo.TileHeight / (localTrickplayInfo.Interval / 1000)); + var bitrate = (int)Math.Ceiling((decimal)tile.Length * 8 / localTrickplayInfo.TileWidth / localTrickplayInfo.TileHeight / (localTrickplayInfo.Interval / 1000)); localTrickplayInfo.Bandwidth = Math.Max(localTrickplayInfo.Bandwidth, bitrate); } @@ -296,7 +296,7 @@ public class TrickplayManager : ITrickplayManager .ToList(); // Create tiles - var trickplayInfo = CreateTiles(images, actualWidth, options, outputDir); + var trickplayInfo = CreateTiles(images, actualWidth, options, outputDir.FullName); // Save tiles info try @@ -319,7 +319,7 @@ public class TrickplayManager : ITrickplayManager // Make sure no files stay in metadata folders on failure // if tiles info wasn't saved. - Directory.Delete(outputDir, true); + outputDir.Delete(true); } } catch (Exception ex) diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index b04e55baa..09a4e2ed3 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -215,7 +215,7 @@ namespace Jellyfin.Server.Extensions }); // Add all xml doc files to swagger generator. - var xmlFiles = Directory.GetFiles( + var xmlFiles = Directory.EnumerateFiles( AppContext.BaseDirectory, "*.xml", SearchOption.TopDirectoryOnly); diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 1f2bc2403..48a0654bb 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -133,9 +133,9 @@ namespace MediaBrowser.MediaEncoding.Attachments var outputFolder = _pathManager.GetAttachmentFolderPath(mediaSource.Id); using (await _semaphoreLocks.LockAsync(outputFolder, cancellationToken).ConfigureAwait(false)) { - Directory.CreateDirectory(outputFolder); - var fileNames = Directory.GetFiles(outputFolder, "*", SearchOption.TopDirectoryOnly).Select(f => Path.GetFileName(f)); - var missingFiles = mediaSource.MediaAttachments.Where(a => !fileNames.Contains(a.FileName) && !string.Equals(a.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)); + var directory = Directory.CreateDirectory(outputFolder); + var fileNames = directory.GetFiles("*", SearchOption.TopDirectoryOnly).Select(f => f.Name).ToHashSet(); + var missingFiles = mediaSource.MediaAttachments.Where(a => a.FileName is not null && !fileNames.Contains(a.FileName) && !string.Equals(a.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)); if (!missingFiles.Any()) { // Skip extraction if all files already exist diff --git a/MediaBrowser.Model/IO/AsyncFile.cs b/MediaBrowser.Model/IO/AsyncFile.cs index 3c8007d1c..a9db6b81c 100644 --- a/MediaBrowser.Model/IO/AsyncFile.cs +++ b/MediaBrowser.Model/IO/AsyncFile.cs @@ -26,6 +26,14 @@ namespace MediaBrowser.Model.IO Options = FileOptions.Asynchronous }; + /// + /// Creates, or truncates and overwrites, a file in the specified path. + /// + /// The path and name of the file to create. + /// A that provides read/write access to the file specified in path. + public static FileStream Create(string path) + => new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + /// /// Opens an existing file for reading. /// diff --git a/src/Jellyfin.Extensions/FileHelper.cs b/src/Jellyfin.Extensions/FileHelper.cs new file mode 100644 index 000000000..b1ccf8d47 --- /dev/null +++ b/src/Jellyfin.Extensions/FileHelper.cs @@ -0,0 +1,20 @@ +using System.IO; + +namespace Jellyfin.Extensions; + +/// +/// Provides helper functions for . +/// +public static class FileHelper +{ + /// + /// Creates, or truncates a file in the specified path. + /// + /// The path and name of the file to create. + public static void CreateEmpty(string path) + { + using (File.OpenHandle(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) + { + } + } +} diff --git a/src/Jellyfin.LiveTv/Channels/ChannelManager.cs b/src/Jellyfin.LiveTv/Channels/ChannelManager.cs index 0ca294a28..5addcd26e 100644 --- a/src/Jellyfin.LiveTv/Channels/ChannelManager.cs +++ b/src/Jellyfin.LiveTv/Channels/ChannelManager.cs @@ -363,7 +363,7 @@ namespace Jellyfin.LiveTv.Channels Directory.CreateDirectory(Path.GetDirectoryName(path)); - FileStream createStream = File.Create(path); + FileStream createStream = AsyncFile.Create(path); await using (createStream.ConfigureAwait(false)) { await JsonSerializer.SerializeAsync(createStream, mediaSources, _jsonOptions).ConfigureAwait(false); @@ -866,7 +866,7 @@ namespace Jellyfin.LiveTv.Channels { Directory.CreateDirectory(Path.GetDirectoryName(path)); - var createStream = File.Create(path); + var createStream = AsyncFile.Create(path); await using (createStream.ConfigureAwait(false)) { await JsonSerializer.SerializeAsync(createStream, result, _jsonOptions).ConfigureAwait(false); diff --git a/tests/Jellyfin.Extensions.Tests/FileHelperTests.cs b/tests/Jellyfin.Extensions.Tests/FileHelperTests.cs new file mode 100644 index 000000000..fb6a5dd0a --- /dev/null +++ b/tests/Jellyfin.Extensions.Tests/FileHelperTests.cs @@ -0,0 +1,23 @@ +using System.IO; +using Xunit; + +namespace Jellyfin.Extensions.Tests; + +public static class FileHelperTests +{ + [Fact] + public static void CreateEmpty_Valid_Correct() + { + var path = Path.Join(Path.GetTempPath(), Path.GetRandomFileName()); + var fileInfo = new FileInfo(path); + + Assert.False(fileInfo.Exists); + + FileHelper.CreateEmpty(path); + + fileInfo.Refresh(); + Assert.True(fileInfo.Exists); + + File.Delete(path); + } +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Plugins/PluginManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Plugins/PluginManagerTests.cs index 934024826..b289c763b 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Plugins/PluginManagerTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Plugins/PluginManagerTests.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using AutoFixture; using Emby.Server.Implementations.Library; using Emby.Server.Implementations.Plugins; +using Jellyfin.Extensions; using Jellyfin.Extensions.Json; using Jellyfin.Extensions.Json.Converters; using MediaBrowser.Common.Plugins; @@ -85,7 +86,7 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins var dllPath = Path.GetDirectoryName(Path.Combine(_pluginPath, dllFile))!; Directory.CreateDirectory(dllPath); - File.Create(Path.Combine(dllPath, filename)); + FileHelper.CreateEmpty(Path.Combine(dllPath, filename)); var metafilePath = Path.Combine(_pluginPath, "meta.json"); File.WriteAllText(metafilePath, JsonSerializer.Serialize(manifest, _options)); @@ -141,7 +142,7 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins foreach (var file in files) { - File.Create(Path.Combine(_pluginPath, file)); + FileHelper.CreateEmpty(Path.Combine(_pluginPath, file)); } var metafilePath = Path.Combine(_pluginPath, "meta.json"); diff --git a/tests/Jellyfin.Server.Integration.Tests/OpenApiSpecTests.cs b/tests/Jellyfin.Server.Integration.Tests/OpenApiSpecTests.cs index 98195a294..62cdd25ae 100644 --- a/tests/Jellyfin.Server.Integration.Tests/OpenApiSpecTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/OpenApiSpecTests.cs @@ -1,6 +1,7 @@ using System.IO; using System.Reflection; using System.Threading.Tasks; +using MediaBrowser.Model.IO; using Xunit; using Xunit.Abstractions; @@ -33,7 +34,7 @@ namespace Jellyfin.Server.Integration.Tests // Write out for publishing string outputPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "openapi.json")); _outputHelper.WriteLine("Writing OpenAPI Spec JSON to '{0}'.", outputPath); - await using var fs = File.Create(outputPath); + await using var fs = AsyncFile.Create(outputPath); await response.Content.CopyToAsync(fs); } } -- cgit v1.2.3 From d976f13970e034a24c1d0f69384501e31475a127 Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Mon, 5 May 2025 05:21:44 +0200 Subject: Recognize file changes and remove data on change (#13839) --- Emby.Server.Implementations/ApplicationHost.cs | 4 +- .../Collections/CollectionManager.cs | 8 +- .../Library/KeyframeManager.cs | 44 +++ .../Library/LibraryManager.cs | 122 +++--- Emby.Server.Implementations/Library/PathManager.cs | 14 + .../Library/ResolverHelper.cs | 20 +- .../Playlists/PlaylistManager.cs | 6 +- .../Tasks/MediaSegmentExtractionTask.cs | 2 +- .../Controllers/MediaSegmentsController.cs | 2 +- .../Item/KeyframeRepository.cs | 8 + .../MediaSegments/MediaSegmentManager.cs | 9 +- .../Migrations/Routines/MigrateKeyframeData.cs | 5 + .../Migrations/Routines/MoveExtractedFiles.cs | 5 + .../Routines/RefreshInternalDateModified.cs | 131 +++++++ MediaBrowser.Controller/Entities/BaseItem.cs | 40 +- MediaBrowser.Controller/IO/IPathManager.cs | 10 +- .../Library/IKeyframeManager.cs | 37 ++ MediaBrowser.Controller/Library/ILibraryManager.cs | 8 +- .../MediaSegments/IMediaSegmentManager.cs | 9 +- .../MediaSegments/IMediaSegmentProvider.cs | 6 +- .../Persistence/IKeyframeRepository.cs | 8 + MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 4 +- .../Books/AudioBookMetadataService.cs | 80 ++-- .../Books/BookMetadataService.cs | 58 +-- .../BoxSets/BoxSetMetadataService.cs | 124 +++--- .../Channels/ChannelMetadataService.cs | 42 ++- .../Folders/CollectionFolderMetadataService.cs | 42 ++- .../Folders/FolderMetadataService.cs | 50 ++- .../Folders/UserViewMetadataService.cs | 42 ++- .../Genres/GenreMetadataService.cs | 42 ++- .../LiveTv/LiveTvMetadataService.cs | 42 ++- MediaBrowser.Providers/Manager/MetadataService.cs | 76 +++- MediaBrowser.Providers/Manager/ProviderManager.cs | 3 +- .../MediaInfo/AudioFileProber.cs | 1 - .../MediaInfo/FFProbeVideoInfo.cs | 16 +- MediaBrowser.Providers/MediaInfo/ProbeProvider.cs | 4 +- .../MediaInfo/SubtitleScheduledTask.cs | 1 - .../Movies/MovieMetadataService.cs | 62 +-- .../Movies/TrailerMetadataService.cs | 64 ++-- .../Music/AlbumMetadataService.cs | 359 +++++++++--------- .../Music/ArtistMetadataService.cs | 69 ++-- .../Music/AudioMetadataService.cs | 111 +++--- .../Music/MusicVideoMetadataService.cs | 88 +++-- .../MusicGenres/MusicGenreMetadataService.cs | 42 ++- .../People/PersonMetadataService.cs | 42 ++- .../Photos/PhotoAlbumMetadataService.cs | 42 ++- .../Photos/PhotoMetadataService.cs | 42 ++- .../Playlists/PlaylistMetadataService.cs | 110 +++--- .../Studios/StudioMetadataService.cs | 42 ++- .../TV/EpisodeMetadataService.cs | 164 ++++---- MediaBrowser.Providers/TV/SeasonMetadataService.cs | 155 ++++---- MediaBrowser.Providers/TV/SeriesMetadataService.cs | 419 +++++++++++---------- .../Videos/VideoMetadataService.cs | 50 ++- .../Years/YearMetadataService.cs | 42 ++- src/Jellyfin.Drawing/ImageProcessor.cs | 4 +- src/Jellyfin.LiveTv/Channels/ChannelManager.cs | 5 +- .../Manager/ProviderManagerTests.cs | 1 + 57 files changed, 1914 insertions(+), 1124 deletions(-) create mode 100644 Emby.Server.Implementations/Library/KeyframeManager.cs create mode 100644 Jellyfin.Server/Migrations/Routines/RefreshInternalDateModified.cs create mode 100644 MediaBrowser.Controller/Library/IKeyframeManager.cs (limited to 'MediaBrowser.MediaEncoding') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index fa6e9ff97..987ce8b84 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -36,7 +36,6 @@ using Emby.Server.Implementations.SyncPlay; using Emby.Server.Implementations.TV; using Emby.Server.Implementations.Updates; using Jellyfin.Api.Helpers; -using Jellyfin.Database.Implementations; using Jellyfin.Drawing; using Jellyfin.MediaEncoding.Hls.Playlist; using Jellyfin.Networking.Manager; @@ -63,6 +62,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Lyrics; using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Playlists; @@ -93,7 +93,6 @@ using MediaBrowser.Providers.Subtitles; using MediaBrowser.XbmcMetadata.Providers; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -560,6 +559,7 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index 60f515f24..0eb387ffd 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -95,7 +95,7 @@ namespace Emby.Server.Implementations.Collections var libraryOptions = new LibraryOptions { - PathInfos = new[] { new MediaPathInfo(path) }, + PathInfos = [new MediaPathInfo(path)], EnableRealtimeMonitor = false, SaveLocalMetadata = true }; @@ -150,15 +150,15 @@ namespace Emby.Server.Implementations.Collections try { - Directory.CreateDirectory(path); - + var info = Directory.CreateDirectory(path); var collection = new BoxSet { Name = name, Path = path, IsLocked = options.IsLocked, ProviderIds = options.ProviderIds, - DateCreated = DateTime.UtcNow + DateCreated = info.CreationTimeUtc, + DateModified = info.LastWriteTimeUtc }; parentFolder.AddChild(collection); diff --git a/Emby.Server.Implementations/Library/KeyframeManager.cs b/Emby.Server.Implementations/Library/KeyframeManager.cs new file mode 100644 index 000000000..18f4ce047 --- /dev/null +++ b/Emby.Server.Implementations/Library/KeyframeManager.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.MediaEncoding.Keyframes; +using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.Persistence; + +namespace Emby.Server.Implementations.Library; + +/// +/// Manager for Keyframe data. +/// +public class KeyframeManager : IKeyframeManager +{ + private readonly IKeyframeRepository _repository; + + /// + /// Initializes a new instance of the class. + /// + /// The keyframe repository. + public KeyframeManager(IKeyframeRepository repository) + { + _repository = repository; + } + + /// + public IReadOnlyList GetKeyframeData(Guid itemId) + { + return _repository.GetKeyframeData(itemId); + } + + /// + public async Task SaveKeyframeDataAsync(Guid itemId, KeyframeData data, CancellationToken cancellationToken) + { + await _repository.SaveKeyframeDataAsync(itemId, data, cancellationToken).ConfigureAwait(false); + } + + /// + public async Task DeleteKeyframeDataAsync(Guid itemId, CancellationToken cancellationToken) + { + await _repository.DeleteKeyframeDataAsync(itemId, cancellationToken).ConfigureAwait(false); + } +} diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 51f330746..1fdd80bd8 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -208,7 +208,7 @@ namespace Emby.Server.Implementations.Library /// Gets or sets the postscan tasks. /// /// The postscan tasks. - private ILibraryPostScanTask[] PostscanTasks { get; set; } = []; + private ILibraryPostScanTask[] PostScanTasks { get; set; } = []; /// /// Gets or sets the intro providers. @@ -245,20 +245,20 @@ namespace Emby.Server.Implementations.Library /// The resolvers. /// The intro providers. /// The item comparers. - /// The post scan tasks. + /// The post scan tasks. public void AddParts( IEnumerable rules, IEnumerable resolvers, IEnumerable introProviders, IEnumerable itemComparers, - IEnumerable postscanTasks) + IEnumerable postScanTasks) { EntityResolutionIgnoreRules = rules.ToArray(); EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray(); MultiItemResolvers = EntityResolvers.OfType().ToArray(); IntroProviders = introProviders.ToArray(); Comparers = itemComparers.ToArray(); - PostscanTasks = postscanTasks.ToArray(); + PostScanTasks = postScanTasks.ToArray(); } /// @@ -393,7 +393,7 @@ namespace Emby.Server.Implementations.Library } } - if (options.DeleteFileLocation && item.IsFileProtocol) + if ((options.DeleteFileLocation && item.IsFileProtocol) || IsInternalItem(item)) { // Assume only the first is required // Add this flag to GetDeletePaths if required in the future @@ -472,6 +472,36 @@ namespace Emby.Server.Implementations.Library ReportItemRemoved(item, parent); } + private bool IsInternalItem(BaseItem item) + { + if (!item.IsFileProtocol) + { + return false; + } + + var pathToCheck = item switch + { + Genre => _configurationManager.ApplicationPaths.GenrePath, + MusicArtist => _configurationManager.ApplicationPaths.ArtistsPath, + MusicGenre => _configurationManager.ApplicationPaths.GenrePath, + Person => _configurationManager.ApplicationPaths.PeoplePath, + Studio => _configurationManager.ApplicationPaths.StudioPath, + Year => _configurationManager.ApplicationPaths.YearPath, + _ => null + }; + + var itemPath = item.Path; + if (!string.IsNullOrEmpty(pathToCheck) && !string.IsNullOrEmpty(itemPath)) + { + var cleanPath = _fileSystem.GetValidFilename(itemPath); + var cleanCheckPath = _fileSystem.GetValidFilename(pathToCheck); + + return cleanPath.StartsWith(cleanCheckPath, StringComparison.Ordinal); + } + + return false; + } + private List GetMetadataPaths(BaseItem item, IEnumerable children) { var list = GetInternalMetadataPaths(item); @@ -639,7 +669,7 @@ namespace Emby.Server.Implementations.Library } } - // Need to remove subpaths that may have been resolved from shortcuts + // Need to remove sub-paths that may have been resolved from shortcuts // Example: if \\server\movies exists, then strip out \\server\movies\action if (isPhysicalRoot) { @@ -772,11 +802,12 @@ namespace Emby.Server.Implementations.Library // Add in the plug-in folders var path = Path.Combine(_configurationManager.ApplicationPaths.DataPath, "playlists"); - Directory.CreateDirectory(path); - + var info = Directory.CreateDirectory(path); Folder folder = new PlaylistsFolder { - Path = path + Path = path, + DateCreated = info.CreationTimeUtc, + DateModified = info.LastWriteTimeUtc, }; if (folder.Id.IsEmpty()) @@ -862,7 +893,7 @@ namespace Emby.Server.Implementations.Library { Path = path, IsFolder = isFolder, - OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending) }, + OrderBy = [(ItemSortBy.DateCreated, SortOrder.Descending)], Limit = 1, DtoOptions = new DtoOptions(true) }; @@ -968,7 +999,7 @@ namespace Emby.Server.Implementations.Library { var existing = GetItemList(new InternalItemsQuery { - IncludeItemTypes = new[] { BaseItemKind.MusicArtist }, + IncludeItemTypes = [BaseItemKind.MusicArtist], Name = name, DtoOptions = options }).Cast() @@ -987,12 +1018,13 @@ namespace Emby.Server.Implementations.Library var item = GetItemById(id) as T; if (item is null) { + var info = Directory.CreateDirectory(path); item = new T { Name = name, Id = id, - DateCreated = DateTime.UtcNow, - DateModified = DateTime.UtcNow, + DateCreated = info.CreationTimeUtc, + DateModified = info.LastWriteTimeUtc, Path = path }; @@ -1118,7 +1150,7 @@ namespace Emby.Server.Implementations.Library /// Task. private async Task RunPostScanTasks(IProgress progress, CancellationToken cancellationToken) { - var tasks = PostscanTasks.ToList(); + var tasks = PostScanTasks.ToList(); var numComplete = 0; var numTasks = tasks.Count; @@ -1241,7 +1273,7 @@ namespace Emby.Server.Implementations.Library private CollectionTypeOptions? GetCollectionType(string path) { - var files = _fileSystem.GetFilePaths(path, new[] { ".collection" }, true, false); + var files = _fileSystem.GetFilePaths(path, [".collection"], true, false); foreach (ReadOnlySpan file in files) { if (Enum.TryParse(Path.GetFileNameWithoutExtension(file), true, out var res)) @@ -1312,7 +1344,7 @@ namespace Emby.Server.Implementations.Library var parent = GetItemById(query.ParentId); if (parent is not null) { - SetTopParentIdsOrAncestors(query, new[] { parent }); + SetTopParentIdsOrAncestors(query, [parent]); } } @@ -1343,7 +1375,7 @@ namespace Emby.Server.Implementations.Library var parent = GetItemById(query.ParentId); if (parent is not null) { - SetTopParentIdsOrAncestors(query, new[] { parent }); + SetTopParentIdsOrAncestors(query, [parent]); } } @@ -1531,7 +1563,7 @@ namespace Emby.Server.Implementations.Library var parent = GetItemById(query.ParentId); if (parent is not null) { - SetTopParentIdsOrAncestors(query, new[] { parent }); + SetTopParentIdsOrAncestors(query, [parent]); } } @@ -1561,7 +1593,7 @@ namespace Emby.Server.Implementations.Library // Prevent searching in all libraries due to empty filter if (query.TopParentIds.Length == 0) { - query.TopParentIds = new[] { Guid.NewGuid() }; + query.TopParentIds = [Guid.NewGuid()]; } } else @@ -1572,7 +1604,7 @@ namespace Emby.Server.Implementations.Library // Prevent searching in all libraries due to empty filter if (query.AncestorIds.Length == 0) { - query.AncestorIds = new[] { Guid.NewGuid() }; + query.AncestorIds = [Guid.NewGuid()]; } } @@ -1601,7 +1633,7 @@ namespace Emby.Server.Implementations.Library // Prevent searching in all libraries due to empty filter if (query.TopParentIds.Length == 0) { - query.TopParentIds = new[] { Guid.NewGuid() }; + query.TopParentIds = [Guid.NewGuid()]; } } } @@ -1612,7 +1644,7 @@ namespace Emby.Server.Implementations.Library { if (view.ViewType == CollectionType.livetv) { - return new[] { view.Id }; + return [view.Id]; } // Translate view into folders @@ -1661,7 +1693,7 @@ namespace Emby.Server.Implementations.Library var topParent = item.GetTopParent(); if (topParent is not null) { - return new[] { topParent.Id }; + return [topParent.Id]; } return []; @@ -1868,7 +1900,7 @@ namespace Emby.Server.Implementations.Library /// public void CreateItem(BaseItem item, BaseItem? parent) { - CreateItems(new[] { item }, parent, CancellationToken.None); + CreateItems([item], parent, CancellationToken.None); } /// @@ -2054,7 +2086,7 @@ namespace Emby.Server.Implementations.Library /// public Task UpdateItemAsync(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) - => UpdateItemsAsync(new[] { item }, parent, updateReason, cancellationToken); + => UpdateItemsAsync([item], parent, updateReason, cancellationToken); public async Task RunMetadataSavers(BaseItem item, ItemUpdateType updateReason) { @@ -2283,13 +2315,13 @@ namespace Emby.Server.Implementations.Library if (item is null || !string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase)) { - Directory.CreateDirectory(path); - + var info = Directory.CreateDirectory(path); item = new UserView { Path = path, Id = id, - DateCreated = DateTime.UtcNow, + DateCreated = info.CreationTimeUtc, + DateModified = info.LastWriteTimeUtc, Name = name, ViewType = viewType, ForcedSortName = sortName @@ -2331,13 +2363,13 @@ namespace Emby.Server.Implementations.Library if (item is null) { - Directory.CreateDirectory(path); - + var info = Directory.CreateDirectory(path); item = new UserView { Path = path, Id = id, - DateCreated = DateTime.UtcNow, + DateCreated = info.CreationTimeUtc, + DateModified = info.LastWriteTimeUtc, Name = name, ViewType = viewType, ForcedSortName = sortName, @@ -2395,20 +2427,19 @@ namespace Emby.Server.Implementations.Library if (item is null) { - Directory.CreateDirectory(path); - + var info = Directory.CreateDirectory(path); item = new UserView { Path = path, Id = id, - DateCreated = DateTime.UtcNow, + DateCreated = info.CreationTimeUtc, + DateModified = info.LastWriteTimeUtc, Name = name, ViewType = viewType, - ForcedSortName = sortName + ForcedSortName = sortName, + DisplayParentId = parentId }; - item.DisplayParentId = parentId; - CreateItem(item, null); isNew = true; @@ -2465,20 +2496,19 @@ namespace Emby.Server.Implementations.Library if (item is null) { - Directory.CreateDirectory(path); - + var info = Directory.CreateDirectory(path); item = new UserView { Path = path, Id = id, - DateCreated = DateTime.UtcNow, + DateCreated = info.CreationTimeUtc, + DateModified = info.LastWriteTimeUtc, Name = name, ViewType = viewType, - ForcedSortName = sortName + ForcedSortName = sortName, + DisplayParentId = parentId }; - item.DisplayParentId = parentId; - CreateItem(item, null); isNew = true; @@ -2989,12 +3019,14 @@ namespace Emby.Server.Implementations.Library if (personEntity is null) { var path = Person.GetPath(person.Name); + var info = Directory.CreateDirectory(path); + var lastWriteTime = info.LastWriteTimeUtc; personEntity = new Person() { Name = person.Name, Id = GetItemByNameId(path), - DateCreated = DateTime.UtcNow, - DateModified = DateTime.UtcNow, + DateCreated = info.CreationTimeUtc, + DateModified = lastWriteTime, Path = path }; diff --git a/Emby.Server.Implementations/Library/PathManager.cs b/Emby.Server.Implementations/Library/PathManager.cs index 853d85e5e..a9b7a1274 100644 --- a/Emby.Server.Implementations/Library/PathManager.cs +++ b/Emby.Server.Implementations/Library/PathManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using MediaBrowser.Common.Configuration; @@ -84,4 +85,17 @@ public class PathManager : IPathManager return Path.Combine(GetChapterImageFolderPath(item), filename); } + + /// + public IReadOnlyList GetExtractedDataPaths(BaseItem item) + { + var mediaSourceId = item.Id.ToString("N", CultureInfo.InvariantCulture); + return [ + GetAttachmentFolderPath(mediaSourceId), + GetSubtitleFolderPath(mediaSourceId), + GetTrickplayDirectory(item, false), + GetTrickplayDirectory(item, true), + GetChapterImageFolderPath(item) + ]; + } } diff --git a/Emby.Server.Implementations/Library/ResolverHelper.cs b/Emby.Server.Implementations/Library/ResolverHelper.cs index c9e3a4daf..ab6bc4907 100644 --- a/Emby.Server.Implementations/Library/ResolverHelper.cs +++ b/Emby.Server.Implementations/Library/ResolverHelper.cs @@ -136,23 +136,33 @@ namespace Emby.Server.Implementations.Library if (config.UseFileCreationTimeForDateAdded) { - // directoryService.getFile may return null - if (info is not null) + var fileCreationDate = info?.CreationTimeUtc; + if (fileCreationDate is not null) { - var dateCreated = info.CreationTimeUtc; - + var dateCreated = fileCreationDate; if (dateCreated.Equals(DateTime.MinValue)) { dateCreated = DateTime.UtcNow; } - item.DateCreated = dateCreated; + item.DateCreated = dateCreated.Value; } } else { item.DateCreated = DateTime.UtcNow; } + + if (info is not null && !info.IsDirectory) + { + item.Size = info.Length; + } + + var fileModificationDate = info?.LastWriteTimeUtc; + if (fileModificationDate.HasValue) + { + item.DateModified = fileModificationDate.Value; + } } } } diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 98a43b6c9..1ce363de5 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -134,14 +134,16 @@ namespace Emby.Server.Implementations.Playlists try { - Directory.CreateDirectory(path); + var info = Directory.CreateDirectory(path); var playlist = new Playlist { Name = name, Path = path, OwnerUserId = request.UserId, Shares = request.Users ?? [], - OpenAccess = request.Public ?? false + OpenAccess = request.Public ?? false, + DateCreated = info.CreationTimeUtc, + DateModified = info.LastWriteTimeUtc }; playlist.SetMediaType(request.MediaType); diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/MediaSegmentExtractionTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/MediaSegmentExtractionTask.cs index b8c944d3d..c3f17c2ae 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/MediaSegmentExtractionTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/MediaSegmentExtractionTask.cs @@ -4,10 +4,10 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; -using MediaBrowser.Controller; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Tasks; diff --git a/Jellyfin.Api/Controllers/MediaSegmentsController.cs b/Jellyfin.Api/Controllers/MediaSegmentsController.cs index e30e2b54e..2a91a8455 100644 --- a/Jellyfin.Api/Controllers/MediaSegmentsController.cs +++ b/Jellyfin.Api/Controllers/MediaSegmentsController.cs @@ -5,9 +5,9 @@ using System.Linq; using System.Threading.Tasks; using Jellyfin.Api.Extensions; using Jellyfin.Database.Implementations.Enums; -using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Model.MediaSegments; using MediaBrowser.Model.Querying; using Microsoft.AspNetCore.Authorization; diff --git a/Jellyfin.Server.Implementations/Item/KeyframeRepository.cs b/Jellyfin.Server.Implementations/Item/KeyframeRepository.cs index a2267700f..93c6f472e 100644 --- a/Jellyfin.Server.Implementations/Item/KeyframeRepository.cs +++ b/Jellyfin.Server.Implementations/Item/KeyframeRepository.cs @@ -61,4 +61,12 @@ public class KeyframeRepository : IKeyframeRepository await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false); await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); } + + /// + public async Task DeleteKeyframeDataAsync(Guid itemId, CancellationToken cancellationToken) + { + using var context = _dbProvider.CreateDbContext(); + await context.KeyframeData.Where(e => e.ItemId.Equals(itemId)).ExecuteDeleteAsync(cancellationToken).ConfigureAwait(false); + await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false); + } } diff --git a/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs b/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs index d6eeafacc..5a2032c1f 100644 --- a/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs +++ b/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs @@ -10,10 +10,10 @@ using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model; using MediaBrowser.Model.MediaSegments; @@ -139,6 +139,13 @@ public class MediaSegmentManager : IMediaSegmentManager await db.MediaSegments.Where(e => e.Id.Equals(segmentId)).ExecuteDeleteAsync().ConfigureAwait(false); } + /// + public async Task DeleteSegmentsAsync(Guid itemId) + { + using var db = await _dbProvider.CreateDbContextAsync().ConfigureAwait(false); + await db.MediaSegments.Where(e => e.ItemId.Equals(itemId)).ExecuteDeleteAsync().ConfigureAwait(false); + } + /// public async Task> GetSegmentsAsync(Guid itemId, IEnumerable? typeFilter, bool filterByProvider = true) { diff --git a/Jellyfin.Server/Migrations/Routines/MigrateKeyframeData.cs b/Jellyfin.Server/Migrations/Routines/MigrateKeyframeData.cs index c5bc70278..1ee4c41c3 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateKeyframeData.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateKeyframeData.cs @@ -73,6 +73,11 @@ public class MigrateKeyframeData : IDatabaseMigrationRoutine } offset += Limit; + if (offset > records) + { + offset = records; + } + _logger.LogInformation("Checked: {Count} - Imported: {Items} - Time: {Time}", offset, itemCount, sw.Elapsed); } while (offset < records); diff --git a/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs b/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs index 9031f2fdc..c6471b24c 100644 --- a/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs +++ b/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs @@ -95,6 +95,11 @@ public class MoveExtractedFiles : IMigrationRoutine } offset += Limit; + if (offset > records) + { + offset = records; + } + _logger.LogInformation("Checked: {Count} - Moved: {Items} - Time: {Time}", offset, itemCount, sw.Elapsed); } while (offset < records); diff --git a/Jellyfin.Server/Migrations/Routines/RefreshInternalDateModified.cs b/Jellyfin.Server/Migrations/Routines/RefreshInternalDateModified.cs new file mode 100644 index 000000000..9a95757a8 --- /dev/null +++ b/Jellyfin.Server/Migrations/Routines/RefreshInternalDateModified.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; +using Jellyfin.Extensions; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.IO; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Migrations.Routines; + +/// +/// Migration to re-read creation dates for library items with internal metadata paths. +/// +[JellyfinMigration("2025-04-20T23:00:00", nameof(RefreshInternalDateModified), "32E762EB-4918-45CE-A44C-C801F66B877D", RunMigrationOnSetup = false)] +public class RefreshInternalDateModified : IDatabaseMigrationRoutine +{ + private readonly ILogger _logger; + private readonly IDbContextFactory _dbProvider; + private readonly IFileSystem _fileSystem; + private readonly IServerApplicationHost _applicationHost; + private readonly bool _useFileCreationTimeForDateAdded; + + private IReadOnlyList _internalTypes = [ + typeof(Genre).FullName!, + typeof(MusicGenre).FullName!, + typeof(MusicArtist).FullName!, + typeof(People).FullName!, + typeof(Studio).FullName! + ]; + + private IReadOnlyList _internalPaths; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// The logger. + /// Instance of the interface. + public RefreshInternalDateModified( + IServerApplicationHost applicationHost, + IServerApplicationPaths applicationPaths, + IServerConfigurationManager configurationManager, + IDbContextFactory dbProvider, + ILogger logger, + IFileSystem fileSystem) + { + _dbProvider = dbProvider; + _logger = logger; + _fileSystem = fileSystem; + _applicationHost = applicationHost; + _internalPaths = [ + applicationPaths.ArtistsPath, + applicationPaths.GenrePath, + applicationPaths.MusicGenrePath, + applicationPaths.StudioPath, + applicationPaths.PeoplePath + ]; + _useFileCreationTimeForDateAdded = configurationManager.GetMetadataConfiguration().UseFileCreationTimeForDateAdded; + } + + /// + public void Perform() + { + const int Limit = 5000; + int itemCount = 0, offset = 0; + + var sw = Stopwatch.StartNew(); + + using var context = _dbProvider.CreateDbContext(); + var records = context.BaseItems.Count(b => _internalTypes.Contains(b.Type)); + _logger.LogInformation("Checking if {Count} potentially internal items require refreshed DateModified", records); + + do + { + var results = context.BaseItems + .Where(b => _internalTypes.Contains(b.Type)) + .OrderBy(e => e.Id) + .Skip(offset) + .Take(Limit) + .ToList(); + + foreach (var item in results) + { + var itemPath = item.Path; + if (itemPath is not null) + { + var realPath = _applicationHost.ExpandVirtualPath(item.Path); + if (_internalPaths.Any(path => realPath.StartsWith(path, StringComparison.Ordinal))) + { + var writeTime = _fileSystem.GetLastWriteTimeUtc(realPath); + var itemModificationTime = item.DateModified; + if (writeTime != itemModificationTime) + { + _logger.LogDebug("Reset file modification date: Old: {Old} - New: {New} - Path: {Path}", itemModificationTime, writeTime, realPath); + item.DateModified = writeTime; + if (_useFileCreationTimeForDateAdded) + { + item.DateCreated = _fileSystem.GetCreationTimeUtc(realPath); + } + + itemCount++; + } + } + } + } + + offset += Limit; + if (offset > records) + { + offset = records; + } + + _logger.LogInformation("Checked: {Count} - Refreshed: {Items} - Time: {Time}", offset, itemCount, sw.Elapsed); + } while (offset < records); + + context.SaveChanges(); + + _logger.LogInformation("Refreshed DateModified for {Count} items in {Time}", itemCount, sw.Elapsed); + } +} diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index b90ec8222..16fde9440 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -25,6 +25,7 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; @@ -1265,7 +1266,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Overrides the base implementation to refresh metadata for local trailers. + /// The base implementation to refresh metadata. /// /// The options. /// The cancellation token. @@ -1362,9 +1363,7 @@ namespace MediaBrowser.Controller.Entities protected virtual FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService) { - var path = ContainingFolderPath; - - return directoryService.GetFileSystemEntries(path); + return directoryService.GetFileSystemEntries(ContainingFolderPath); } private async Task RefreshExtras(BaseItem item, MetadataRefreshOptions options, IReadOnlyList fileSystemChildren, CancellationToken cancellationToken) @@ -1393,6 +1392,23 @@ namespace MediaBrowser.Controller.Entities return RefreshMetadataForOwnedItem(i, true, subOptions, cancellationToken); }); + // Cleanup removed extras + var removedExtraIds = item.ExtraIds.Where(e => !newExtraIds.Contains(e)).ToArray(); + if (removedExtraIds.Length > 0) + { + var removedExtras = LibraryManager.GetItemList(new InternalItemsQuery() + { + ItemIds = removedExtraIds + }); + foreach (var removedExtra in removedExtras) + { + LibraryManager.DeleteItem(removedExtra, new DeleteOptions() + { + DeleteFileLocation = false + }); + } + } + await Task.WhenAll(tasks).ConfigureAwait(false); item.ExtraIds = newExtraIds; @@ -1407,6 +1423,22 @@ namespace MediaBrowser.Controller.Entities public virtual bool RequiresRefresh() { + if (string.IsNullOrEmpty(Path) || DateModified == default) + { + return false; + } + + var info = FileSystem.GetFileSystemInfo(Path); + if (info.Exists) + { + if (info.IsDirectory) + { + return info.LastWriteTimeUtc != DateModified; + } + + return info.LastWriteTimeUtc != DateModified && info.Length != (Size ?? 0); + } + return false; } diff --git a/MediaBrowser.Controller/IO/IPathManager.cs b/MediaBrowser.Controller/IO/IPathManager.cs index 4e4eb514e..eb6743754 100644 --- a/MediaBrowser.Controller/IO/IPathManager.cs +++ b/MediaBrowser.Controller/IO/IPathManager.cs @@ -1,9 +1,10 @@ +using System.Collections.Generic; using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.IO; /// -/// Interface ITrickplayManager. +/// Interface IPathManager. /// public interface IPathManager { @@ -60,4 +61,11 @@ public interface IPathManager /// The chapter position. /// The chapter images data path. public string GetChapterImagePath(BaseItem item, long chapterPositionTicks); + + /// + /// Gets the paths of extracted data folders. + /// + /// The base item. + /// The absolute paths. + public IReadOnlyList GetExtractedDataPaths(BaseItem item); } diff --git a/MediaBrowser.Controller/Library/IKeyframeManager.cs b/MediaBrowser.Controller/Library/IKeyframeManager.cs new file mode 100644 index 000000000..b0155efdd --- /dev/null +++ b/MediaBrowser.Controller/Library/IKeyframeManager.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.MediaEncoding.Keyframes; + +namespace MediaBrowser.Controller.IO; + +/// +/// Interface IKeyframeManager. +/// +public interface IKeyframeManager +{ + /// + /// Gets the keyframe data. + /// + /// The item id. + /// The keyframe data. + IReadOnlyList GetKeyframeData(Guid itemId); + + /// + /// Saves the keyframe data. + /// + /// The item id. + /// The keyframe data. + /// The cancellation token. + /// The task object representing the asynchronous operation. + Task SaveKeyframeDataAsync(Guid itemId, KeyframeData data, CancellationToken cancellationToken); + + /// + /// Deletes the keyframe data. + /// + /// The item id. + /// The cancellation token. + /// The task object representing the asynchronous operation. + Task DeleteKeyframeDataAsync(Guid itemId, CancellationToken cancellationToken); +} diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index df90f546c..98ed15eb6 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -220,13 +220,13 @@ namespace MediaBrowser.Controller.Library /// The resolvers. /// The intro providers. /// The item comparers. - /// The postscan tasks. + /// The post scan tasks. void AddParts( IEnumerable rules, IEnumerable resolvers, IEnumerable introProviders, IEnumerable itemComparers, - IEnumerable postscanTasks); + IEnumerable postScanTasks); /// /// Sorts the specified items. @@ -593,11 +593,11 @@ namespace MediaBrowser.Controller.Library QueryResult GetItemsResult(InternalItemsQuery query); /// - /// Ignores the file. + /// Checks if the file is ignored. /// /// The file. /// The parent. - /// true if XXXX, false otherwise. + /// true if ignored, false otherwise. bool IgnoreFile(FileSystemMetadata file, BaseItem parent); Guid GetStudioId(string name); diff --git a/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs b/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs index 456977b88..6cd6474f7 100644 --- a/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs +++ b/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs @@ -7,7 +7,7 @@ using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.MediaSegments; -namespace MediaBrowser.Controller; +namespace MediaBrowser.Controller.MediaSegments; /// /// Defines methods for interacting with media segments. @@ -45,6 +45,13 @@ public interface IMediaSegmentManager /// a task. Task DeleteSegmentAsync(Guid segmentId); + /// + /// Deletes all media segments of an item. + /// + /// The to delete all segments for. + /// a task. + Task DeleteSegmentsAsync(Guid itemId); + /// /// Obtains all segments associated with the itemId. /// diff --git a/MediaBrowser.Controller/MediaSegments/IMediaSegmentProvider.cs b/MediaBrowser.Controller/MediaSegments/IMediaSegmentProvider.cs index 39bb58bef..5a6d15d78 100644 --- a/MediaBrowser.Controller/MediaSegments/IMediaSegmentProvider.cs +++ b/MediaBrowser.Controller/MediaSegments/IMediaSegmentProvider.cs @@ -1,13 +1,11 @@ -using System; -using System.Collections; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; using MediaBrowser.Model; using MediaBrowser.Model.MediaSegments; -namespace MediaBrowser.Controller; +namespace MediaBrowser.Controller.MediaSegments; /// /// Provides methods for Obtaining the Media Segments from an Item. diff --git a/MediaBrowser.Controller/Persistence/IKeyframeRepository.cs b/MediaBrowser.Controller/Persistence/IKeyframeRepository.cs index 4930434a7..2596784ba 100644 --- a/MediaBrowser.Controller/Persistence/IKeyframeRepository.cs +++ b/MediaBrowser.Controller/Persistence/IKeyframeRepository.cs @@ -26,4 +26,12 @@ public interface IKeyframeRepository /// The cancellation token. /// The task object representing the asynchronous operation. Task SaveKeyframeDataAsync(Guid itemId, KeyframeData data, CancellationToken cancellationToken); + + /// + /// Deletes the keyframe data. + /// + /// The item id. + /// The cancellation token. + /// The task object representing the asynchronous operation. + Task DeleteKeyframeDataAsync(Guid itemId, CancellationToken cancellationToken); } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 897652fcd..2eb647e26 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -537,7 +537,7 @@ namespace MediaBrowser.MediaEncoding.Encoder EnableRaisingEvents = true }; - _logger.LogInformation("Starting {ProcessFileName} with args {ProcessArgs}", _ffprobePath, args); + _logger.LogDebug("Starting {ProcessFileName} with args {ProcessArgs}", _ffprobePath, args); var memoryStream = new MemoryStream(); await using (memoryStream.ConfigureAwait(false)) @@ -637,7 +637,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } catch (Exception ex) { - _logger.LogError(ex, "I-frame image extraction failed, will attempt standard way. Input: {Arguments}", inputArgument); + _logger.LogWarning(ex, "I-frame image extraction failed, will attempt standard way. Input: {Arguments}", inputArgument); } } diff --git a/MediaBrowser.Providers/Books/AudioBookMetadataService.cs b/MediaBrowser.Providers/Books/AudioBookMetadataService.cs index 96e1165b6..79cd33aa0 100644 --- a/MediaBrowser.Providers/Books/AudioBookMetadataService.cs +++ b/MediaBrowser.Providers/Books/AudioBookMetadataService.cs @@ -1,50 +1,66 @@ -#pragma warning disable CS1591 - using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Providers.Manager; using Microsoft.Extensions.Logging; -namespace MediaBrowser.Providers.Books +namespace MediaBrowser.Providers.Books; + +/// +/// Service to manage audiobook metadata. +/// +public class AudioBookMetadataService : MetadataService { - public class AudioBookMetadataService : MetadataService + /// + /// Initializes a new instance of the class. + /// + /// Instance of the . + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public AudioBookMetadataService( + IServerConfigurationManager serverConfigurationManager, + ILogger logger, + IProviderManager providerManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + IPathManager pathManager, + IKeyframeManager keyframeManager, + IMediaSegmentManager mediaSegmentManager) + : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager, pathManager, keyframeManager, mediaSegmentManager) { - public AudioBookMetadataService( - IServerConfigurationManager serverConfigurationManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem, - ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager) - { - } + } - /// - protected override void MergeData( - MetadataResult source, - MetadataResult target, - MetadataField[] lockedFields, - bool replaceData, - bool mergeMetadataSettings) - { - base.MergeData(source, target, lockedFields, replaceData, mergeMetadataSettings); + /// + protected override void MergeData( + MetadataResult source, + MetadataResult target, + MetadataField[] lockedFields, + bool replaceData, + bool mergeMetadataSettings) + { + base.MergeData(source, target, lockedFields, replaceData, mergeMetadataSettings); - var sourceItem = source.Item; - var targetItem = target.Item; + var sourceItem = source.Item; + var targetItem = target.Item; - if (replaceData || targetItem.Artists.Count == 0) - { - targetItem.Artists = sourceItem.Artists; - } + if (replaceData || targetItem.Artists.Count == 0) + { + targetItem.Artists = sourceItem.Artists; + } - if (replaceData || string.IsNullOrEmpty(targetItem.Album)) - { - targetItem.Album = sourceItem.Album; - } + if (replaceData || string.IsNullOrEmpty(targetItem.Album)) + { + targetItem.Album = sourceItem.Album; } } } diff --git a/MediaBrowser.Providers/Books/BookMetadataService.cs b/MediaBrowser.Providers/Books/BookMetadataService.cs index 50b9922c6..6df8feab8 100644 --- a/MediaBrowser.Providers/Books/BookMetadataService.cs +++ b/MediaBrowser.Providers/Books/BookMetadataService.cs @@ -1,37 +1,53 @@ -#pragma warning disable CS1591 - using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Providers.Manager; using Microsoft.Extensions.Logging; -namespace MediaBrowser.Providers.Books +namespace MediaBrowser.Providers.Books; + +/// +/// Service to manage book metadata. +/// +public class BookMetadataService : MetadataService { - public class BookMetadataService : MetadataService + /// + /// Initializes a new instance of the class. + /// + /// Instance of the . + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public BookMetadataService( + IServerConfigurationManager serverConfigurationManager, + ILogger logger, + IProviderManager providerManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + IPathManager pathManager, + IKeyframeManager keyframeManager, + IMediaSegmentManager mediaSegmentManager) + : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager, pathManager, keyframeManager, mediaSegmentManager) { - public BookMetadataService( - IServerConfigurationManager serverConfigurationManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem, - ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager) - { - } + } - /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) - { - base.MergeData(source, target, lockedFields, replaceData, mergeMetadataSettings); + /// + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) + { + base.MergeData(source, target, lockedFields, replaceData, mergeMetadataSettings); - if (replaceData || string.IsNullOrEmpty(target.Item.SeriesName)) - { - target.Item.SeriesName = source.Item.SeriesName; - } + if (replaceData || string.IsNullOrEmpty(target.Item.SeriesName)) + { + target.Item.SeriesName = source.Item.SeriesName; } } } diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs index b51ab4c08..83f0f2485 100644 --- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs +++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs @@ -1,85 +1,101 @@ -#pragma warning disable CS1591 - using System.Collections.Generic; using System.Linq; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Providers.Manager; using Microsoft.Extensions.Logging; -namespace MediaBrowser.Providers.BoxSets +namespace MediaBrowser.Providers.BoxSets; + +/// +/// Service to manage boxset metadata. +/// +public class BoxSetMetadataService : MetadataService { - public class BoxSetMetadataService : MetadataService + /// + /// Initializes a new instance of the class. + /// + /// Instance of the . + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public BoxSetMetadataService( + IServerConfigurationManager serverConfigurationManager, + ILogger logger, + IProviderManager providerManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + IPathManager pathManager, + IKeyframeManager keyframeManager, + IMediaSegmentManager mediaSegmentManager) + : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager, pathManager, keyframeManager, mediaSegmentManager) { - public BoxSetMetadataService( - IServerConfigurationManager serverConfigurationManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem, - ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager) - { - } + } - /// - protected override bool EnableUpdatingGenresFromChildren => true; + /// + protected override bool EnableUpdatingGenresFromChildren => true; - /// - protected override bool EnableUpdatingOfficialRatingFromChildren => true; + /// + protected override bool EnableUpdatingOfficialRatingFromChildren => true; - /// - protected override bool EnableUpdatingStudiosFromChildren => true; + /// + protected override bool EnableUpdatingStudiosFromChildren => true; - /// - protected override bool EnableUpdatingPremiereDateFromChildren => true; + /// + protected override bool EnableUpdatingPremiereDateFromChildren => true; - /// - protected override IReadOnlyList GetChildrenForMetadataUpdates(BoxSet item) - { - return item.GetLinkedChildren(); - } + /// + protected override IReadOnlyList GetChildrenForMetadataUpdates(BoxSet item) + { + return item.GetLinkedChildren(); + } - /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) - { - base.MergeData(source, target, lockedFields, replaceData, mergeMetadataSettings); + /// + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) + { + base.MergeData(source, target, lockedFields, replaceData, mergeMetadataSettings); - var sourceItem = source.Item; - var targetItem = target.Item; + var sourceItem = source.Item; + var targetItem = target.Item; - if (mergeMetadataSettings) + if (mergeMetadataSettings) + { + if (replaceData || targetItem.LinkedChildren.Length == 0) + { + targetItem.LinkedChildren = sourceItem.LinkedChildren; + } + else { - if (replaceData || targetItem.LinkedChildren.Length == 0) - { - targetItem.LinkedChildren = sourceItem.LinkedChildren; - } - else - { - targetItem.LinkedChildren = sourceItem.LinkedChildren.Concat(targetItem.LinkedChildren).Distinct().ToArray(); - } + targetItem.LinkedChildren = sourceItem.LinkedChildren.Concat(targetItem.LinkedChildren).Distinct().ToArray(); } } + } - /// - protected override ItemUpdateType BeforeSaveInternal(BoxSet item, bool isFullRefresh, ItemUpdateType updateType) - { - var updatedType = base.BeforeSaveInternal(item, isFullRefresh, updateType); - - var libraryFolderIds = item.GetLibraryFolderIds(); + /// + protected override ItemUpdateType BeforeSaveInternal(BoxSet item, bool isFullRefresh, ItemUpdateType updateType) + { + var updatedType = base.BeforeSaveInternal(item, isFullRefresh, updateType); - var itemLibraryFolderIds = item.LibraryFolderIds; - if (itemLibraryFolderIds is null || !libraryFolderIds.SequenceEqual(itemLibraryFolderIds)) - { - item.LibraryFolderIds = libraryFolderIds; - updatedType |= ItemUpdateType.MetadataImport; - } + var libraryFolderIds = item.GetLibraryFolderIds(); - return updatedType; + var itemLibraryFolderIds = item.LibraryFolderIds; + if (itemLibraryFolderIds is null || !libraryFolderIds.SequenceEqual(itemLibraryFolderIds)) + { + item.LibraryFolderIds = libraryFolderIds; + updatedType |= ItemUpdateType.MetadataImport; } + + return updatedType; } } diff --git a/MediaBrowser.Providers/Channels/ChannelMetadataService.cs b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs index 0267fa13f..a1f77e0a8 100644 --- a/MediaBrowser.Providers/Channels/ChannelMetadataService.cs +++ b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs @@ -1,25 +1,41 @@ -#pragma warning disable CS1591 - using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; using MediaBrowser.Providers.Manager; using Microsoft.Extensions.Logging; -namespace MediaBrowser.Providers.Channels +namespace MediaBrowser.Providers.Channels; + +/// +/// Service to manage channel metadata. +/// +public class ChannelMetadataService : MetadataService { - public class ChannelMetadataService : MetadataService + /// + /// Initializes a new instance of the class. + /// + /// Instance of the . + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public ChannelMetadataService( + IServerConfigurationManager serverConfigurationManager, + ILogger logger, + IProviderManager providerManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + IPathManager pathManager, + IKeyframeManager keyframeManager, + IMediaSegmentManager mediaSegmentManager) + : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager, pathManager, keyframeManager, mediaSegmentManager) { - public ChannelMetadataService( - IServerConfigurationManager serverConfigurationManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem, - ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager) - { - } } } diff --git a/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs b/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs index 0629824d3..6407b1a61 100644 --- a/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs +++ b/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs @@ -1,25 +1,41 @@ -#pragma warning disable CS1591 - using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; using MediaBrowser.Providers.Manager; using Microsoft.Extensions.Logging; -namespace MediaBrowser.Providers.Folders +namespace MediaBrowser.Providers.Folders; + +/// +/// Service to manage collection folder metadata. +/// +public class CollectionFolderMetadataService : MetadataService { - public class CollectionFolderMetadataService : MetadataService + /// + /// Initializes a new instance of the class. + /// + /// Instance of the . + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public CollectionFolderMetadataService( + IServerConfigurationManager serverConfigurationManager, + ILogger logger, + IProviderManager providerManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + IPathManager pathManager, + IKeyframeManager keyframeManager, + IMediaSegmentManager mediaSegmentManager) + : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager, pathManager, keyframeManager, mediaSegmentManager) { - public CollectionFolderMetadataService( - IServerConfigurationManager serverConfigurationManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem, - ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager) - { - } } } diff --git a/MediaBrowser.Providers/Folders/FolderMetadataService.cs b/MediaBrowser.Providers/Folders/FolderMetadataService.cs index 79d52991a..7843f729d 100644 --- a/MediaBrowser.Providers/Folders/FolderMetadataService.cs +++ b/MediaBrowser.Providers/Folders/FolderMetadataService.cs @@ -1,29 +1,45 @@ -#pragma warning disable CS1591 - using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; using MediaBrowser.Providers.Manager; using Microsoft.Extensions.Logging; -namespace MediaBrowser.Providers.Folders +namespace MediaBrowser.Providers.Folders; + +/// +/// Service to manage folder metadata. +/// +public class FolderMetadataService : MetadataService { - public class FolderMetadataService : MetadataService + /// + /// Initializes a new instance of the class. + /// + /// Instance of the . + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public FolderMetadataService( + IServerConfigurationManager serverConfigurationManager, + ILogger logger, + IProviderManager providerManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + IPathManager pathManager, + IKeyframeManager keyframeManager, + IMediaSegmentManager mediaSegmentManager) + : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager, pathManager, keyframeManager, mediaSegmentManager) { - public FolderMetadataService( - IServerConfigurationManager serverConfigurationManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem, - ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager) - { - } - - /// - // Make sure the type-specific services get picked first - public override int Order => 10; } + + /// + // Make sure the type-specific services get picked first + public override int Order => 10; } diff --git a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs index 79c5597e5..834fba458 100644 --- a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs +++ b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs @@ -1,25 +1,41 @@ -#pragma warning disable CS1591 - using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; using MediaBrowser.Providers.Manager; using Microsoft.Extensions.Logging; -namespace MediaBrowser.Providers.Folders +namespace MediaBrowser.Providers.Folders; + +/// +/// Service to manage user view metadata. +/// +public class UserViewMetadataService : MetadataService { - public class UserViewMetadataService : MetadataService + /// + /// Initializes a new instance of the class. + /// + /// Instance of the . + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public UserViewMetadataService( + IServerConfigurationManager serverConfigurationManager, + ILogger logger, + IProviderManager providerManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + IPathManager pathManager, + IKeyframeManager keyframeManager, + IMediaSegmentManager mediaSegmentManager) + : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager, pathManager, keyframeManager, mediaSegmentManager) { - public UserViewMetadataService( - IServerConfigurationManager serverConfigurationManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem, - ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager) - { - } } } diff --git a/MediaBrowser.Providers/Genres/GenreMetadataService.cs b/MediaBrowser.Providers/Genres/GenreMetadataService.cs index 4d10d8987..2a2a0bf50 100644 --- a/MediaBrowser.Providers/Genres/GenreMetadataService.cs +++ b/MediaBrowser.Providers/Genres/GenreMetadataService.cs @@ -1,25 +1,41 @@ -#pragma warning disable CS1591 - using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; using MediaBrowser.Providers.Manager; using Microsoft.Extensions.Logging; -namespace MediaBrowser.Providers.Genres +namespace MediaBrowser.Providers.Genres; + +/// +/// Service to manage genre metadata. +/// +public class GenreMetadataService : MetadataService { - public class GenreMetadataService : MetadataService + /// + /// Initializes a new instance of the class. + /// + /// Instance of the . + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public GenreMetadataService( + IServerConfigurationManager serverConfigurationManager, + ILogger logger, + IProviderManager providerManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + IPathManager pathManager, + IKeyframeManager keyframeManager, + IMediaSegmentManager mediaSegmentManager) + : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager, pathManager, keyframeManager, mediaSegmentManager) { - public GenreMetadataService( - IServerConfigurationManager serverConfigurationManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem, - ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager) - { - } } } diff --git a/MediaBrowser.Providers/LiveTv/LiveTvMetadataService.cs b/MediaBrowser.Providers/LiveTv/LiveTvMetadataService.cs index c94d36530..9e4d91019 100644 --- a/MediaBrowser.Providers/LiveTv/LiveTvMetadataService.cs +++ b/MediaBrowser.Providers/LiveTv/LiveTvMetadataService.cs @@ -1,25 +1,41 @@ -#pragma warning disable CS1591 - using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; using MediaBrowser.Providers.Manager; using Microsoft.Extensions.Logging; -namespace MediaBrowser.Providers.LiveTv +namespace MediaBrowser.Providers.LiveTv; + +/// +/// Service to manage live TV metadata. +/// +public class LiveTvMetadataService : MetadataService { - public class LiveTvMetadataService : MetadataService + /// + /// Initializes a new instance of the class. + /// + /// Instance of the . + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public LiveTvMetadataService( + IServerConfigurationManager serverConfigurationManager, + ILogger logger, + IProviderManager providerManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + IPathManager pathManager, + IKeyframeManager keyframeManager, + IMediaSegmentManager mediaSegmentManager) + : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager, pathManager, keyframeManager, mediaSegmentManager) { - public LiveTvMetadataService( - IServerConfigurationManager serverConfigurationManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem, - ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager) - { - } } } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 50bbf0974..c4d4e775a 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net.Http; using System.Threading; @@ -12,7 +13,9 @@ using Jellyfin.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; @@ -26,13 +29,24 @@ namespace MediaBrowser.Providers.Manager where TItemType : BaseItem, IHasLookupInfo, new() where TIdType : ItemLookupInfo, new() { - protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger> logger, IProviderManager providerManager, IFileSystem fileSystem, ILibraryManager libraryManager) + protected MetadataService( + IServerConfigurationManager serverConfigurationManager, + ILogger> logger, + IProviderManager providerManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + IPathManager pathManager, + IKeyframeManager keyframeManager, + IMediaSegmentManager mediaSegmentManager) { ServerConfigurationManager = serverConfigurationManager; Logger = logger; ProviderManager = providerManager; FileSystem = fileSystem; LibraryManager = libraryManager; + PathManager = pathManager; + KeyframeManager = keyframeManager; + MediaSegmentManager = mediaSegmentManager; ImageProvider = new ItemImageProvider(Logger, ProviderManager, FileSystem); } @@ -48,6 +62,12 @@ namespace MediaBrowser.Providers.Manager protected ILibraryManager LibraryManager { get; } + protected IPathManager PathManager { get; } + + protected IKeyframeManager KeyframeManager { get; } + + protected IMediaSegmentManager MediaSegmentManager { get; } + protected virtual bool EnableUpdatingPremiereDateFromChildren => false; protected virtual bool EnableUpdatingGenresFromChildren => false; @@ -303,6 +323,55 @@ namespace MediaBrowser.Providers.Manager updateType |= ItemUpdateType.MetadataImport; } + // Cleanup extracted files if source file was modified + var itemPath = item.Path; + if (!string.IsNullOrEmpty(itemPath)) + { + var info = FileSystem.GetFileSystemInfo(itemPath); + var modificationDate = info.LastWriteTimeUtc; + var itemLastModifiedFileSystem = item.DateModified; + if (info.Exists && itemLastModifiedFileSystem != modificationDate) + { + Logger.LogDebug("File modification time changed from {Then} to {Now}: {Path}", itemLastModifiedFileSystem, modificationDate, itemPath); + + item.DateModified = modificationDate; + if (ServerConfigurationManager.GetMetadataConfiguration().UseFileCreationTimeForDateAdded) + { + item.DateCreated = info.CreationTimeUtc; + } + + var size = info.Length; + if (item is Video video) + { + var videoType = video.VideoType; + var sizeChanged = size != (video.Size ?? 0); + if (videoType == VideoType.BluRay || video.VideoType == VideoType.Dvd || sizeChanged) + { + if (sizeChanged) + { + item.Size = size; + Logger.LogDebug("File size changed from {Then} to {Now}: {Path}", video.Size, size, itemPath); + } + + var validPaths = PathManager.GetExtractedDataPaths(video).Where(Directory.Exists).ToList(); + if (validPaths.Count > 0) + { + Logger.LogInformation("File changed, pruning extracted data: {Path}", itemPath); + foreach (var path in validPaths) + { + Directory.Delete(path, true); + } + } + + KeyframeManager.DeleteKeyframeDataAsync(video.Id, CancellationToken.None).GetAwaiter().GetResult(); + MediaSegmentManager.DeleteSegmentsAsync(item.Id).GetAwaiter().GetResult(); + } + } + + updateType |= ItemUpdateType.MetadataImport; + } + } + return updateType; } @@ -1132,6 +1201,11 @@ namespace MediaBrowser.Providers.Manager target.DateCreated = source.DateCreated; } + if (replaceData || source.DateModified != default) + { + target.DateModified = source.DateModified; + } + if (replaceData || string.IsNullOrEmpty(target.PreferredMetadataCountryCode)) { target.PreferredMetadataCountryCode = source.PreferredMetadataCountryCode; diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 856f33b49..1a29548f2 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -1,13 +1,11 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Mime; -using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; @@ -24,6 +22,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Lyrics; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Subtitles; using MediaBrowser.Model.Configuration; diff --git a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs index 286ba0de0..4fd3ab973 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs @@ -133,7 +133,6 @@ namespace MediaBrowser.Providers.MediaInfo audio.TotalBitrate = mediaInfo.Bitrate; audio.RunTimeTicks = mediaInfo.RunTimeTicks; - audio.Size = mediaInfo.Size; // Add external lyrics first to prevent the lrc file get overwritten on first scan var mediaStreams = new List(mediaInfo.MediaStreams); diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 7947ba921..7c88a0e7d 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -214,10 +214,14 @@ namespace MediaBrowser.Providers.MediaInfo mediaAttachments = mediaInfo.MediaAttachments; video.TotalBitrate = mediaInfo.Bitrate; video.RunTimeTicks = mediaInfo.RunTimeTicks; - video.Size = mediaInfo.Size; video.Container = mediaInfo.Container; + var videoType = video.VideoType; + if (videoType == VideoType.BluRay || videoType == VideoType.Dvd) + { + video.Size = mediaInfo.Size; + } - chapters = mediaInfo.Chapters ?? Array.Empty(); + chapters = mediaInfo.Chapters ?? []; if (blurayInfo is not null) { FetchBdInfo(video, ref chapters, mediaStreams, blurayInfo); @@ -234,8 +238,8 @@ namespace MediaBrowser.Providers.MediaInfo } } - mediaAttachments = Array.Empty(); - chapters = Array.Empty(); + mediaAttachments = []; + chapters = []; } var libraryOptions = _libraryManager.GetLibraryOptions(video); @@ -400,7 +404,7 @@ namespace MediaBrowser.Providers.MediaInfo { if (video.Genres.Length == 0 || replaceData) { - video.Genres = Array.Empty(); + video.Genres = []; foreach (var genre in data.Genres.Trimmed()) { @@ -643,7 +647,7 @@ namespace MediaBrowser.Providers.MediaInfo long dummyChapterDuration = TimeSpan.FromSeconds(_config.Configuration.DummyChapterDuration).Ticks; if (runtime <= dummyChapterDuration) { - return Array.Empty(); + return []; } int chapterCount = (int)(runtime / dummyChapterDuration); diff --git a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs index ba6034ec1..8c673350d 100644 --- a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs @@ -130,9 +130,9 @@ namespace MediaBrowser.Providers.MediaInfo if (!string.IsNullOrWhiteSpace(path) && item.IsFileProtocol) { var file = directoryService.GetFile(path); - if (file is not null && file.LastWriteTimeUtc != item.DateModified) + if (file is not null && file.LastWriteTimeUtc != item.DateModified && file.Length != item.Size) { - _logger.LogDebug("Refreshing {ItemPath} due to date modified timestamp change.", path); + _logger.LogDebug("Refreshing {ItemPath} due to file system modification.", path); return true; } } diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs index 938f3cb32..1134baf92 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs @@ -14,7 +14,6 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Subtitles; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Providers; using MediaBrowser.Model.Tasks; diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs index 8997ddc64..0779e17bd 100644 --- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs +++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs @@ -1,40 +1,56 @@ -#pragma warning disable CS1591 - using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Providers.Manager; using Microsoft.Extensions.Logging; -namespace MediaBrowser.Providers.Movies +namespace MediaBrowser.Providers.Movies; + +/// +/// Service to manage movie metadata. +/// +public class MovieMetadataService : MetadataService { - public class MovieMetadataService : MetadataService + /// + /// Initializes a new instance of the class. + /// + /// Instance of the . + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public MovieMetadataService( + IServerConfigurationManager serverConfigurationManager, + ILogger logger, + IProviderManager providerManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + IPathManager pathManager, + IKeyframeManager keyframeManager, + IMediaSegmentManager mediaSegmentManager) + : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager, pathManager, keyframeManager, mediaSegmentManager) { - public MovieMetadataService( - IServerConfigurationManager serverConfigurationManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem, - ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager) - { - } + } - /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) - { - base.MergeData(source, target, lockedFields, replaceData, mergeMetadataSettings); + /// + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) + { + base.MergeData(source, target, lockedFields, replaceData, mergeMetadataSettings); - var sourceItem = source.Item; - var targetItem = target.Item; + var sourceItem = source.Item; + var targetItem = target.Item; - if (replaceData || string.IsNullOrEmpty(targetItem.CollectionName)) - { - targetItem.CollectionName = sourceItem.CollectionName; - } + if (replaceData || string.IsNullOrEmpty(targetItem.CollectionName)) + { + targetItem.CollectionName = sourceItem.CollectionName; } } } diff --git a/MediaBrowser.Providers/Movies/TrailerMetadataService.cs b/MediaBrowser.Providers/Movies/TrailerMetadataService.cs index e77d2fa8a..bf8735ad4 100644 --- a/MediaBrowser.Providers/Movies/TrailerMetadataService.cs +++ b/MediaBrowser.Providers/Movies/TrailerMetadataService.cs @@ -1,42 +1,58 @@ -#pragma warning disable CS1591 - using System.Linq; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Providers.Manager; using Microsoft.Extensions.Logging; -namespace MediaBrowser.Providers.Movies +namespace MediaBrowser.Providers.Movies; + +/// +/// Service to manage trailer metadata. +/// +public class TrailerMetadataService : MetadataService { - public class TrailerMetadataService : MetadataService + /// + /// Initializes a new instance of the class. + /// + /// Instance of the . + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public TrailerMetadataService( + IServerConfigurationManager serverConfigurationManager, + ILogger logger, + IProviderManager providerManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + IPathManager pathManager, + IKeyframeManager keyframeManager, + IMediaSegmentManager mediaSegmentManager) + : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager, pathManager, keyframeManager, mediaSegmentManager) + { + } + + /// + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { - public TrailerMetadataService( - IServerConfigurationManager serverConfigurationManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem, - ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager) + base.MergeData(source, target, lockedFields, replaceData, mergeMetadataSettings); + + if (replaceData || target.Item.TrailerTypes.Length == 0) { + target.Item.TrailerTypes = source.Item.TrailerTypes; } - - /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) + else { - base.MergeData(source, target, lockedFields, replaceData, mergeMetadataSettings); - - if (replaceData || target.Item.TrailerTypes.Length == 0) - { - target.Item.TrailerTypes = source.Item.TrailerTypes; - } - else - { - target.Item.TrailerTypes = target.Item.TrailerTypes.Concat(source.Item.TrailerTypes).Distinct().ToArray(); - } + target.Item.TrailerTypes = target.Item.TrailerTypes.Concat(source.Item.TrailerTypes).Distinct().ToArray(); } } } diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs index 64b627367..cc6d7953d 100644 --- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs +++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs @@ -5,245 +5,252 @@ using Jellyfin.Data.Enums; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Providers.Manager; using Microsoft.Extensions.Logging; -namespace MediaBrowser.Providers.Music +namespace MediaBrowser.Providers.Music; + +/// +/// The album metadata service. +/// +public class AlbumMetadataService : MetadataService { /// - /// The album metadata service. + /// Initializes a new instance of the class. /// - public class AlbumMetadataService : MetadataService + /// Instance of the . + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public AlbumMetadataService( + IServerConfigurationManager serverConfigurationManager, + ILogger logger, + IProviderManager providerManager, + IFileSystem fileSystem, + ILibraryManager libraryManager, + IPathManager pathManager, + IKeyframeManager keyframeManager, + IMediaSegmentManager mediaSegmentManager) + : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager, pathManager, keyframeManager, mediaSegmentManager) { - /// - /// Initializes a new instance of the class. - /// - /// Instance of the . - /// Instance of the interface. - /// Instance of the interface. - /// Instance of the interface. - /// Instance of the interface. - public AlbumMetadataService( - IServerConfigurationManager serverConfigurationManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem, - ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager) - { - } + } + + /// + protected override bool EnableUpdatingPremiereDateFromChildren => true; - /// - protected override bool EnableUpdatingPremiereDateFromChildren => true; + /// + protected override bool EnableUpdatingGenresFromChildren => true; - /// - protected override bool EnableUpdatingGenresFromChildren => true; + /// + protected override bool EnableUpdatingStudiosFromChildren => true; - /// - protected override bool EnableUpdatingStudiosFromChildren => true; + /// + protected override IReadOnlyList GetChildrenForMetadataUpdates(MusicAlbum item) + => item.GetRecursiveChildren(i => i is Audio); - /// - protected override IReadOnlyList GetChildrenForMetadataUpdates(MusicAlbum item) - => item.GetRecursiveChildren(i => i is Audio); + /// + protected override ItemUpdateType UpdateMetadataFromChildren(MusicAlbum item, IReadOnlyList children, bool isFullRefresh, ItemUpdateType currentUpdateType) + { + var updateType = base.UpdateMetadataFromChildren(item, children, isFullRefresh, currentUpdateType); - /// - protected override ItemUpdateType UpdateMetadataFromChildren(MusicAlbum item, IReadOnlyList children, bool isFullRefresh, ItemUpdateType currentUpdateType) + // don't update user-changeable metadata for locked items + if (item.IsLocked) { - var updateType = base.UpdateMetadataFromChildren(item, children, isFullRefresh, currentUpdateType); + return updateType; + } - // don't update user-changeable metadata for locked items - if (item.IsLocked) + if (isFullRefresh || currentUpdateType > ItemUpdateType.None) + { + if (!item.LockedFields.Contains(MetadataField.Name)) { - return updateType; - } + var name = children.Select(i => i.Album).FirstOrDefault(i => !string.IsNullOrEmpty(i)); - if (isFullRefresh || currentUpdateType > ItemUpdateType.None) - { - if (!item.LockedFields.Contains(MetadataField.Name)) + if (!string.IsNullOrEmpty(name) + && !string.Equals(item.Name, name, StringComparison.Ordinal)) { - var name = children.Select(i => i.Album).FirstOrDefault(i => !string.IsNullOrEmpty(i)); - - if (!string.IsNullOrEmpty(name) - && !string.Equals(item.Name, name, StringComparison.Ordinal)) - { - item.Name = name; - updateType |= ItemUpdateType.MetadataEdit; - } + item.Name = name; + updateType |= ItemUpdateType.MetadataEdit; } - - var songs = children.Cast