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 --- Emby.Server.Implementations/Library/LibraryManager.cs | 1 + Emby.Server.Implementations/Library/MediaSourceManager.cs | 1 + Emby.Server.Implementations/Library/UserViewManager.cs | 1 + 3 files changed, 3 insertions(+) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 93ee47fe81..1fc9ccb141 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 d0f5e60f79..669db65f7d 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 e9cf47d462..b4e05ebf03 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; -- cgit v1.2.3 From 06be4998e189729170a6f6dbbca68a0790c72d43 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Tue, 25 Feb 2025 15:26:47 -0500 Subject: Backport pull request #13611 from jellyfin/release-10.10.z Remove empty ParentIndexNumber workaround Original-merge: 1daf761aece5114a6ac3b7b938f114e70b83d99e Merged-by: Bond-009 Backported-by: Bond_009 --- Emby.Server.Implementations/Library/LibraryManager.cs | 9 --------- MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs | 5 ++--- .../Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs | 6 +++--- MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs | 10 +++++----- 4 files changed, 10 insertions(+), 20 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index c483f3c61f..8568104941 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2630,15 +2630,6 @@ namespace Emby.Server.Implementations.Library { episode.ParentIndexNumber = season.IndexNumber; } - else - { - /* - Anime series don't generally have a season in their file name, however, - TVDb needs a season to correctly get the metadata. - Hence, a null season needs to be filled with something. */ - // FIXME perhaps this would be better for TVDb parser to ask for season 1 if no season is specified - episode.ParentIndexNumber = 1; - } if (episode.ParentIndexNumber.HasValue) { diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs index d8b33a799f..ccff31ebaa 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs @@ -55,13 +55,12 @@ namespace MediaBrowser.Providers.Plugins.Omdb if (info.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out string? seriesImdbId) && !string.IsNullOrEmpty(seriesImdbId) - && info.IndexNumber.HasValue - && info.ParentIndexNumber.HasValue) + && info.IndexNumber.HasValue) { result.HasMetadata = await _omdbProvider.FetchEpisodeData( result, info.IndexNumber.Value, - info.ParentIndexNumber.Value, + info.ParentIndexNumber ?? 1, info.GetProviderId(MetadataProvider.Imdb), seriesImdbId, info.MetadataLanguage, diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs index d1fec7cb13..7de0e430f2 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs @@ -63,10 +63,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV return Enumerable.Empty(); } - var seasonNumber = episode.ParentIndexNumber; + var seasonNumber = episode.ParentIndexNumber ?? 1; var episodeNumber = episode.IndexNumber; - if (!seasonNumber.HasValue || !episodeNumber.HasValue) + if (!episodeNumber.HasValue) { return Enumerable.Empty(); } @@ -75,7 +75,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV // TODO use image languages if All Languages isn't toggled, but there's currently no way to get that value in here var episodeResult = await _tmdbClientManager - .GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, series.DisplayOrder, null, null, cancellationToken) + .GetEpisodeAsync(seriesTmdbId, seasonNumber, episodeNumber.Value, series.DisplayOrder, null, null, cancellationToken) .ConfigureAwait(false); var stills = episodeResult?.Images?.Stills; diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs index e628abde55..c93dabb66c 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs @@ -47,7 +47,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV public async Task> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken) { // The search query must either provide an episode number or date - if (!searchInfo.IndexNumber.HasValue || !searchInfo.ParentIndexNumber.HasValue) + if (!searchInfo.IndexNumber.HasValue) { return Enumerable.Empty(); } @@ -96,10 +96,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV return metadataResult; } - var seasonNumber = info.ParentIndexNumber; + var seasonNumber = info.ParentIndexNumber ?? 1; var episodeNumber = info.IndexNumber; - if (!seasonNumber.HasValue || !episodeNumber.HasValue) + if (!episodeNumber.HasValue) { return metadataResult; } @@ -112,7 +112,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV List? result = null; for (int? episode = startindex; episode <= endindex; episode++) { - var episodeInfo = await _tmdbClientManager.GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episode.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken).ConfigureAwait(false); + var episodeInfo = await _tmdbClientManager.GetEpisodeAsync(seriesTmdbId, seasonNumber, episode.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken).ConfigureAwait(false); if (episodeInfo is not null) { (result ??= new List()).Add(episodeInfo); @@ -156,7 +156,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV else { episodeResult = await _tmdbClientManager - .GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken) + .GetEpisodeAsync(seriesTmdbId, seasonNumber, episodeNumber.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken) .ConfigureAwait(false); } -- cgit v1.2.3 From 1131b051d8ec9f5cb0d0b3d42852c1a022a04932 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Tue, 25 Feb 2025 15:32:03 -0500 Subject: Backport pull request #13601 from jellyfin/release-10.10.z Delete children from cache on parent delete Original-merge: 767a5e61930897d6151bf2b5b6c4940a288deb41 Merged-by: Bond-009 Backported-by: Bond_009 --- Emby.Server.Implementations/Library/LibraryManager.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 8568104941..cc2092e21e 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -457,6 +457,7 @@ namespace Emby.Server.Implementations.Library foreach (var child in children) { _itemRepository.DeleteItem(child.Id); + _cache.TryRemove(child.Id, out _); } _cache.TryRemove(item.Id, out _); -- cgit v1.2.3 From 85b5bebda4a887bad03a114e727d9ee5d87961cc Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Tue, 18 Mar 2025 17:37:04 -0600 Subject: Add fast-path to getting just the SeriesPresentationUniqueKey for NextUp (#13687) * Add more optimized query to calculate series that should be processed for next up * Filter series based on last watched date --- .../Library/LibraryManager.cs | 15 +++ Emby.Server.Implementations/TV/TVSeriesManager.cs | 61 ++--------- Jellyfin.Api/Controllers/TvShowsController.cs | 4 +- .../Item/BaseItemRepository.cs | 31 ++++++ MediaBrowser.Controller/Library/ILibraryManager.cs | 9 ++ .../Persistence/IItemRepository.cs | 8 ++ MediaBrowser.Model/Querying/NextUpQuery.cs | 113 ++++++++++----------- 7 files changed, 128 insertions(+), 113 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index cc2092e21e..7b3a540398 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1344,6 +1344,21 @@ namespace Emby.Server.Implementations.Library return _itemRepository.GetItemList(query); } + public IReadOnlyList GetNextUpSeriesKeys(InternalItemsQuery query, IReadOnlyCollection parents, DateTime dateCutoff) + { + SetTopParentIdsOrAncestors(query, parents); + + if (query.AncestorIds.Length == 0 && query.TopParentIds.Length == 0) + { + if (query.User is not null) + { + AddUserToQuery(query, query.User); + } + } + + return _itemRepository.GetNextUpSeriesKeys(query, dateCutoff); + } + public QueryResult QueryItems(InternalItemsQuery query) { if (query.User is not null) diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs index f8ce473da3..10d27498bf 100644 --- a/Emby.Server.Implementations/TV/TVSeriesManager.cs +++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs @@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.TV if (!string.IsNullOrEmpty(presentationUniqueKey)) { - return GetResult(GetNextUpEpisodes(request, user, new[] { presentationUniqueKey }, options), request); + return GetResult(GetNextUpEpisodes(request, user, [presentationUniqueKey], options), request); } if (limit.HasValue) @@ -99,25 +99,9 @@ namespace Emby.Server.Implementations.TV limit = limit.Value + 10; } - var items = _libraryManager - .GetItemList( - new InternalItemsQuery(user) - { - IncludeItemTypes = new[] { BaseItemKind.Episode }, - OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending) }, - SeriesPresentationUniqueKey = presentationUniqueKey, - Limit = limit, - DtoOptions = new DtoOptions { Fields = new[] { ItemFields.SeriesPresentationUniqueKey }, EnableImages = false }, - GroupBySeriesPresentationUniqueKey = true - }, - parentsFolders.ToList()) - .Cast() - .Where(episode => !string.IsNullOrEmpty(episode.SeriesPresentationUniqueKey)) - .Select(GetUniqueSeriesKey) - .ToList(); - - // Avoid implicitly captured closure - var episodes = GetNextUpEpisodes(request, user, items.Distinct().ToArray(), options); + var nextUpSeriesKeys = _libraryManager.GetNextUpSeriesKeys(new InternalItemsQuery(user) { Limit = limit }, parentsFolders, request.NextUpDateCutoff); + + var episodes = GetNextUpEpisodes(request, user, nextUpSeriesKeys, options); return GetResult(episodes, request); } @@ -133,36 +117,11 @@ namespace Emby.Server.Implementations.TV .OrderByDescending(i => i.LastWatchedDate); } - // If viewing all next up for all series, remove first episodes - // But if that returns empty, keep those first episodes (avoid completely empty view) - var alwaysEnableFirstEpisode = !request.SeriesId.IsNullOrEmpty(); - var anyFound = false; - return allNextUp - .Where(i => - { - if (request.DisableFirstEpisode) - { - return i.LastWatchedDate != DateTime.MinValue; - } - - if (alwaysEnableFirstEpisode || (i.LastWatchedDate != DateTime.MinValue && i.LastWatchedDate.Date >= request.NextUpDateCutoff)) - { - anyFound = true; - return true; - } - - return !anyFound && i.LastWatchedDate == DateTime.MinValue; - }) .Select(i => i.GetEpisodeFunction()) .Where(i => i is not null)!; } - private static string GetUniqueSeriesKey(Episode episode) - { - return episode.SeriesPresentationUniqueKey; - } - private static string GetUniqueSeriesKey(Series series) { return series.GetPresentationUniqueKey(); @@ -178,13 +137,13 @@ namespace Emby.Server.Implementations.TV { AncestorWithPresentationUniqueKey = null, SeriesPresentationUniqueKey = seriesKey, - IncludeItemTypes = new[] { BaseItemKind.Episode }, + IncludeItemTypes = [BaseItemKind.Episode], IsPlayed = true, Limit = 1, ParentIndexNumberNotEquals = 0, DtoOptions = new DtoOptions { - Fields = new[] { ItemFields.SortName }, + Fields = [ItemFields.SortName], EnableImages = false } }; @@ -202,8 +161,8 @@ namespace Emby.Server.Implementations.TV { AncestorWithPresentationUniqueKey = null, SeriesPresentationUniqueKey = seriesKey, - IncludeItemTypes = new[] { BaseItemKind.Episode }, - OrderBy = new[] { (ItemSortBy.ParentIndexNumber, SortOrder.Ascending), (ItemSortBy.IndexNumber, SortOrder.Ascending) }, + IncludeItemTypes = [BaseItemKind.Episode], + OrderBy = [(ItemSortBy.ParentIndexNumber, SortOrder.Ascending), (ItemSortBy.IndexNumber, SortOrder.Ascending)], Limit = 1, IsPlayed = includePlayed, IsVirtualItem = false, @@ -228,7 +187,7 @@ namespace Emby.Server.Implementations.TV AncestorWithPresentationUniqueKey = null, SeriesPresentationUniqueKey = seriesKey, ParentIndexNumber = 0, - IncludeItemTypes = new[] { BaseItemKind.Episode }, + IncludeItemTypes = [BaseItemKind.Episode], IsPlayed = includePlayed, IsVirtualItem = false, DtoOptions = dtoOptions @@ -248,7 +207,7 @@ namespace Emby.Server.Implementations.TV consideredEpisodes.Add(nextEpisode); } - var sortedConsideredEpisodes = _libraryManager.Sort(consideredEpisodes, user, new[] { (ItemSortBy.AiredEpisodeOrder, SortOrder.Ascending) }) + var sortedConsideredEpisodes = _libraryManager.Sort(consideredEpisodes, user, [(ItemSortBy.AiredEpisodeOrder, SortOrder.Ascending)]) .Cast(); if (lastWatchedEpisode is not null) { diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index df46c2dac9..cc070244b1 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; @@ -86,7 +87,7 @@ public class TvShowsController : BaseJellyfinApiController [FromQuery] bool? enableUserData, [FromQuery] DateTime? nextUpDateCutoff, [FromQuery] bool enableTotalRecordCount = true, - [FromQuery] bool disableFirstEpisode = false, + [FromQuery][ParameterObsolete] bool disableFirstEpisode = false, [FromQuery] bool enableResumable = true, [FromQuery] bool enableRewatching = false) { @@ -109,7 +110,6 @@ public class TvShowsController : BaseJellyfinApiController StartIndex = startIndex, User = user, EnableTotalRecordCount = enableTotalRecordCount, - DisableFirstEpisode = disableFirstEpisode, NextUpDateCutoff = nextUpDateCutoff ?? DateTime.MinValue, EnableResumable = enableResumable, EnableRewatching = enableRewatching diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs index 392b7de74f..e20ad79ad1 100644 --- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs +++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs @@ -255,6 +255,37 @@ public sealed class BaseItemRepository return dbQuery.AsEnumerable().Where(e => e is not null).Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToArray(); } + /// + public IReadOnlyList GetNextUpSeriesKeys(InternalItemsQuery filter, DateTime dateCutoff) + { + ArgumentNullException.ThrowIfNull(filter); + ArgumentNullException.ThrowIfNull(filter.User); + + using var context = _dbProvider.CreateDbContext(); + + var query = context.BaseItems + .AsNoTracking() + .Where(i => filter.TopParentIds.Contains(i.TopParentId!.Value)) + .Where(i => i.Type == _itemTypeLookup.BaseItemKindNames[BaseItemKind.Episode]) + .Join( + context.UserData.AsNoTracking(), + i => new { UserId = filter.User.Id, ItemId = i.Id }, + u => new { UserId = u.UserId, ItemId = u.ItemId }, + (entity, data) => new { Item = entity, UserData = data }) + .GroupBy(g => g.Item.SeriesPresentationUniqueKey) + .Select(g => new { g.Key, LastPlayedDate = g.Max(u => u.UserData.LastPlayedDate) }) + .Where(g => g.Key != null && g.LastPlayedDate != null && g.LastPlayedDate >= dateCutoff) + .OrderByDescending(g => g.LastPlayedDate) + .Select(g => g.Key!); + + if (filter.Limit.HasValue) + { + query = query.Take(filter.Limit.Value); + } + + return query.ToArray(); + } + private IQueryable ApplyGroupingFilter(IQueryable dbQuery, InternalItemsQuery filter) { // This whole block is needed to filter duplicate entries on request diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 47b1cb16e8..03a28fd8c0 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -565,6 +565,15 @@ namespace MediaBrowser.Controller.Library /// List of items. IReadOnlyList GetItemList(InternalItemsQuery query, List parents); + /// + /// Gets the list of series presentation keys for next up. + /// + /// The query to use. + /// Items to use for query. + /// The minimum date for a series to have been most recently watched. + /// List of series presentation keys. + IReadOnlyList GetNextUpSeriesKeys(InternalItemsQuery query, IReadOnlyCollection parents, DateTime dateCutoff); + /// /// Gets the items result. /// diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index afe2d833d5..f1ed4fe274 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -59,6 +59,14 @@ public interface IItemRepository /// List<BaseItem>. IReadOnlyList GetItemList(InternalItemsQuery filter); + /// + /// Gets the list of series presentation keys for next up. + /// + /// The query. + /// The minimum date for a series to have been most recently watched. + /// The list of keys. + IReadOnlyList GetNextUpSeriesKeys(InternalItemsQuery filter, DateTime dateCutoff); + /// /// Updates the inherited values. /// diff --git a/MediaBrowser.Model/Querying/NextUpQuery.cs b/MediaBrowser.Model/Querying/NextUpQuery.cs index 8dece28a09..aee720aa7b 100644 --- a/MediaBrowser.Model/Querying/NextUpQuery.cs +++ b/MediaBrowser.Model/Querying/NextUpQuery.cs @@ -4,76 +4,69 @@ using System; using Jellyfin.Data.Entities; using MediaBrowser.Model.Entities; -namespace MediaBrowser.Model.Querying +namespace MediaBrowser.Model.Querying; + +public class NextUpQuery { - public class NextUpQuery + public NextUpQuery() { - public NextUpQuery() - { - EnableImageTypes = Array.Empty(); - EnableTotalRecordCount = true; - DisableFirstEpisode = false; - NextUpDateCutoff = DateTime.MinValue; - EnableResumable = false; - EnableRewatching = false; - } - - /// - /// Gets or sets the user. - /// - /// The user. - public required User User { get; set; } + EnableImageTypes = Array.Empty(); + EnableTotalRecordCount = true; + NextUpDateCutoff = DateTime.MinValue; + EnableResumable = false; + EnableRewatching = false; + } - /// - /// Gets or sets the parent identifier. - /// - /// The parent identifier. - public Guid? ParentId { get; set; } + /// + /// Gets or sets the user. + /// + /// The user. + public required User User { get; set; } - /// - /// Gets or sets the series id. - /// - /// The series id. - public Guid? SeriesId { get; set; } + /// + /// Gets or sets the parent identifier. + /// + /// The parent identifier. + public Guid? ParentId { get; set; } - /// - /// Gets or sets the start index. Use for paging. - /// - /// The start index. - public int? StartIndex { get; set; } + /// + /// Gets or sets the series id. + /// + /// The series id. + public Guid? SeriesId { get; set; } - /// - /// Gets or sets the maximum number of items to return. - /// - /// The limit. - public int? Limit { get; set; } + /// + /// Gets or sets the start index. Use for paging. + /// + /// The start index. + public int? StartIndex { get; set; } - /// - /// Gets or sets the enable image types. - /// - /// The enable image types. - public ImageType[] EnableImageTypes { get; set; } + /// + /// Gets or sets the maximum number of items to return. + /// + /// The limit. + public int? Limit { get; set; } - public bool EnableTotalRecordCount { get; set; } + /// + /// Gets or sets the enable image types. + /// + /// The enable image types. + public ImageType[] EnableImageTypes { get; set; } - /// - /// Gets or sets a value indicating whether do disable sending first episode as next up. - /// - public bool DisableFirstEpisode { get; set; } + public bool EnableTotalRecordCount { get; set; } - /// - /// Gets or sets a value indicating the oldest date for a show to appear in Next Up. - /// - public DateTime NextUpDateCutoff { get; set; } + /// + /// Gets or sets a value indicating the oldest date for a show to appear in Next Up. + /// + public DateTime NextUpDateCutoff { get; set; } - /// - /// Gets or sets a value indicating whether to include resumable episodes as next up. - /// - public bool EnableResumable { get; set; } + /// + /// Gets or sets a value indicating whether to include resumable episodes as next up. + /// + public bool EnableResumable { get; set; } - /// - /// Gets or sets a value indicating whether getting rewatching next up list. - /// - public bool EnableRewatching { get; set; } - } + /// + /// Gets or sets a value indicating whether getting rewatching next up list. + /// + public bool EnableRewatching { get; set; } } -- cgit v1.2.3 From c24d0c1240d300a4912bb7c6810063b16078927f Mon Sep 17 00:00:00 2001 From: timminator <150205162+timminator@users.noreply.github.com> Date: Wed, 19 Mar 2025 00:40:06 +0100 Subject: Respect preferred language when selecting forced subtitles (#13098) Rework subtitle selection logic --- .../Library/MediaStreamSelector.cs | 86 +++++++++++++++------- 1 file changed, 60 insertions(+), 26 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs index ea223e3ece..6791e3ca90 100644 --- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs +++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs @@ -39,46 +39,48 @@ namespace Emby.Server.Implementations.Library return null; } + // Sort in the following order: Default > No tag > Forced var sortedStreams = streams .Where(i => i.Type == MediaStreamType.Subtitle) .OrderByDescending(x => x.IsExternal) - .ThenByDescending(x => x.IsForced && string.Equals(x.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) - .ThenByDescending(x => x.IsForced) .ThenByDescending(x => x.IsDefault) - .ThenByDescending(x => preferredLanguages.Contains(x.Language, StringComparison.OrdinalIgnoreCase)) + .ThenByDescending(x => !x.IsForced && MatchesPreferredLanguage(x.Language, preferredLanguages)) + .ThenByDescending(x => x.IsForced && MatchesPreferredLanguage(x.Language, preferredLanguages)) + .ThenByDescending(x => x.IsForced && IsLanguageUndefined(x.Language)) + .ThenByDescending(x => x.IsForced) .ToList(); MediaStream? stream = null; + if (mode == SubtitlePlaybackMode.Default) { - // Load subtitles according to external, forced and default flags. - stream = sortedStreams.FirstOrDefault(x => x.IsExternal || x.IsForced || x.IsDefault); + // Load subtitles according to external, default and forced flags. + stream = sortedStreams.FirstOrDefault(x => x.IsExternal || x.IsDefault || x.IsForced); } else if (mode == SubtitlePlaybackMode.Smart) { // Only attempt to load subtitles if the audio language is not one of the user's preferred subtitle languages. - // If no subtitles of preferred language available, use default behaviour. + // If no subtitles of preferred language available, use none. + // If the audio language is one of the user's preferred subtitle languages behave like OnlyForced. if (!preferredLanguages.Contains(audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) { - stream = sortedStreams.FirstOrDefault(x => preferredLanguages.Contains(x.Language, StringComparison.OrdinalIgnoreCase)) ?? - sortedStreams.FirstOrDefault(x => x.IsExternal || x.IsForced || x.IsDefault); + stream = sortedStreams.FirstOrDefault(x => MatchesPreferredLanguage(x.Language, preferredLanguages)); } else { - // Respect forced flag. - stream = sortedStreams.FirstOrDefault(x => x.IsForced); + stream = BehaviorOnlyForced(sortedStreams, preferredLanguages).FirstOrDefault(); } } else if (mode == SubtitlePlaybackMode.Always) { - // Always load (full/non-forced) subtitles of the user's preferred subtitle language if possible, otherwise default behaviour. - stream = sortedStreams.FirstOrDefault(x => !x.IsForced && preferredLanguages.Contains(x.Language, StringComparison.OrdinalIgnoreCase)) ?? - sortedStreams.FirstOrDefault(x => x.IsExternal || x.IsForced || x.IsDefault); + // Always load (full/non-forced) subtitles of the user's preferred subtitle language if possible, otherwise OnlyForced behaviour. + stream = sortedStreams.FirstOrDefault(x => !x.IsForced && MatchesPreferredLanguage(x.Language, preferredLanguages)) ?? + BehaviorOnlyForced(sortedStreams, preferredLanguages).FirstOrDefault(); } else if (mode == SubtitlePlaybackMode.OnlyForced) { - // Only load subtitles that are flagged forced. - stream = sortedStreams.FirstOrDefault(x => x.IsForced); + // Load subtitles that are flagged forced of the user's preferred subtitle language or with an undefined language + stream = BehaviorOnlyForced(sortedStreams, preferredLanguages).FirstOrDefault(); } return stream?.Index; @@ -110,40 +112,72 @@ namespace Emby.Server.Implementations.Library if (mode == SubtitlePlaybackMode.Default) { // Prefer embedded metadata over smart logic - filteredStreams = sortedStreams.Where(s => s.IsForced || s.IsDefault) + // Load subtitles according to external, default, and forced flags. + filteredStreams = sortedStreams.Where(s => s.IsExternal || s.IsDefault || s.IsForced) .ToList(); } else if (mode == SubtitlePlaybackMode.Smart) { // Prefer smart logic over embedded metadata + // Only attempt to load subtitles if the audio language is not one of the user's preferred subtitle languages, otherwise OnlyForced behavior. if (!preferredLanguages.Contains(audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) { - filteredStreams = sortedStreams.Where(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparison.OrdinalIgnoreCase)) + filteredStreams = sortedStreams.Where(s => MatchesPreferredLanguage(s.Language, preferredLanguages)) .ToList(); } + else + { + filteredStreams = BehaviorOnlyForced(sortedStreams, preferredLanguages); + } } else if (mode == SubtitlePlaybackMode.Always) { - // Always load the most suitable full subtitles - filteredStreams = sortedStreams.Where(s => !s.IsForced).ToList(); + // Always load (full/non-forced) subtitles of the user's preferred subtitle language if possible, otherwise OnlyForced behavior. + filteredStreams = sortedStreams.Where(s => !s.IsForced && MatchesPreferredLanguage(s.Language, preferredLanguages)) + .ToList() ?? BehaviorOnlyForced(sortedStreams, preferredLanguages); } else if (mode == SubtitlePlaybackMode.OnlyForced) { - // Always load the most suitable full subtitles - filteredStreams = sortedStreams.Where(s => s.IsForced).ToList(); + // Load subtitles that are flagged forced of the user's preferred subtitle language or with an undefined language + filteredStreams = BehaviorOnlyForced(sortedStreams, preferredLanguages); } - // Load forced subs if we have found no suitable full subtitles - var iterStreams = filteredStreams is null || filteredStreams.Count == 0 - ? sortedStreams.Where(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) - : filteredStreams; + // If filteredStreams is null, initialize it as an empty list to avoid null reference errors + filteredStreams ??= new List(); - foreach (var stream in iterStreams) + foreach (var stream in filteredStreams) { stream.Score = GetStreamScore(stream, preferredLanguages); } } + private static bool MatchesPreferredLanguage(string language, IReadOnlyList preferredLanguages) + { + // If preferredLanguages is empty, treat it as "any language" (wildcard) + return preferredLanguages.Count == 0 || + preferredLanguages.Contains(language, StringComparison.OrdinalIgnoreCase); + } + + private static bool IsLanguageUndefined(string language) + { + // Check for null, empty, or known placeholders + return string.IsNullOrEmpty(language) || + language.Equals("und", StringComparison.OrdinalIgnoreCase) || + language.Equals("unknown", StringComparison.OrdinalIgnoreCase) || + language.Equals("undetermined", StringComparison.OrdinalIgnoreCase) || + language.Equals("mul", StringComparison.OrdinalIgnoreCase) || + language.Equals("zxx", StringComparison.OrdinalIgnoreCase); + } + + private static List BehaviorOnlyForced(IEnumerable sortedStreams, IReadOnlyList preferredLanguages) + { + return sortedStreams + .Where(s => s.IsForced && (MatchesPreferredLanguage(s.Language, preferredLanguages) || IsLanguageUndefined(s.Language))) + .OrderByDescending(s => MatchesPreferredLanguage(s.Language, preferredLanguages)) + .ThenByDescending(s => IsLanguageUndefined(s.Language)) + .ToList(); + } + internal static int GetStreamScore(MediaStream stream, IReadOnlyList languagePreferences) { var index = languagePreferences.FindIndex(x => string.Equals(x, stream.Language, StringComparison.OrdinalIgnoreCase)); -- cgit v1.2.3 From 350983e03cc354e083cccdd156d3672cc7125685 Mon Sep 17 00:00:00 2001 From: timminator <150205162+timminator@users.noreply.github.com> Date: Thu, 20 Mar 2025 14:10:48 +0100 Subject: Fix OnPlaybackStopped task erroring out (#13226) --- .../Library/MediaSourceManager.cs | 10 +++++++--- Emby.Server.Implementations/Session/SessionManager.cs | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 5795c47ccc..92a5e9ffd9 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -782,9 +782,13 @@ namespace Emby.Server.Implementations.Library { ArgumentException.ThrowIfNullOrEmpty(id); - // TODO probably shouldn't throw here but it is kept for "backwards compatibility" - var info = GetLiveStreamInfo(id) ?? throw new ResourceNotFoundException(); - return Task.FromResult(new Tuple(info.MediaSource, info as IDirectStreamProvider)); + var info = GetLiveStreamInfo(id); + if (info is null) + { + return Task.FromResult>(new Tuple(null, null)); + } + + return Task.FromResult>(new Tuple(info.MediaSource, info as IDirectStreamProvider)); } public ILiveStream GetLiveStreamInfo(string id) diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 030da6f73e..df2acfc46c 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -343,6 +343,11 @@ namespace Emby.Server.Implementations.Session /// Task. private async Task UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem, bool updateLastCheckInTime) { + if (session is null) + { + return; + } + if (string.IsNullOrEmpty(info.MediaSourceId)) { info.MediaSourceId = info.ItemId.ToString("N", CultureInfo.InvariantCulture); @@ -675,6 +680,11 @@ namespace Emby.Server.Implementations.Session private BaseItem GetNowPlayingItem(SessionInfo session, Guid itemId) { + if (session is null) + { + return null; + } + var item = session.FullNowPlayingItem; if (item is not null && item.Id.Equals(itemId)) { @@ -794,7 +804,11 @@ namespace Emby.Server.Implementations.Session ArgumentNullException.ThrowIfNull(info); - var session = GetSession(info.SessionId); + var session = GetSession(info.SessionId, false); + if (session is null) + { + return; + } var libraryItem = info.ItemId.IsEmpty() ? null -- cgit v1.2.3 From 8db6a39e92acfd76689e77c71b00ac96e60c515b Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Sun, 23 Mar 2025 17:05:13 +0100 Subject: Remove all DB data on item removal, delete internal trickplay files (#13753) --- .../Data/CleanDatabaseScheduledTask.cs | 106 ++++++++++----------- .../Library/LibraryManager.cs | 56 +++++++---- Emby.Server.Implementations/Library/PathManager.cs | 36 +++++++ .../Item/BaseItemRepository.cs | 19 ++-- .../Trickplay/TrickplayManager.cs | 16 ++-- MediaBrowser.Controller/IO/IPathManager.cs | 17 ++++ 6 files changed, 164 insertions(+), 86 deletions(-) create mode 100644 Emby.Server.Implementations/Library/PathManager.cs create mode 100644 MediaBrowser.Controller/IO/IPathManager.cs (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs index 7ea863d769..a83ded439c 100644 --- a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs +++ b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs @@ -5,80 +5,80 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Server.Implementations; +using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Trickplay; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.Data +namespace Emby.Server.Implementations.Data; + +public class CleanDatabaseScheduledTask : ILibraryPostScanTask { - public class CleanDatabaseScheduledTask : ILibraryPostScanTask + private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; + private readonly IDbContextFactory _dbProvider; + + public CleanDatabaseScheduledTask( + ILibraryManager libraryManager, + ILogger logger, + IDbContextFactory dbProvider) { - private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; - private readonly IDbContextFactory _dbProvider; + _libraryManager = libraryManager; + _logger = logger; + _dbProvider = dbProvider; + } - public CleanDatabaseScheduledTask( - ILibraryManager libraryManager, - ILogger logger, - IDbContextFactory dbProvider) - { - _libraryManager = libraryManager; - _logger = logger; - _dbProvider = dbProvider; - } + public async Task Run(IProgress progress, CancellationToken cancellationToken) + { + await CleanDeadItems(cancellationToken, progress).ConfigureAwait(false); + } - public async Task Run(IProgress progress, CancellationToken cancellationToken) + private async Task CleanDeadItems(CancellationToken cancellationToken, IProgress progress) + { + var itemIds = _libraryManager.GetItemIds(new InternalItemsQuery { - await CleanDeadItems(cancellationToken, progress).ConfigureAwait(false); - } + HasDeadParentId = true + }); - private async Task CleanDeadItems(CancellationToken cancellationToken, IProgress progress) - { - var itemIds = _libraryManager.GetItemIds(new InternalItemsQuery - { - HasDeadParentId = true - }); + var numComplete = 0; + var numItems = itemIds.Count + 1; - var numComplete = 0; - var numItems = itemIds.Count + 1; + _logger.LogDebug("Cleaning {Number} items with dead parent links", numItems); - _logger.LogDebug("Cleaning {0} items with dead parent links", numItems); + foreach (var itemId in itemIds) + { + cancellationToken.ThrowIfCancellationRequested(); - foreach (var itemId in itemIds) + var item = _libraryManager.GetItemById(itemId); + if (item is not null) { - cancellationToken.ThrowIfCancellationRequested(); - - var item = _libraryManager.GetItemById(itemId); + _logger.LogInformation("Cleaning item {Item} type: {Type} path: {Path}", item.Name, item.GetType().Name, item.Path ?? string.Empty); - if (item is not null) + _libraryManager.DeleteItem(item, new DeleteOptions { - _logger.LogInformation("Cleaning item {0} type: {1} path: {2}", item.Name, item.GetType().Name, item.Path ?? string.Empty); - - _libraryManager.DeleteItem(item, new DeleteOptions - { - DeleteFileLocation = false - }); - } - - numComplete++; - double percent = numComplete; - percent /= numItems; - progress.Report(percent * 100); + DeleteFileLocation = false + }); } - var context = await _dbProvider.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); - await using (context.ConfigureAwait(false)) + numComplete++; + double percent = numComplete; + percent /= numItems; + progress.Report(percent * 100); + } + + var context = await _dbProvider.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); + await using (context.ConfigureAwait(false)) + { + var transaction = await context.Database.BeginTransactionAsync(cancellationToken).ConfigureAwait(false); + await using (transaction.ConfigureAwait(false)) { - var transaction = await context.Database.BeginTransactionAsync(cancellationToken).ConfigureAwait(false); - await using (transaction.ConfigureAwait(false)) - { - await context.ItemValues.Where(e => e.BaseItemsMap!.Count == 0).ExecuteDeleteAsync(cancellationToken).ConfigureAwait(false); - await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); - } + await context.ItemValues.Where(e => e.BaseItemsMap!.Count == 0).ExecuteDeleteAsync(cancellationToken).ConfigureAwait(false); + await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); } - - progress.Report(100); } + + progress.Report(100); } } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 7b3a540398..3432aa3222 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -78,6 +78,7 @@ namespace Emby.Server.Implementations.Library private readonly NamingOptions _namingOptions; private readonly IPeopleRepository _peopleRepository; private readonly ExtraResolver _extraResolver; + private readonly IPathManager _pathManager; /// /// The _root folder sync lock. @@ -113,7 +114,8 @@ namespace Emby.Server.Implementations.Library /// The image processor. /// The naming options. /// The directory service. - /// The People Repository. + /// The people repository. + /// The path manager. public LibraryManager( IServerApplicationHost appHost, ILoggerFactory loggerFactory, @@ -130,7 +132,8 @@ namespace Emby.Server.Implementations.Library IImageProcessor imageProcessor, NamingOptions namingOptions, IDirectoryService directoryService, - IPeopleRepository peopleRepository) + IPeopleRepository peopleRepository, + IPathManager pathManager) { _appHost = appHost; _logger = loggerFactory.CreateLogger(); @@ -148,6 +151,7 @@ namespace Emby.Server.Implementations.Library _cache = new ConcurrentDictionary(); _namingOptions = namingOptions; _peopleRepository = peopleRepository; + _pathManager = pathManager; _extraResolver = new ExtraResolver(loggerFactory.CreateLogger(), namingOptions, directoryService); _configurationManager.ConfigurationUpdated += ConfigurationUpdated; @@ -200,33 +204,33 @@ namespace Emby.Server.Implementations.Library /// Gets or sets the postscan tasks. /// /// The postscan tasks. - private ILibraryPostScanTask[] PostscanTasks { get; set; } = Array.Empty(); + private ILibraryPostScanTask[] PostscanTasks { get; set; } = []; /// /// Gets or sets the intro providers. /// /// The intro providers. - private IIntroProvider[] IntroProviders { get; set; } = Array.Empty(); + private IIntroProvider[] IntroProviders { get; set; } = []; /// /// Gets or sets the list of entity resolution ignore rules. /// /// The entity resolution ignore rules. - private IResolverIgnoreRule[] EntityResolutionIgnoreRules { get; set; } = Array.Empty(); + private IResolverIgnoreRule[] EntityResolutionIgnoreRules { get; set; } = []; /// /// Gets or sets the list of currently registered entity resolvers. /// /// The entity resolvers enumerable. - private IItemResolver[] EntityResolvers { get; set; } = Array.Empty(); + private IItemResolver[] EntityResolvers { get; set; } = []; - private IMultiItemResolver[] MultiItemResolvers { get; set; } = Array.Empty(); + private IMultiItemResolver[] MultiItemResolvers { get; set; } = []; /// /// Gets or sets the comparers. /// /// The comparers. - private IBaseItemComparer[] Comparers { get; set; } = Array.Empty(); + private IBaseItemComparer[] Comparers { get; set; } = []; public bool IsScanRunning { get; private set; } @@ -359,7 +363,7 @@ namespace Emby.Server.Implementations.Library var children = item.IsFolder ? ((Folder)item).GetRecursiveChildren(false) - : Array.Empty(); + : []; foreach (var metadataPath in GetMetadataPaths(item, children)) { @@ -465,14 +469,28 @@ namespace Emby.Server.Implementations.Library ReportItemRemoved(item, parent); } - private static List GetMetadataPaths(BaseItem item, IEnumerable children) + private List GetMetadataPaths(BaseItem item, IEnumerable children) + { + var list = GetInternalMetadataPaths(item); + foreach (var child in children) + { + list.AddRange(GetInternalMetadataPaths(child)); + } + + return list; + } + + private List GetInternalMetadataPaths(BaseItem item) { var list = new List { item.GetInternalMetadataPath() }; - list.AddRange(children.Select(i => i.GetInternalMetadataPath())); + if (item is Video video) + { + list.Add(_pathManager.GetTrickplayDirectory(video)); + } return list; } @@ -593,7 +611,7 @@ namespace Emby.Server.Implementations.Library { _logger.LogError(ex, "Error in GetFilteredFileSystemEntries isPhysicalRoot: {0} IsVf: {1}", isPhysicalRoot, isVf); - files = Array.Empty(); + files = []; } else { @@ -1463,7 +1481,7 @@ namespace Emby.Server.Implementations.Library // Optimize by querying against top level views query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).ToArray(); - query.AncestorIds = Array.Empty(); + query.AncestorIds = []; // Prevent searching in all libraries due to empty filter if (query.TopParentIds.Length == 0) @@ -1583,7 +1601,7 @@ namespace Emby.Server.Implementations.Library return GetTopParentIdsForQuery(displayParent, user); } - return Array.Empty(); + return []; } if (!view.ParentId.IsEmpty()) @@ -1594,7 +1612,7 @@ namespace Emby.Server.Implementations.Library return GetTopParentIdsForQuery(displayParent, user); } - return Array.Empty(); + return []; } // Handle grouping @@ -1609,7 +1627,7 @@ namespace Emby.Server.Implementations.Library .SelectMany(i => GetTopParentIdsForQuery(i, user)); } - return Array.Empty(); + return []; } if (item is CollectionFolder collectionFolder) @@ -1623,7 +1641,7 @@ namespace Emby.Server.Implementations.Library return new[] { topParent.Id }; } - return Array.Empty(); + return []; } /// @@ -1667,7 +1685,7 @@ namespace Emby.Server.Implementations.Library { _logger.LogError(ex, "Error getting intros"); - return Enumerable.Empty(); + return []; } } @@ -2894,7 +2912,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, Array.Empty()).ConfigureAwait(false); + await File.WriteAllBytesAsync(path, []).ConfigureAwait(false); } CollectionFolder.SaveLibraryOptions(virtualFolderPath, options); diff --git a/Emby.Server.Implementations/Library/PathManager.cs b/Emby.Server.Implementations/Library/PathManager.cs new file mode 100644 index 0000000000..c910abadbc --- /dev/null +++ b/Emby.Server.Implementations/Library/PathManager.cs @@ -0,0 +1,36 @@ +using System.Globalization; +using System.IO; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; + +namespace Emby.Server.Implementations.Library; + +/// +/// IPathManager implementation. +/// +public class PathManager : IPathManager +{ + private readonly IServerConfigurationManager _config; + + /// + /// Initializes a new instance of the class. + /// + /// The server configuration manager. + public PathManager( + IServerConfigurationManager config) + { + _config = config; + } + + /// + public string GetTrickplayDirectory(BaseItem item, bool saveWithMedia = false) + { + var basePath = _config.ApplicationPaths.TrickplayPath; + var idString = item.Id.ToString("N", CultureInfo.InvariantCulture); + + return saveWithMedia + ? Path.Combine(item.ContainingFolderPath, Path.ChangeExtension(item.Path, ".trickplay")) + : Path.Combine(basePath, idString); + } +} diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs index e20ad79ad1..630a169cba 100644 --- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs +++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs @@ -101,16 +101,23 @@ public sealed class BaseItemRepository using var context = _dbProvider.CreateDbContext(); using var transaction = context.Database.BeginTransaction(); - context.PeopleBaseItemMap.Where(e => e.ItemId == id).ExecuteDelete(); - context.Peoples.Where(e => e.BaseItems!.Count == 0).ExecuteDelete(); - context.Chapters.Where(e => e.ItemId == id).ExecuteDelete(); - context.MediaStreamInfos.Where(e => e.ItemId == id).ExecuteDelete(); context.AncestorIds.Where(e => e.ItemId == id || e.ParentItemId == id).ExecuteDelete(); - context.ItemValuesMap.Where(e => e.ItemId == id).ExecuteDelete(); - context.ItemValues.Where(e => e.BaseItemsMap!.Count == 0).ExecuteDelete(); + context.AttachmentStreamInfos.Where(e => e.ItemId == id).ExecuteDelete(); context.BaseItemImageInfos.Where(e => e.ItemId == id).ExecuteDelete(); + context.BaseItemMetadataFields.Where(e => e.ItemId == id).ExecuteDelete(); context.BaseItemProviders.Where(e => e.ItemId == id).ExecuteDelete(); + context.BaseItemTrailerTypes.Where(e => e.ItemId == id).ExecuteDelete(); context.BaseItems.Where(e => e.Id == id).ExecuteDelete(); + context.Chapters.Where(e => e.ItemId == id).ExecuteDelete(); + context.CustomItemDisplayPreferences.Where(e => e.ItemId == id).ExecuteDelete(); + context.ItemDisplayPreferences.Where(e => e.ItemId == id).ExecuteDelete(); + context.ItemValues.Where(e => e.BaseItemsMap!.Count == 0).ExecuteDelete(); + context.ItemValuesMap.Where(e => e.ItemId == id).ExecuteDelete(); + context.MediaSegments.Where(e => e.ItemId == id).ExecuteDelete(); + context.MediaStreamInfos.Where(e => e.ItemId == id).ExecuteDelete(); + context.PeopleBaseItemMap.Where(e => e.ItemId == id).ExecuteDelete(); + context.Peoples.Where(e => e.BaseItems!.Count == 0).ExecuteDelete(); + context.TrickplayInfos.Where(e => e.ItemId == id).ExecuteDelete(); context.SaveChanges(); transaction.Commit(); } diff --git a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs index 9c0f5b57b4..6949ec1a8c 100644 --- a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs +++ b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs @@ -12,6 +12,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Trickplay; @@ -37,9 +38,10 @@ public class TrickplayManager : ITrickplayManager private readonly IImageEncoder _imageEncoder; private readonly IDbContextFactory _dbProvider; private readonly IApplicationPaths _appPaths; + private readonly IPathManager _pathManager; private static readonly AsyncNonKeyedLocker _resourcePool = new(1); - private static readonly string[] _trickplayImgExtensions = { ".jpg" }; + private static readonly string[] _trickplayImgExtensions = [".jpg"]; /// /// Initializes a new instance of the class. @@ -53,6 +55,7 @@ public class TrickplayManager : ITrickplayManager /// The image encoder. /// The database provider. /// The application paths. + /// The path manager. public TrickplayManager( ILogger logger, IMediaEncoder mediaEncoder, @@ -62,7 +65,8 @@ public class TrickplayManager : ITrickplayManager IServerConfigurationManager config, IImageEncoder imageEncoder, IDbContextFactory dbProvider, - IApplicationPaths appPaths) + IApplicationPaths appPaths, + IPathManager pathManager) { _logger = logger; _mediaEncoder = mediaEncoder; @@ -73,6 +77,7 @@ public class TrickplayManager : ITrickplayManager _imageEncoder = imageEncoder; _dbProvider = dbProvider; _appPaths = appPaths; + _pathManager = pathManager; } /// @@ -610,12 +615,7 @@ public class TrickplayManager : ITrickplayManager /// public string GetTrickplayDirectory(BaseItem item, int tileWidth, int tileHeight, int width, bool saveWithMedia = false) { - var basePath = _config.ApplicationPaths.TrickplayPath; - var idString = item.Id.ToString("N", CultureInfo.InvariantCulture); - var path = saveWithMedia - ? Path.Combine(item.ContainingFolderPath, Path.ChangeExtension(item.Path, ".trickplay")) - : Path.Combine(basePath, idString); - + var path = _pathManager.GetTrickplayDirectory(item, saveWithMedia); var subdirectory = string.Format( CultureInfo.InvariantCulture, "{0} - {1}x{2}", diff --git a/MediaBrowser.Controller/IO/IPathManager.cs b/MediaBrowser.Controller/IO/IPathManager.cs new file mode 100644 index 0000000000..0368898102 --- /dev/null +++ b/MediaBrowser.Controller/IO/IPathManager.cs @@ -0,0 +1,17 @@ +using MediaBrowser.Controller.Entities; + +namespace MediaBrowser.Controller.IO; + +/// +/// Interface ITrickplayManager. +/// +public interface IPathManager +{ + /// + /// Gets the path to the trickplay image base folder. + /// + /// The item. + /// Whether or not the tile should be saved next to the media file. + /// The absolute path. + public string GetTrickplayDirectory(BaseItem item, bool saveWithMedia = false); +} -- cgit v1.2.3 From dfb485d1f205c8eda95bc3b79d341f3c3aef7ec4 Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Sun, 23 Mar 2025 17:05:40 +0100 Subject: Rework season folder parsing (#11748) --- Emby.Naming/TV/SeasonPathParser.cs | 90 +++++++++------------- .../Library/LibraryManager.cs | 7 +- .../Library/Resolvers/TV/SeasonResolver.cs | 2 +- .../Library/Resolvers/TV/SeriesResolver.cs | 7 +- MediaBrowser.Controller/Entities/TV/Season.cs | 2 +- MediaBrowser.Controller/Library/ILibraryManager.cs | 3 +- .../TV/SeasonPathParserTests.cs | 68 ++++++++++------ 7 files changed, 96 insertions(+), 83 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Naming/TV/SeasonPathParser.cs b/Emby.Naming/TV/SeasonPathParser.cs index 45b91971bf..98ee1e4b8f 100644 --- a/Emby.Naming/TV/SeasonPathParser.cs +++ b/Emby.Naming/TV/SeasonPathParser.cs @@ -1,43 +1,35 @@ using System; using System.Globalization; using System.IO; +using System.Text.RegularExpressions; namespace Emby.Naming.TV { /// /// Class to parse season paths. /// - public static class SeasonPathParser + public static partial class SeasonPathParser { - /// - /// A season folder must contain one of these somewhere in the name. - /// - private static readonly string[] _seasonFolderNames = - { - "season", - "sæson", - "temporada", - "saison", - "staffel", - "series", - "сезон", - "stagione" - }; - - private static readonly char[] _splitChars = ['.', '_', ' ', '-']; + [GeneratedRegex(@"^\s*((?(?>\d+))(?:st|nd|rd|th|\.)*(?!\s*[Ee]\d+))\s*(?:[[시즌]*|[シーズン]*|[sS](?:eason|æson|aison|taffel|eries|tagione|äsong|eizoen|easong|ezon|ezona|ezóna|ezonul)*|[tT](?:emporada)*|[kK](?:ausi)*|[Сс](?:езон)*)\s*(?.*)$")] + private static partial Regex ProcessPre(); + + [GeneratedRegex(@"^\s*(?:[[시즌]*|[シーズン]*|[sS](?:eason|æson|aison|taffel|eries|tagione|äsong|eizoen|easong|ezon|ezona|ezóna|ezonul)*|[tT](?:emporada)*|[kK](?:ausi)*|[Сс](?:езон)*)\s*(?(?>\d+)(?!\s*[Ee]\d+))(?.*)$")] + private static partial Regex ProcessPost(); /// /// Attempts to parse season number from path. /// /// Path to season. + /// Folder name of the parent. /// Support special aliases when parsing. /// Support numeric season folders when parsing. /// Returns object. - public static SeasonPathParserResult Parse(string path, bool supportSpecialAliases, bool supportNumericSeasonFolders) + public static SeasonPathParserResult Parse(string path, string? parentPath, bool supportSpecialAliases, bool supportNumericSeasonFolders) { var result = new SeasonPathParserResult(); + var parentFolderName = parentPath is null ? null : new DirectoryInfo(parentPath).Name; - var (seasonNumber, isSeasonFolder) = GetSeasonNumberFromPath(path, supportSpecialAliases, supportNumericSeasonFolders); + var (seasonNumber, isSeasonFolder) = GetSeasonNumberFromPath(path, parentFolderName, supportSpecialAliases, supportNumericSeasonFolders); result.SeasonNumber = seasonNumber; @@ -54,15 +46,24 @@ namespace Emby.Naming.TV /// Gets the season number from path. /// /// The path. + /// The parent folder name. /// if set to true [support special aliases]. /// if set to true [support numeric season folders]. /// System.Nullable{System.Int32}. private static (int? SeasonNumber, bool IsSeasonFolder) GetSeasonNumberFromPath( string path, + string? parentFolderName, bool supportSpecialAliases, bool supportNumericSeasonFolders) { string filename = Path.GetFileName(path); + filename = Regex.Replace(filename, "[ ._-]", string.Empty); + + if (parentFolderName is not null) + { + parentFolderName = Regex.Replace(parentFolderName, "[ ._-]", string.Empty); + filename = filename.Replace(parentFolderName, string.Empty, StringComparison.OrdinalIgnoreCase); + } if (supportSpecialAliases) { @@ -85,53 +86,38 @@ namespace Emby.Naming.TV } } - if (TryGetSeasonNumberFromPart(filename, out int seasonNumber)) + if (filename.StartsWith('s')) { - return (seasonNumber, true); - } + var testFilename = filename.AsSpan()[1..]; - // Look for one of the season folder names - foreach (var name in _seasonFolderNames) - { - if (filename.Contains(name, StringComparison.OrdinalIgnoreCase)) + if (int.TryParse(testFilename, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val)) { - var result = GetSeasonNumberFromPathSubstring(filename.Replace(name, " ", StringComparison.OrdinalIgnoreCase)); - if (result.SeasonNumber.HasValue) - { - return result; - } - - break; + return (val, true); } } - var parts = filename.Split(_splitChars, StringSplitOptions.RemoveEmptyEntries); - foreach (var part in parts) + var preMatch = ProcessPre().Match(filename); + if (preMatch.Success) { - if (TryGetSeasonNumberFromPart(part, out seasonNumber)) - { - return (seasonNumber, true); - } + return CheckMatch(preMatch); } - - return (null, true); - } - - private static bool TryGetSeasonNumberFromPart(ReadOnlySpan part, out int seasonNumber) - { - seasonNumber = 0; - if (part.Length < 2 || !part.StartsWith("s", StringComparison.OrdinalIgnoreCase)) + else { - return false; + var postMatch = ProcessPost().Match(filename); + return CheckMatch(postMatch); } + } - if (int.TryParse(part.Slice(1), NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) + private static (int? SeasonNumber, bool IsSeasonFolder) CheckMatch(Match match) + { + var numberString = match.Groups["seasonnumber"]; + if (numberString.Success) { - seasonNumber = value; - return true; + var seasonNumber = int.Parse(numberString.Value, CultureInfo.InvariantCulture); + return (seasonNumber, true); } - return false; + return (null, false); } /// diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 3432aa3222..b810ad4de1 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2512,8 +2512,11 @@ namespace Emby.Server.Implementations.Library } /// - public int? GetSeasonNumberFromPath(string path) - => SeasonPathParser.Parse(path, true, true).SeasonNumber; + public int? GetSeasonNumberFromPath(string path, Guid? parentId) + { + var parentPath = parentId.HasValue ? GetItemById(parentId.Value)?.ContainingFolderPath : null; + return SeasonPathParser.Parse(path, parentPath, true, true).SeasonNumber; + } /// public bool FillMissingEpisodeNumbersFromPath(Episode episode, bool forceRefresh) diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs index abf2d01159..6cb63a28a2 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs @@ -48,7 +48,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV var path = args.Path; - var seasonParserResult = SeasonPathParser.Parse(path, true, true); + var seasonParserResult = SeasonPathParser.Parse(path, series.ContainingFolderPath, true, true); var season = new Season { diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index fb48d7bf17..c81a0adb89 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -118,7 +118,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV { if (child.IsDirectory) { - if (IsSeasonFolder(child.FullName, isTvContentType)) + if (IsSeasonFolder(child.FullName, path, isTvContentType)) { _logger.LogDebug("{Path} is a series because of season folder {Dir}.", path, child.FullName); return true; @@ -155,11 +155,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV /// Determines whether [is season folder] [the specified path]. /// /// The path. + /// The parentpath. /// if set to true [is tv content type]. /// true if [is season folder] [the specified path]; otherwise, false. - private static bool IsSeasonFolder(string path, bool isTvContentType) + private static bool IsSeasonFolder(string path, string parentPath, bool isTvContentType) { - var seasonNumber = SeasonPathParser.Parse(path, isTvContentType, isTvContentType).SeasonNumber; + var seasonNumber = SeasonPathParser.Parse(path, parentPath, isTvContentType, isTvContentType).SeasonNumber; return seasonNumber.HasValue; } diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index e3fbe8e4d6..9dbac1e920 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -257,7 +257,7 @@ namespace MediaBrowser.Controller.Entities.TV if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path)) { - IndexNumber ??= LibraryManager.GetSeasonNumberFromPath(Path); + IndexNumber ??= LibraryManager.GetSeasonNumberFromPath(Path, ParentId); // If a change was made record it if (IndexNumber.HasValue) diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 03a28fd8c0..e4490bca3b 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -426,8 +426,9 @@ namespace MediaBrowser.Controller.Library /// Gets the season number from path. /// /// The path. + /// The parent id. /// System.Nullable<System.Int32>. - int? GetSeasonNumberFromPath(string path); + int? GetSeasonNumberFromPath(string path, Guid? parentId); /// /// Fills the missing episode numbers from path. diff --git a/tests/Jellyfin.Naming.Tests/TV/SeasonPathParserTests.cs b/tests/Jellyfin.Naming.Tests/TV/SeasonPathParserTests.cs index 3a042df683..4c8ba58d04 100644 --- a/tests/Jellyfin.Naming.Tests/TV/SeasonPathParserTests.cs +++ b/tests/Jellyfin.Naming.Tests/TV/SeasonPathParserTests.cs @@ -6,32 +6,54 @@ namespace Jellyfin.Naming.Tests.TV; public class SeasonPathParserTests { [Theory] - [InlineData("/Drive/Season 1", 1, true)] - [InlineData("/Drive/s1", 1, true)] - [InlineData("/Drive/S1", 1, true)] - [InlineData("/Drive/Season 2", 2, true)] - [InlineData("/Drive/Season 02", 2, true)] - [InlineData("/Drive/Seinfeld/S02", 2, true)] - [InlineData("/Drive/Seinfeld/2", 2, true)] - [InlineData("/Drive/Seinfeld - S02", 2, true)] - [InlineData("/Drive/Season 2009", 2009, true)] - [InlineData("/Drive/Season1", 1, true)] - [InlineData("The Wonder Years/The.Wonder.Years.S04.PDTV.x264-JCH", 4, true)] - [InlineData("/Drive/Season 7 (2016)", 7, false)] - [InlineData("/Drive/Staffel 7 (2016)", 7, false)] - [InlineData("/Drive/Stagione 7 (2016)", 7, false)] - [InlineData("/Drive/Season (8)", null, false)] - [InlineData("/Drive/3.Staffel", 3, false)] - [InlineData("/Drive/s06e05", null, false)] - [InlineData("/Drive/The.Legend.of.Condor.Heroes.2017.V2.web-dl.1080p.h264.aac-hdctv", null, false)] - [InlineData("/Drive/extras", 0, true)] - [InlineData("/Drive/specials", 0, true)] - public void GetSeasonNumberFromPathTest(string path, int? seasonNumber, bool isSeasonDirectory) + [InlineData("/Drive/Season 1", "/Drive", 1, true)] + [InlineData("/Drive/Staffel 1", "/Drive", 1, true)] + [InlineData("/Drive/Stagione 1", "/Drive", 1, true)] + [InlineData("/Drive/sæson 1", "/Drive", 1, true)] + [InlineData("/Drive/Temporada 1", "/Drive", 1, true)] + [InlineData("/Drive/series 1", "/Drive", 1, true)] + [InlineData("/Drive/Kausi 1", "/Drive", 1, true)] + [InlineData("/Drive/Säsong 1", "/Drive", 1, true)] + [InlineData("/Drive/Seizoen 1", "/Drive", 1, true)] + [InlineData("/Drive/Seasong 1", "/Drive", 1, true)] + [InlineData("/Drive/Sezon 1", "/Drive", 1, true)] + [InlineData("/Drive/sezona 1", "/Drive", 1, true)] + [InlineData("/Drive/sezóna 1", "/Drive", 1, true)] + [InlineData("/Drive/Sezonul 1", "/Drive", 1, true)] + [InlineData("/Drive/시즌 1", "/Drive", 1, true)] + [InlineData("/Drive/シーズン 1", "/Drive", 1, true)] + [InlineData("/Drive/сезон 1", "/Drive", 1, true)] + [InlineData("/Drive/Сезон 1", "/Drive", 1, true)] + [InlineData("/Drive/Season 10", "/Drive", 10, true)] + [InlineData("/Drive/Season 100", "/Drive", 100, true)] + [InlineData("/Drive/s1", "/Drive", 1, true)] + [InlineData("/Drive/S1", "/Drive", 1, true)] + [InlineData("/Drive/Season 2", "/Drive", 2, true)] + [InlineData("/Drive/Season 02", "/Drive", 2, true)] + [InlineData("/Drive/Seinfeld/S02", "/Seinfeld", 2, true)] + [InlineData("/Drive/Seinfeld/2", "/Seinfeld", 2, true)] + [InlineData("/Drive/Seinfeld Season 2", "/Drive", null, false)] + [InlineData("/Drive/Season 2009", "/Drive", 2009, true)] + [InlineData("/Drive/Season1", "/Drive", 1, true)] + [InlineData("The Wonder Years/The.Wonder.Years.S04.PDTV.x264-JCH", "/The Wonder Years", 4, true)] + [InlineData("/Drive/Season 7 (2016)", "/Drive", 7, true)] + [InlineData("/Drive/Staffel 7 (2016)", "/Drive", 7, true)] + [InlineData("/Drive/Stagione 7 (2016)", "/Drive", 7, true)] + [InlineData("/Drive/Stargate SG-1/Season 1", "/Drive/Stargate SG-1", 1, true)] + [InlineData("/Drive/Stargate SG-1/Stargate SG-1 Season 1", "/Drive/Stargate SG-1", 1, true)] + [InlineData("/Drive/Season (8)", "/Drive", null, false)] + [InlineData("/Drive/3.Staffel", "/Drive", 3, true)] + [InlineData("/Drive/s06e05", "/Drive", null, false)] + [InlineData("/Drive/The.Legend.of.Condor.Heroes.2017.V2.web-dl.1080p.h264.aac-hdctv", "/Drive", null, false)] + [InlineData("/Drive/extras", "/Drive", 0, true)] + [InlineData("/Drive/specials", "/Drive", 0, true)] + [InlineData("/Drive/Episode 1 Season 2", "/Drive", null, false)] + public void GetSeasonNumberFromPathTest(string path, string? parentPath, int? seasonNumber, bool isSeasonDirectory) { - var result = SeasonPathParser.Parse(path, true, true); + var result = SeasonPathParser.Parse(path, parentPath, true, true); Assert.Equal(result.SeasonNumber is not null, result.Success); - Assert.Equal(result.SeasonNumber, seasonNumber); + Assert.Equal(seasonNumber, result.SeasonNumber); Assert.Equal(isSeasonDirectory, result.IsSeasonFolder); } } -- 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 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 6e8a9fc204..4d959905d9 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 a83ded439c..63481b1f8c 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 82945a4f62..8a79cdebc1 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 f9c10ba098..0d63b3af7d 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 34c722e41d..273d356a39 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 c9b41f8193..706de60a90 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 31f053f065..c472623e67 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 b0003ed414..846663900b 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 3e71b2fcde..8631958365 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 6791e3ca90..631179ffcf 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 71c69ec50a..ffbf8068f0 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 3ac1d02192..9253a9a69f 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 76e564d535..0c9edd8398 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 a41ef888b0..2a28131519 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 2560466c10..22baafbb07 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 89f64ee4f0..337b1afdd4 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 05223d28ae..4d3a04377f 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 dc37c4f2a2..959373fec8 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 270c1b4411..74db077d8c 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 0fd0149904..f6f2f59c52 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 07dedb017a..6b80d537fb 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 5fcf72fb46..7efb5b1698 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 a7c3cce971..152c400cde 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 10556da65d..2da4839138 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 2f55e88ec4..880b3a82d4 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 6d94d96f3a..2196616dd9 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 f0d17decbf..1fd57eba9c 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 e6fe7df79c..803c2f1f78 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 7c6160fc49..ff4540f58f 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 1c0a6af79d..5461d12fa2 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 2d1d4e2c8a..e30e2b54e4 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 cbbaaddbfe..09a7b73b94 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 e8bc8f2657..0cb20e433d 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 9b56d08494..5075d91be7 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 7ee4396bba..3e4bac89a5 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 cc070244b1..0f08854d24 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 838578fab8..d0ced277a0 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 2b32ae728c..bbfa270db9 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 2c45789d34..1801b6bfd4 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 eb83a37ba4..3c2691cb5e 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 dece664262..2616694d83 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 e2e7b0cb5a..60379f4152 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 cc0792477e..9d149cc85a 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 82abfb8313..836860e0ea 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 8d84a6b6e1..8bf82265c9 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 54272aeafa..007a468bf2 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 180561fc84..537630561c 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 1b4048b8e6..e414a8232f 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 b0e4567a78..fbbb5bca73 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 bea69b2820..1f04b28290 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 fc6f04d56a..48b94a5f3f 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 1557982093..18167cc530 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 f47e3fdfd3..f700718841 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 a8dfd4cd3a..01a0ade63c 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 59ec418ce7..fa507ad040 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 1c9f54ab03..534e80f4e7 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 9e225393c4..e3fe517c49 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 6949ec1a8c..b55d2271a6 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 27222a183c..02a52e5f25 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 e204a16a64..3f9491038d 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 79fa70c0b2..0105f8162d 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 9788119a54..f3bf6b805a 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 597643ed19..c3b02ad4ed 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 2f23cb1f8f..933d85de01 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 c845beef2f..a50990ac5d 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 502a37cde1..4f6c5100d9 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 f183bce107..490daae42b 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 f126230fb4..bd5bf98e0f 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 d8684f6da7..32814393cf 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 fa21d25664..688b169359 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 49f8df508e..f6cbf5a00c 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 3b0938ea79..d6e6592429 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 e99479ee19..39dc909633 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 e20679084d..29481481c4 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 b2f23cc11d..d3e9da6226 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 0bd28154de..57a8a01131 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 07def2e0f2..a252b7a25f 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 f3c252decc..470702f3e6 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 3670808673..18845ab9f6 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 e4490bca3b..13915dc5c6 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 1c5d2f4e53..cf76f336c8 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 570d2bacea..1e75446e1c 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 491acdc9c2..53e04066f0 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 d35ed57b89..85bb862c77 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 b477f2593a..fe4b2de65f 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 90163ae91f..54cbe65f68 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 d872572b77..38e2731762 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 dae885775c..e93ad81d3a 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 a0433fee18..6e5c7885cc 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 951e057632..ba0eaf21cf 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 af2ede7010..b481a106fd 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 f534e49f3f..909e8750f8 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 51dd0ffb8e..3a76784052 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 e3e0e0861e..42be5b3b99 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 37723df116..ac6b72acea 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 9a1565728d..c0c5e3147f 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 f0be657691..82bf007a8a 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 09f2372893..4b343c164a 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 8dd6e647e2..edffec4aba 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 93e6664ea4..7e75a200b6 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 94db6a011b..e80a9aec34 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 fc3c1036f0..b529da8fa7 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 a838686d05..54c30d92ce 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 4a350d200e..7b1a68bb55 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 f068338f92..cbcb9a5f54 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 7de6019692..8da9793f9d 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 15b356a74e..4bd99d83a7 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 1abbee4458..5dc1039a1f 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 e27d01d860..92307afecd 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 ce2f0c6178..6379755264 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 3b822ee828..329b8973f5 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 fa9276c669..401d58ff22 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 0db42a1c7b..17673cb1d9 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 d889b871ed..975614be10 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 7b5a3af64c..0913f95be1 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 e24e73ecb7..3170653fec 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 b38d6a4f1f..afaebb8e86 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 a198f53ba3..fa36e58db7 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 499fafd0e1..beae325ec5 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 44b5f34d7f..df48ebf279 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 90dc55b70d..d9609f1cc0 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 7d40bdf448..627f74140b 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 4b459432bc..094d57139c 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 58c8fa49ef..6b792ffb48 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 0f3a073244..91ee8caa16 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 e68ab9105a..40466def1d 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 42115802c5..28da91e472 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 d354000337..6d6a920225 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 90120d7721..8c1c071e63 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 77816565af..b16b62b104 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 6d2e68077c..c488b90e1c 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 a6ab275d31..f4f9dd17ac 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 f3398eeeac..aafa92b4a6 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 05ab6dd2d2..ced12b9e62 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 f7a73848c8..218e97bcc0 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 c9c8a4a625..123f2fe438 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 d3d8dd8227..69a9b5816a 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 62da8c3fff..6ba57e74d5 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 3967712b03..72ac1140cb 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 797c26ec27..8e6f677dca 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 4586354504..fed092b978 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 c3d6705c24..0818639636 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 1e619f5eef..5b913385e8 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 d2b412e459..f70e3e2c23 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 29c50e2c4e..3ff3c45faf 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 4151448e4e..c865b75f11 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 79693d321a..c394c209bb 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 030d16fb90..311642e0d7 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 c0fd7d448b..b2bcbf2bb6 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 cc96792e64..0740165530 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 a4d9c54af4..03c2ca4a47 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 8f19ce04fa..ed449a8f14 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 2c4091493e..196d2680db 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 6d1eb59f67..606b1169b8 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 3b615893ed..653572b6e9 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 b3ab3d0944..778aca373e 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 024d595d58..5cdc853319 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 9a63ed9f21..be99b46d56 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 8cc817fb8b..146df5546c 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 3f19b6986a..7c15f064d8 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 057b6689ac..b5fae4053c 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 08f2a33566..67a071039f 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 b4c6511bf2..c101e0085e 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 d15049a1fa..175a82e091 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 e9564b854b..c7efef2390 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 5a84f7750a..5935b632a7 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 779aec986b..550fa5073b 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 a750b65c03..5f87c8d403 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 038afd7524..923a53acaf 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 9b437861bb..92068c8f29 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 abeeb09c9b..0e63c130e3 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 9c22b114c7..3860b0e161 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 7e572f9a39..37e15f5e72 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 cdaee9161c..125b9e92cd 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 f3cccb13fe..fe25d3064d 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 240e284c0c..90a3ec5d00 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 49c869c6a8..d6d3fadfc4 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 dc1c17e5ef..a198c80f7e 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 bcaa3634ed..4e830801ee 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 7bbb28d431..a7e223c435 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 80fe784dd7..7891006430 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 7aa4479b3d..eab3cd3e7e 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 3860c851d0..91dd0ff7ab 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 1134f7aa42..8ec9231030 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 607310caae..499faa9c47 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 02c3fc7532..7ab851689a 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 1cfd7112ce..e14ed9380e 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 ecf7af4952..05f2c80a25 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 dccba6f773..c9f3cf696c 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 e821c106e3..ab7781d155 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 360fa03768..8a2806113f 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 17d33845f5..a11507bd5d 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 4c09176691..ddea37f6dd 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 35a3cdad2d..ab7065ee65 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 8dba31a67f..aa60bff324 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 27745f601a..2ea6dafe13 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 1fbf21492d..d589a4afd7 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 bac6fd5b5a..3d70bb0296 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 ad622d44c5..1e0d3b129f 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 dc4c8212ba..ccf67d899f 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 5714120b5c..d3ba8c96a9 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 855f02fd3f..2c0058c720 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 d7b806d7a3..da4bab3fd3 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 a329f1ef16..9b72d9688a 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 48919c9b5d..f5cfe86c44 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 79587a9c33..5d8ddde082 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 448bd2fc8b..1629c732c6 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 79ae1661aa..0d75686198 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 2aa3522d8a..d9eb0ae7a4 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 83f68ab509..402a3f3b0e 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 318cc7acd0..d8f873abe6 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 da98606a4b..7ebcc48834 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 1d571805b8..a5d186ce18 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 2f4caa3867..9ca5d7420b 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 6b3afc9357..0a6489d0ac 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 31d2b486b3..1fe9fc97ef 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 534d1863ca..ed5235252a 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 a2d1b3607b..2851b08e6c 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 d84da89e28..03884d7754 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 42bdb22bfb690a6af37d70f12844881d884927b1 Mon Sep 17 00:00:00 2001 From: JPVenson Date: Tue, 25 Mar 2025 16:45:00 +0100 Subject: Fixed namespaces --- Emby.Server.Implementations/Collections/CollectionManager.cs | 2 +- Emby.Server.Implementations/Dto/DtoService.cs | 2 +- Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs | 2 +- Emby.Server.Implementations/Library/LibraryManager.cs | 2 +- Emby.Server.Implementations/Library/MediaSourceManager.cs | 2 +- Emby.Server.Implementations/Library/MusicManager.cs | 2 +- Emby.Server.Implementations/Library/SearchEngine.cs | 2 +- Emby.Server.Implementations/Library/UserDataManager.cs | 2 +- Emby.Server.Implementations/Library/UserViewManager.cs | 2 +- Emby.Server.Implementations/Playlists/PlaylistManager.cs | 2 +- Emby.Server.Implementations/Playlists/PlaylistsFolder.cs | 2 +- Emby.Server.Implementations/Session/SessionManager.cs | 4 ++-- Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs | 2 +- Emby.Server.Implementations/Sorting/DatePlayedComparer.cs | 2 +- Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs | 2 +- Emby.Server.Implementations/Sorting/IsPlayedComparer.cs | 2 +- Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs | 2 +- Emby.Server.Implementations/Sorting/PlayCountComparer.cs | 2 +- Emby.Server.Implementations/SyncPlay/Group.cs | 2 +- Emby.Server.Implementations/TV/TVSeriesManager.cs | 2 +- Jellyfin.Api/Controllers/ArtistsController.cs | 2 +- Jellyfin.Api/Controllers/DisplayPreferencesController.cs | 2 +- Jellyfin.Api/Controllers/GenresController.cs | 2 +- Jellyfin.Api/Controllers/ImageController.cs | 2 +- Jellyfin.Api/Controllers/InstantMixController.cs | 2 +- Jellyfin.Api/Controllers/LibraryController.cs | 2 +- Jellyfin.Api/Controllers/MoviesController.cs | 2 +- Jellyfin.Api/Controllers/MusicGenresController.cs | 2 +- Jellyfin.Api/Controllers/PersonsController.cs | 2 +- Jellyfin.Api/Controllers/PlaystateController.cs | 2 +- Jellyfin.Api/Controllers/StudiosController.cs | 2 +- Jellyfin.Api/Controllers/SuggestionsController.cs | 2 +- Jellyfin.Api/Controllers/UserLibraryController.cs | 2 +- Jellyfin.Api/Controllers/YearsController.cs | 2 +- Jellyfin.Api/Helpers/DynamicHlsHelper.cs | 2 +- Jellyfin.Api/Helpers/MediaInfoHelper.cs | 2 +- Jellyfin.Api/Helpers/RequestHelpers.cs | 2 +- Jellyfin.Data/Events/Users/UserCreatedEventArgs.cs | 2 +- Jellyfin.Data/Events/Users/UserDeletedEventArgs.cs | 2 +- Jellyfin.Data/Events/Users/UserLockedOutEventArgs.cs | 2 +- Jellyfin.Data/Events/Users/UserPasswordChangedEventArgs.cs | 2 +- Jellyfin.Data/Events/Users/UserUpdatedEventArgs.cs | 2 +- Jellyfin.Data/UserEntityExtensions.cs | 2 +- Jellyfin.Server.Implementations/Activity/ActivityManager.cs | 2 +- Jellyfin.Server.Implementations/Devices/DeviceManager.cs | 4 ++-- .../Events/Consumers/Library/LyricDownloadFailureLogger.cs | 2 +- .../Events/Consumers/Library/SubtitleDownloadFailureLogger.cs | 2 +- .../Events/Consumers/Security/AuthenticationFailedLogger.cs | 2 +- .../Events/Consumers/Security/AuthenticationSucceededLogger.cs | 2 +- .../Events/Consumers/Session/PlaybackStartLogger.cs | 2 +- .../Events/Consumers/Session/PlaybackStopLogger.cs | 2 +- .../Events/Consumers/Session/SessionEndedLogger.cs | 2 +- .../Events/Consumers/Session/SessionStartedLogger.cs | 2 +- .../Events/Consumers/System/TaskCompletedLogger.cs | 2 +- .../Events/Consumers/Updates/PluginInstallationFailedLogger.cs | 2 +- .../Events/Consumers/Updates/PluginInstalledLogger.cs | 2 +- .../Events/Consumers/Updates/PluginUninstalledLogger.cs | 2 +- .../Events/Consumers/Updates/PluginUpdatedLogger.cs | 2 +- .../Events/Consumers/Users/UserCreatedLogger.cs | 2 +- .../Events/Consumers/Users/UserDeletedLogger.cs | 2 +- .../Events/Consumers/Users/UserLockedOutLogger.cs | 2 +- .../Events/Consumers/Users/UserPasswordChangedLogger.cs | 2 +- Jellyfin.Server.Implementations/Item/BaseItemRepository.cs | 4 ++-- Jellyfin.Server.Implementations/Item/ChapterRepository.cs | 2 +- Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs | 2 +- Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs | 2 +- Jellyfin.Server.Implementations/Item/PeopleRepository.cs | 2 +- .../MediaSegments/MediaSegmentManager.cs | 2 +- Jellyfin.Server.Implementations/Security/AuthenticationManager.cs | 2 +- Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs | 2 +- .../Users/DefaultAuthenticationProvider.cs | 2 +- .../Users/DefaultPasswordResetProvider.cs | 2 +- Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs | 2 +- Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs | 2 +- Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs | 2 +- Jellyfin.Server.Implementations/Users/UserManager.cs | 2 +- Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs | 2 +- Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs | 2 +- Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs | 2 +- Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs | 7 ++++--- Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs | 2 +- MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs | 2 +- MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs | 2 +- MediaBrowser.Controller/Channels/Channel.cs | 2 +- MediaBrowser.Controller/Collections/ICollectionManager.cs | 2 +- MediaBrowser.Controller/Devices/IDeviceManager.cs | 4 ++-- MediaBrowser.Controller/Drawing/IImageProcessor.cs | 2 +- MediaBrowser.Controller/Dto/IDtoService.cs | 2 +- MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs | 2 +- MediaBrowser.Controller/Entities/Audio/MusicArtist.cs | 2 +- MediaBrowser.Controller/Entities/BaseItem.cs | 2 +- MediaBrowser.Controller/Entities/CollectionFolder.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 2 +- MediaBrowser.Controller/Entities/InternalItemsQuery.cs | 2 +- MediaBrowser.Controller/Entities/InternalPeopleQuery.cs | 2 +- MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 2 +- MediaBrowser.Controller/Entities/TV/Season.cs | 2 +- MediaBrowser.Controller/Entities/TV/Series.cs | 2 +- MediaBrowser.Controller/Entities/UserRootFolder.cs | 2 +- MediaBrowser.Controller/Entities/UserView.cs | 2 +- MediaBrowser.Controller/Entities/UserViewBuilder.cs | 2 +- MediaBrowser.Controller/IDisplayPreferencesManager.cs | 2 +- MediaBrowser.Controller/Library/IIntroProvider.cs | 3 ++- MediaBrowser.Controller/Library/ILibraryManager.cs | 2 +- MediaBrowser.Controller/Library/IMediaSourceManager.cs | 2 +- MediaBrowser.Controller/Library/IMusicManager.cs | 2 +- MediaBrowser.Controller/Library/IUserDataManager.cs | 2 +- MediaBrowser.Controller/Library/IUserManager.cs | 2 +- MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs | 2 +- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 2 +- MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs | 2 +- MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs | 2 +- MediaBrowser.Controller/Net/AuthorizationInfo.cs | 2 +- MediaBrowser.Controller/Playlists/Playlist.cs | 2 +- MediaBrowser.Controller/Session/ISessionManager.cs | 5 +++-- MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs | 3 ++- MediaBrowser.Controller/Trickplay/ITrickplayManager.cs | 2 +- MediaBrowser.Model/Activity/IActivityManager.cs | 2 +- MediaBrowser.Model/Dto/BaseItemDto.cs | 2 +- MediaBrowser.Model/Library/UserViewQuery.cs | 2 +- MediaBrowser.Model/Querying/LatestItemsQuery.cs | 2 +- MediaBrowser.Model/Querying/NextUpQuery.cs | 2 +- MediaBrowser.Model/Users/UserPolicy.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/AccessSchedule.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/ActivityLog.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/AncestorId.cs | 2 +- .../Entities/AttachmentStreamInfo.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs | 2 +- .../Entities/BaseItemExtraType.cs | 2 +- .../Entities/BaseItemImageInfo.cs | 2 +- .../Entities/BaseItemMetadataField.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs | 2 +- .../Entities/BaseItemTrailerType.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Chapter.cs | 2 +- .../Entities/CustomItemDisplayPreferences.cs | 2 +- .../Entities/DisplayPreferences.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Group.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/HomeSection.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/ImageInfo.cs | 2 +- .../Entities/ImageInfoImageType.cs | 2 +- .../Entities/ItemDisplayPreferences.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/ItemValue.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/ItemValueMap.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/ItemValueType.cs | 2 +- .../Entities/Libraries/Artwork.cs | 2 +- .../Jellyfin.Database.Implementations/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/CompanyMetadata.cs | 2 +- .../Entities/Libraries/CustomItem.cs | 2 +- .../Entities/Libraries/CustomItemMetadata.cs | 2 +- .../Entities/Libraries/Episode.cs | 2 +- .../Entities/Libraries/EpisodeMetadata.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs | 2 +- .../Entities/Libraries/ItemMetadata.cs | 2 +- .../Entities/Libraries/Library.cs | 2 +- .../Entities/Libraries/LibraryItem.cs | 2 +- .../Entities/Libraries/MediaFile.cs | 2 +- .../Entities/Libraries/MediaFileStream.cs | 2 +- .../Entities/Libraries/MetadataProvider.cs | 2 +- .../Entities/Libraries/MetadataProviderId.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs | 2 +- .../Entities/Libraries/MovieMetadata.cs | 2 +- .../Entities/Libraries/MusicAlbum.cs | 2 +- .../Entities/Libraries/MusicAlbumMetadata.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Libraries/Person.cs | 2 +- .../Entities/Libraries/PersonRole.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs | 2 +- .../Entities/Libraries/PhotoMetadata.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs | 2 +- .../Entities/Libraries/RatingSource.cs | 2 +- .../Entities/Libraries/Release.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Libraries/Season.cs | 2 +- .../Entities/Libraries/SeasonMetadata.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Libraries/Series.cs | 2 +- .../Entities/Libraries/SeriesMetadata.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Libraries/Track.cs | 2 +- .../Entities/Libraries/TrackMetadata.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/MediaSegment.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs | 2 +- .../Entities/MediaStreamTypeEntity.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/People.cs | 2 +- .../Entities/PeopleBaseItemMap.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Permission.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Preference.cs | 2 +- .../Entities/ProgramAudioEntity.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Security/ApiKey.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/Security/Device.cs | 2 +- .../Entities/Security/DeviceOptions.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/TrickplayInfo.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/User.cs | 2 +- .../Jellyfin.Database.Implementations/Entities/UserData.cs | 2 +- .../Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs | 2 +- .../Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs | 2 +- .../Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs | 2 +- .../Interfaces/IHasPermissions.cs | 2 +- .../Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs | 2 +- .../Jellyfin.Database.Implementations/JellyfinDbContext.cs | 4 ++-- .../ModelConfiguration/ActivityLogConfiguration.cs | 2 +- .../ModelConfiguration/AncestorIdConfiguration.cs | 2 +- .../ModelConfiguration/ApiKeyConfiguration.cs | 2 +- .../ModelConfiguration/AttachmentStreamInfoConfiguration.cs | 2 +- .../ModelConfiguration/BaseItemConfiguration.cs | 2 +- .../ModelConfiguration/BaseItemMetadataFieldConfiguration.cs | 2 +- .../ModelConfiguration/BaseItemProviderConfiguration.cs | 2 +- .../ModelConfiguration/BaseItemTrailerTypeConfiguration.cs | 2 +- .../ModelConfiguration/ChapterConfiguration.cs | 2 +- .../CustomItemDisplayPreferencesConfiguration.cs | 2 +- .../ModelConfiguration/DeviceConfiguration.cs | 2 +- .../ModelConfiguration/DeviceOptionsConfiguration.cs | 2 +- .../ModelConfiguration/DisplayPreferencesConfiguration.cs | 2 +- .../ModelConfiguration/ItemValuesConfiguration.cs | 2 +- .../ModelConfiguration/ItemValuesMapConfiguration.cs | 2 +- .../ModelConfiguration/MediaStreamInfoConfiguration.cs | 2 +- .../ModelConfiguration/PeopleBaseItemMapConfiguration.cs | 2 +- .../ModelConfiguration/PeopleConfiguration.cs | 2 +- .../ModelConfiguration/PermissionConfiguration.cs | 2 +- .../ModelConfiguration/PreferenceConfiguration.cs | 2 +- .../ModelConfiguration/TrickplayInfoConfiguration.cs | 2 +- .../ModelConfiguration/UserConfiguration.cs | 2 +- .../ModelConfiguration/UserDataConfiguration.cs | 2 +- .../Jellyfin.Database.Providers.Sqlite.csproj | 7 ------- .../Migrations/SqliteDesignTimeJellyfinDbFactory.cs | 3 +-- .../Jellyfin.Database.Providers.Sqlite/ModelBuilderExtensions.cs | 2 +- .../ValueConverters/DateTimeKindValueConverter.cs | 2 +- src/Jellyfin.Drawing/ImageProcessor.cs | 2 +- src/Jellyfin.LiveTv/Channels/ChannelManager.cs | 2 +- src/Jellyfin.LiveTv/LiveTvManager.cs | 2 +- tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs | 2 +- .../DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs | 2 +- .../Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs | 2 +- .../Auth/IgnoreSchedulePolicy/IgnoreScheduleHandlerTests.cs | 2 +- tests/Jellyfin.Api.Tests/Controllers/UserControllerTests.cs | 2 +- tests/Jellyfin.Api.Tests/TestHelpers.cs | 4 ++-- .../EfMigrations/EfMigrationTests.cs | 1 + .../SessionManager/SessionManagerTests.cs | 2 +- tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs | 2 +- 240 files changed, 252 insertions(+), 255 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index 4a0662e16a..60f515f24d 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -4,7 +4,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Entities; diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 356d1e437a..0ce967e6a9 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -5,8 +5,8 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using MediaBrowser.Common; using MediaBrowser.Controller.Channels; diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index fb0a55135f..933cfc8cbe 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -5,8 +5,8 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Events; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 846663900b..27f6826685 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -19,8 +19,8 @@ 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.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 8631958365..afe5b14e92 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -14,8 +14,8 @@ using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; using Jellyfin.Data; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using Jellyfin.Extensions.Json; diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs index ffbf8068f0..28cf695007 100644 --- a/Emby.Server.Implementations/Library/MusicManager.cs +++ b/Emby.Server.Implementations/Library/MusicManager.cs @@ -4,8 +4,8 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs index 9253a9a69f..9d81b835ce 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; using System.Linq; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index 2a28131519..8b88b904bb 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -6,8 +6,8 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; -using Jellyfin.Data.Entities; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index 22baafbb07..5a9315a92a 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -7,8 +7,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using Jellyfin.Data; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Channels; diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 9e780a49e5..7b0a164414 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -9,8 +9,8 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs b/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs index db3aeaaf31..a5be2b616e 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Common; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Playlists; diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 959373fec8..42f7deca15 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -8,11 +8,11 @@ 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; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations.Entities; +using Jellyfin.Database.Implementations.Entities.Security; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Events; diff --git a/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs b/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs index e1c26d0121..9afc511086 100644 --- a/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs +++ b/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs @@ -2,8 +2,8 @@ #pragma warning disable CS1591 using System; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Sorting; diff --git a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs index d668c17bfc..4c013a8bd7 100644 --- a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs +++ b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs @@ -1,8 +1,8 @@ #nullable disable using System; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Sorting; diff --git a/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs b/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs index 622a341b6a..cf77861673 100644 --- a/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs +++ b/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs @@ -1,8 +1,8 @@ #nullable disable #pragma warning disable CS1591 -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Sorting; diff --git a/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs b/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs index 2a3e456c2d..e42c8a33a3 100644 --- a/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs +++ b/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs @@ -2,8 +2,8 @@ #pragma warning disable CS1591 -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Sorting; diff --git a/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs b/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs index afd8ccf9f3..f54188030b 100644 --- a/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs +++ b/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs @@ -2,8 +2,8 @@ #pragma warning disable CS1591 -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Sorting; diff --git a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs index 12f88bf4da..dd2149b578 100644 --- a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs +++ b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs @@ -1,7 +1,7 @@ #nullable disable -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Sorting; diff --git a/Emby.Server.Implementations/SyncPlay/Group.cs b/Emby.Server.Implementations/SyncPlay/Group.cs index a7821c0e0e..d47e477938 100644 --- a/Emby.Server.Implementations/SyncPlay/Group.cs +++ b/Emby.Server.Implementations/SyncPlay/Group.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Session; diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs index 74db077d8c..ee2e18f735 100644 --- a/Emby.Server.Implementations/TV/TVSeriesManager.cs +++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs @@ -4,8 +4,8 @@ using System; using System.Collections.Generic; using System.Linq; using Jellyfin.Data; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Configuration; diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs index 2da4839138..7ba75dc243 100644 --- a/Jellyfin.Api/Controllers/ArtistsController.cs +++ b/Jellyfin.Api/Controllers/ArtistsController.cs @@ -4,8 +4,8 @@ using System.Linq; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs index 2196616dd9..13064882cc 100644 --- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs +++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs @@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using Jellyfin.Api.Helpers; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs index 1fd57eba9c..dd60d01e0c 100644 --- a/Jellyfin.Api/Controllers/GenresController.cs +++ b/Jellyfin.Api/Controllers/GenresController.cs @@ -4,8 +4,8 @@ using System.Linq; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index b711990261..e7b7405ca9 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -130,7 +130,7 @@ public class ImageController : BaseJellyfinApiController await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); } - user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + extension)); + user.ProfileImage = new Database.Implementations.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + extension)); await _providerManager .SaveImage(stream, mimeType, user.ProfileImage.Path) diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs index e326b925b8..c4b9767565 100644 --- a/Jellyfin.Api/Controllers/InstantMixController.cs +++ b/Jellyfin.Api/Controllers/InstantMixController.cs @@ -6,7 +6,7 @@ using System.Linq; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index ff4540f58f..bde1758e99 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -11,8 +11,8 @@ using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.LibraryDtos; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Api; diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs index 09a7b73b94..363acf815a 100644 --- a/Jellyfin.Api/Controllers/MoviesController.cs +++ b/Jellyfin.Api/Controllers/MoviesController.cs @@ -5,8 +5,8 @@ using System.Linq; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index 0cb20e433d..1e45e53ca1 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -4,8 +4,8 @@ using System.Linq; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/PersonsController.cs b/Jellyfin.Api/Controllers/PersonsController.cs index b0c493fbec..4d12dc18fc 100644 --- a/Jellyfin.Api/Controllers/PersonsController.cs +++ b/Jellyfin.Api/Controllers/PersonsController.cs @@ -4,7 +4,7 @@ using System.Linq; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs index 794c6500c6..1577b45947 100644 --- a/Jellyfin.Api/Controllers/PlaystateController.cs +++ b/Jellyfin.Api/Controllers/PlaystateController.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs index 43c5384dce..52cb87e72c 100644 --- a/Jellyfin.Api/Controllers/StudiosController.cs +++ b/Jellyfin.Api/Controllers/StudiosController.cs @@ -3,8 +3,8 @@ using System.ComponentModel.DataAnnotations; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; 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 5075d91be7..52982c362d 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -3,8 +3,8 @@ using System.ComponentModel.DataAnnotations; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index 6cc2b4244c..0e04beb14e 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -7,8 +7,8 @@ using System.Threading.Tasks; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index bbfa270db9..ebf98da456 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -6,8 +6,8 @@ using System.Linq; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs index 6487160303..ebd0288ca6 100644 --- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs +++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs @@ -8,8 +8,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Extensions; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs index 1801b6bfd4..7b493d3fa0 100644 --- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs +++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs @@ -8,8 +8,8 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Extensions; using Jellyfin.Data; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs index 3c2691cb5e..e10e940f21 100644 --- a/Jellyfin.Api/Helpers/RequestHelpers.cs +++ b/Jellyfin.Api/Helpers/RequestHelpers.cs @@ -5,8 +5,8 @@ using System.Security.Claims; using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Data/Events/Users/UserCreatedEventArgs.cs b/Jellyfin.Data/Events/Users/UserCreatedEventArgs.cs index b3b8d28318..8de34fec2c 100644 --- a/Jellyfin.Data/Events/Users/UserCreatedEventArgs.cs +++ b/Jellyfin.Data/Events/Users/UserCreatedEventArgs.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; namespace Jellyfin.Data.Events.Users { diff --git a/Jellyfin.Data/Events/Users/UserDeletedEventArgs.cs b/Jellyfin.Data/Events/Users/UserDeletedEventArgs.cs index d57c917c9f..c85de34ded 100644 --- a/Jellyfin.Data/Events/Users/UserDeletedEventArgs.cs +++ b/Jellyfin.Data/Events/Users/UserDeletedEventArgs.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; namespace Jellyfin.Data.Events.Users { diff --git a/Jellyfin.Data/Events/Users/UserLockedOutEventArgs.cs b/Jellyfin.Data/Events/Users/UserLockedOutEventArgs.cs index 4475948219..46b399d26d 100644 --- a/Jellyfin.Data/Events/Users/UserLockedOutEventArgs.cs +++ b/Jellyfin.Data/Events/Users/UserLockedOutEventArgs.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; namespace Jellyfin.Data.Events.Users { diff --git a/Jellyfin.Data/Events/Users/UserPasswordChangedEventArgs.cs b/Jellyfin.Data/Events/Users/UserPasswordChangedEventArgs.cs index a235ccada9..ee41147d5d 100644 --- a/Jellyfin.Data/Events/Users/UserPasswordChangedEventArgs.cs +++ b/Jellyfin.Data/Events/Users/UserPasswordChangedEventArgs.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; namespace Jellyfin.Data.Events.Users { diff --git a/Jellyfin.Data/Events/Users/UserUpdatedEventArgs.cs b/Jellyfin.Data/Events/Users/UserUpdatedEventArgs.cs index 780ace6abe..0f2763f366 100644 --- a/Jellyfin.Data/Events/Users/UserUpdatedEventArgs.cs +++ b/Jellyfin.Data/Events/Users/UserUpdatedEventArgs.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; namespace Jellyfin.Data.Events.Users { diff --git a/Jellyfin.Data/UserEntityExtensions.cs b/Jellyfin.Data/UserEntityExtensions.cs index 8bf82265c9..149fc9042d 100644 --- a/Jellyfin.Data/UserEntityExtensions.cs +++ b/Jellyfin.Data/UserEntityExtensions.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel; using System.Linq; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Database.Implementations.Interfaces; diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs index 007a468bf2..8d492f7cd7 100644 --- a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs +++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs @@ -1,10 +1,10 @@ using System; using System.Linq; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Querying; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server.Implementations/Devices/DeviceManager.cs b/Jellyfin.Server.Implementations/Devices/DeviceManager.cs index e414a8232f..51a1186452 100644 --- a/Jellyfin.Server.Implementations/Devices/DeviceManager.cs +++ b/Jellyfin.Server.Implementations/Devices/DeviceManager.cs @@ -5,11 +5,11 @@ using System.Linq; using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Dtos; -using Jellyfin.Data.Entities; -using Jellyfin.Data.Entities.Security; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; +using Jellyfin.Database.Implementations.Entities.Security; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Library/LyricDownloadFailureLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Library/LyricDownloadFailureLogger.cs index 0d52bb9856..5f4864e953 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Library/LyricDownloadFailureLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Library/LyricDownloadFailureLogger.cs @@ -1,7 +1,7 @@ using System; using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Events; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Library/SubtitleDownloadFailureLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Library/SubtitleDownloadFailureLogger.cs index 0a8c064a99..8fe380e4f4 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Library/SubtitleDownloadFailureLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Library/SubtitleDownloadFailureLogger.cs @@ -1,7 +1,7 @@ using System; using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Events; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs index a4424c7391..1a8931a6dc 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs @@ -1,7 +1,7 @@ using System; using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Authentication; using MediaBrowser.Model.Activity; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs index e0ecef2a5d..584d559e44 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs @@ -1,6 +1,6 @@ using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Authentication; using MediaBrowser.Model.Activity; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs index 0ef929a99b..73323acb37 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs @@ -1,8 +1,8 @@ using System; using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Activity; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs index 7d452ea2fd..b75567539c 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs @@ -1,8 +1,8 @@ using System; using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Activity; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionEndedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionEndedLogger.cs index 77e7859c6f..b90708a2f2 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionEndedLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionEndedLogger.cs @@ -1,6 +1,6 @@ using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Session; using MediaBrowser.Model.Activity; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs index 141dc20ea3..139c2e2acb 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs @@ -1,6 +1,6 @@ using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Session; using MediaBrowser.Model.Activity; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedLogger.cs index b0a9393eb6..da82a3b30f 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedLogger.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Text; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Globalization; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedLogger.cs index 0ae9b7f66f..632f30c7ad 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedLogger.cs @@ -1,7 +1,7 @@ using System; using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Events; using MediaBrowser.Model.Activity; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs index 287ba578ba..4b49b714cf 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs @@ -1,7 +1,7 @@ using System; using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Updates; using MediaBrowser.Model.Activity; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs index 2de207b152..2d24de7fc6 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs @@ -1,7 +1,7 @@ using System; using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Updates; using MediaBrowser.Model.Activity; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs index 08d6bf9c25..e892d3dd9a 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs @@ -1,7 +1,7 @@ using System; using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Updates; using MediaBrowser.Model.Activity; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserCreatedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserCreatedLogger.cs index a09c344f61..4f063f6a1b 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserCreatedLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserCreatedLogger.cs @@ -1,7 +1,7 @@ using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Events.Users; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Globalization; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs index 46da8044a1..ba4a072e84 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs @@ -1,8 +1,8 @@ using System; using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Events.Users; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Globalization; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserLockedOutLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserLockedOutLogger.cs index 1d0d016a74..bbc00567d1 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserLockedOutLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserLockedOutLogger.cs @@ -1,7 +1,7 @@ using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Events.Users; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Globalization; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserPasswordChangedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserPasswordChangedLogger.cs index 2b8f966a80..7219704ec6 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserPasswordChangedLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserPasswordChangedLogger.cs @@ -1,7 +1,7 @@ using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Events.Users; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Events; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Globalization; diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs index 1f04b28290..4f69022441 100644 --- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs +++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs @@ -16,9 +16,9 @@ using System.Reflection; using System.Text; using System.Text.Json; using System.Threading; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using Jellyfin.Extensions.Json; @@ -38,7 +38,7 @@ using MediaBrowser.Model.Querying; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using BaseItemDto = MediaBrowser.Controller.Entities.BaseItem; -using BaseItemEntity = Jellyfin.Data.Entities.BaseItemEntity; +using BaseItemEntity = Jellyfin.Database.Implementations.Entities.BaseItemEntity; namespace Jellyfin.Server.Implementations.Item; diff --git a/Jellyfin.Server.Implementations/Item/ChapterRepository.cs b/Jellyfin.Server.Implementations/Item/ChapterRepository.cs index 48b94a5f3f..93e15735c9 100644 --- a/Jellyfin.Server.Implementations/Item/ChapterRepository.cs +++ b/Jellyfin.Server.Implementations/Item/ChapterRepository.cs @@ -2,8 +2,8 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Jellyfin.Data.Entities; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; 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 18167cc530..3ae6dbd702 100644 --- a/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs +++ b/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; -using Jellyfin.Data.Entities; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; 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 f700718841..36c3b9e565 100644 --- a/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs +++ b/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; -using Jellyfin.Data.Entities; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; 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 01a0ade63c..51040cee73 100644 --- a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs +++ b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs @@ -2,9 +2,9 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; 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 fa507ad040..d6eeafacc3 100644 --- a/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs +++ b/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs @@ -5,8 +5,8 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs b/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs index 534e80f4e7..cf0293463f 100644 --- a/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs +++ b/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Jellyfin.Data.Entities.Security; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities.Security; using MediaBrowser.Controller.Security; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs index b55d2271a6..bf39f13a77 100644 --- a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs +++ b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs @@ -7,8 +7,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; -using Jellyfin.Data.Entities; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; diff --git a/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs index acada7aa46..35c43b176d 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs @@ -2,7 +2,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Authentication; using MediaBrowser.Model.Cryptography; using Microsoft.Extensions.Logging; diff --git a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs index cefbd0624d..6296881a9e 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs @@ -4,7 +4,7 @@ using System.IO; using System.Security.Cryptography; using System.Text.Json; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Common; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Authentication; diff --git a/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs b/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs index 02a52e5f25..92e2bb4fa7 100644 --- a/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs +++ b/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs @@ -1,9 +1,9 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data; -using Jellyfin.Data.Entities; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; diff --git a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs index 3f9491038d..0f21e11a35 100644 --- a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs +++ b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs @@ -5,8 +5,8 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs b/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs index c4e4c460a6..caf9d5bd9a 100644 --- a/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs +++ b/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Authentication; namespace Jellyfin.Server.Implementations.Users diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 0105f8162d..3c39e5503b 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -8,11 +8,11 @@ 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; using Jellyfin.Data.Events.Users; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common; diff --git a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs index 933d85de01..e9fe9abceb 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs @@ -2,8 +2,8 @@ using System; using System.Collections.Generic; using System.IO; using Emby.Server.Implementations.Data; -using Jellyfin.Data.Entities; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; 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 a50990ac5d..feaf46c843 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs @@ -2,8 +2,8 @@ using System; using System.Collections.Generic; using System.IO; using Emby.Server.Implementations.Data; -using Jellyfin.Data.Entities.Security; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities.Security; 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 4f6c5100d9..a8fa2e52a1 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs @@ -5,8 +5,8 @@ using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using Emby.Server.Implementations.Data; -using Jellyfin.Data.Entities; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; diff --git a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs index 490daae42b..08eea03086 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs @@ -11,8 +11,8 @@ using System.Linq; using System.Text; using System.Threading; using Emby.Server.Implementations.Data; -using Jellyfin.Data.Entities; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using Jellyfin.Server.Implementations.Item; using MediaBrowser.Controller; @@ -21,7 +21,8 @@ using MediaBrowser.Model.Entities; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -using Chapter = Jellyfin.Data.Entities.Chapter; +using BaseItemEntity = Jellyfin.Database.Implementations.Entities.BaseItemEntity; +using Chapter = Jellyfin.Database.Implementations.Entities.Chapter; namespace Jellyfin.Server.Migrations.Routines; @@ -125,7 +126,7 @@ public class MigrateLibraryDb : IMigrationRoutine dbContext.ItemValues.ExecuteDelete(); // EFCores local lookup sucks. We cannot use context.ItemValues.Local here because its just super slow. - var localItems = new Dictionary<(int Type, string CleanValue), (ItemValue ItemValue, List ItemIds)>(); + var localItems = new Dictionary<(int Type, string CleanValue), (Database.Implementations.Entities.ItemValue ItemValue, List ItemIds)>(); foreach (SqliteDataReader dto in connection.Query(itemValueQuery)) { diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index bd5bf98e0f..c40560660d 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -2,8 +2,8 @@ using System; using System.IO; using Emby.Server.Implementations.Data; using Jellyfin.Data; -using Jellyfin.Data.Entities; using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions.Json; using Jellyfin.Server.Implementations.Users; diff --git a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs index 81b532fda8..976a667acd 100644 --- a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs +++ b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Authentication diff --git a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs index 8c9d1baf88..592ce99556 100644 --- a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs +++ b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs @@ -4,7 +4,7 @@ using System; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Authentication diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index f6cbf5a00c..199e22b3fa 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using Jellyfin.Data; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Querying; diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs index 38a78a67b5..206b5ac426 100644 --- a/MediaBrowser.Controller/Collections/ICollectionManager.cs +++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs index fe7dc1cf94..ea38950d32 100644 --- a/MediaBrowser.Controller/Devices/IDeviceManager.cs +++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs @@ -1,10 +1,10 @@ using System; using System.Threading.Tasks; using Jellyfin.Data.Dtos; -using Jellyfin.Data.Entities; -using Jellyfin.Data.Entities.Security; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations.Entities; +using Jellyfin.Database.Implementations.Entities.Security; using MediaBrowser.Model.Devices; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index 702ce39a2a..4eeec99b0b 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index 22453f0f76..f1d507fcbd 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -1,7 +1,7 @@ #pragma warning disable CA1002 using System.Collections.Generic; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index d6e6592429..d016d8f62b 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -9,8 +9,8 @@ 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.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 39dc909633..58841e5b78 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -9,8 +9,8 @@ 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.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Providers; diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 29481481c4..1dd289631d 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -13,8 +13,8 @@ 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.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index b7b5dac034..ca79e62454 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -11,8 +11,8 @@ using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions.Json; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index d3e9da6226..dd85a6ec0e 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -14,8 +14,8 @@ 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.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Channels; diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 57a8a01131..5ce5fd4fa9 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -4,8 +4,8 @@ using System; using System.Collections.Generic; using System.Linq; using Jellyfin.Data; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs b/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs index 3e1d892748..203a16a668 100644 --- a/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; namespace MediaBrowser.Controller.Entities { diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index a252b7a25f..d656fccb4f 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -8,8 +8,8 @@ using System.Collections.Immutable; using System.Linq; using System.Text.Json.Serialization; using Jellyfin.Data; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Querying; diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 9dbac1e920..1293528fba 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -7,8 +7,8 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text.Json.Serialization; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using MediaBrowser.Common; using MediaBrowser.Controller.Dto; diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 470702f3e6..5dad158519 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -10,8 +10,8 @@ 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.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Providers; diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index 7ae4a4a2cd..bc7e22d9a0 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Library; using MediaBrowser.Model.Querying; diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index f5ca3737c2..dfa31315cb 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -8,8 +8,8 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.TV; diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 18845ab9f6..c2b4da32ac 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -7,8 +7,8 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using Jellyfin.Data; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Library; diff --git a/MediaBrowser.Controller/IDisplayPreferencesManager.cs b/MediaBrowser.Controller/IDisplayPreferencesManager.cs index 10c0f56e09..a97096eaee 100644 --- a/MediaBrowser.Controller/IDisplayPreferencesManager.cs +++ b/MediaBrowser.Controller/IDisplayPreferencesManager.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; namespace MediaBrowser.Controller { diff --git a/MediaBrowser.Controller/Library/IIntroProvider.cs b/MediaBrowser.Controller/Library/IIntroProvider.cs index 4a9721acbe..860e948afe 100644 --- a/MediaBrowser.Controller/Library/IIntroProvider.cs +++ b/MediaBrowser.Controller/Library/IIntroProvider.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Library @@ -23,6 +24,6 @@ namespace MediaBrowser.Controller.Library /// The item. /// The user. /// IEnumerable{System.String}. - Task> GetIntros(BaseItem item, Jellyfin.Data.Entities.User user); + Task> GetIntros(BaseItem item, User user); } } diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 13915dc5c6..a3e3e4991c 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -4,8 +4,8 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index eb697268c7..2b6781a197 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -6,7 +6,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Persistence; diff --git a/MediaBrowser.Controller/Library/IMusicManager.cs b/MediaBrowser.Controller/Library/IMusicManager.cs index 7ba8fc20cf..20764ec601 100644 --- a/MediaBrowser.Controller/Library/IMusicManager.cs +++ b/MediaBrowser.Controller/Library/IMusicManager.cs @@ -1,7 +1,7 @@ #pragma warning disable CA1002, CS1591 using System.Collections.Generic; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs index 5a2deda66a..eb46611dd9 100644 --- a/MediaBrowser.Controller/Library/IUserDataManager.cs +++ b/MediaBrowser.Controller/Library/IUserDataManager.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Threading; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 1c115be857..0109cf4b7d 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Events; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Users; diff --git a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs index 76e9eb1f54..b0a6782c77 100644 --- a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs +++ b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index c0e46ba245..8d59eef9f1 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -6,8 +6,8 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Events; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index caa312987d..7586ac9024 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -6,8 +6,8 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs b/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs index 1e75446e1c..456977b88e 100644 --- a/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs +++ b/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.MediaSegments; diff --git a/MediaBrowser.Controller/Net/AuthorizationInfo.cs b/MediaBrowser.Controller/Net/AuthorizationInfo.cs index e452f26494..dd5eb9a01d 100644 --- a/MediaBrowser.Controller/Net/AuthorizationInfo.cs +++ b/MediaBrowser.Controller/Net/AuthorizationInfo.cs @@ -1,6 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; namespace MediaBrowser.Controller.Net { diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 53e04066f0..1062399e3f 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -10,8 +10,8 @@ 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.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 5dd0413b4d..21131e6b5e 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -6,7 +6,8 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities.Security; +using Jellyfin.Database.Implementations.Entities; +using Jellyfin.Database.Implementations.Entities.Security; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; @@ -73,7 +74,7 @@ namespace MediaBrowser.Controller.Session /// The remote end point. /// The user. /// A task containing the session information. - Task LogSessionActivity(string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, Jellyfin.Data.Entities.User user); + Task LogSessionActivity(string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user); /// /// Used to report that a session controller has connected. diff --git a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs index 66a0c52547..97f653edf5 100644 --- a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs +++ b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs @@ -1,5 +1,6 @@ #nullable disable +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Library; namespace MediaBrowser.Controller.Sorting @@ -13,7 +14,7 @@ namespace MediaBrowser.Controller.Sorting /// Gets or sets the user. /// /// The user. - Jellyfin.Data.Entities.User User { get; set; } + User User { get; set; } /// /// Gets or sets the user manager. diff --git a/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs b/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs index 800317800d..9ac8ead11c 100644 --- a/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs +++ b/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Configuration; diff --git a/MediaBrowser.Model/Activity/IActivityManager.cs b/MediaBrowser.Model/Activity/IActivityManager.cs index 28073fb8d7..95aa567ada 100644 --- a/MediaBrowser.Model/Activity/IActivityManager.cs +++ b/MediaBrowser.Model/Activity/IActivityManager.cs @@ -2,9 +2,9 @@ using System; using System.Threading.Tasks; -using Jellyfin.Data.Entities; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Model.Querying; namespace MediaBrowser.Model.Activity diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 7e8949e1fb..7bfd8ca29c 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Library; diff --git a/MediaBrowser.Model/Library/UserViewQuery.cs b/MediaBrowser.Model/Library/UserViewQuery.cs index 643a1f9b13..01d5e3b6ca 100644 --- a/MediaBrowser.Model/Library/UserViewQuery.cs +++ b/MediaBrowser.Model/Library/UserViewQuery.cs @@ -1,8 +1,8 @@ #pragma warning disable CS1591 using System; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; namespace MediaBrowser.Model.Library { diff --git a/MediaBrowser.Model/Querying/LatestItemsQuery.cs b/MediaBrowser.Model/Querying/LatestItemsQuery.cs index 251ff5d681..40dc813978 100644 --- a/MediaBrowser.Model/Querying/LatestItemsQuery.cs +++ b/MediaBrowser.Model/Querying/LatestItemsQuery.cs @@ -2,8 +2,8 @@ #pragma warning disable CS1591 using System; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Model.Entities; namespace MediaBrowser.Model.Querying diff --git a/MediaBrowser.Model/Querying/NextUpQuery.cs b/MediaBrowser.Model/Querying/NextUpQuery.cs index aee720aa7b..a2a3a9d1bb 100644 --- a/MediaBrowser.Model/Querying/NextUpQuery.cs +++ b/MediaBrowser.Model/Querying/NextUpQuery.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 using System; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Model.Entities; namespace MediaBrowser.Model.Querying; diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index ba0eaf21cf..3d430e1015 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -7,7 +7,7 @@ using System.ComponentModel.DataAnnotations; using System.Xml.Serialization; using Jellyfin.Data.Enums; using Jellyfin.Database.Implementations.Enums; -using AccessSchedule = Jellyfin.Data.Entities.AccessSchedule; +using AccessSchedule = Jellyfin.Database.Implementations.Entities.AccessSchedule; namespace MediaBrowser.Model.Users { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs index 909e8750f8..e23ac86aaa 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations.Schema; using System.Xml.Serialization; using Jellyfin.Database.Implementations.Enums; -namespace Jellyfin.Data.Entities +namespace Jellyfin.Database.Implementations.Entities { /// /// An entity representing a user's access schedule. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs index 3a76784052..bf623be7ed 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; using Microsoft.Extensions.Logging; -namespace Jellyfin.Data.Entities +namespace Jellyfin.Database.Implementations.Entities { /// /// An entity referencing an activity log entry. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AncestorId.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AncestorId.cs index 954416dfe1..3d25ae4f45 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AncestorId.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AncestorId.cs @@ -1,6 +1,6 @@ using System; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Represents the relational information for an . diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs index 19265a0115..aab3082b37 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs @@ -1,6 +1,6 @@ using System; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Provides information about an Attachment to an . diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs index 42be5b3b99..fc9695a091 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; public class BaseItemEntity { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemExtraType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemExtraType.cs index 54aef50e40..46a59f7903 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemExtraType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemExtraType.cs @@ -1,5 +1,5 @@ #pragma warning disable CS1591 -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; public enum BaseItemExtraType { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs index ac6b72acea..71d60fc25d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs @@ -2,7 +2,7 @@ using System; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Enum TrailerTypes. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemMetadataField.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemMetadataField.cs index 27bbfc4731..e7dbc8e9fd 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemMetadataField.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemMetadataField.cs @@ -1,6 +1,6 @@ using System; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Enum MetadataFields. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs index c0c5e3147f..73bb583e31 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs @@ -1,6 +1,6 @@ using System; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Represents a Key-Value relation of an BaseItem's provider. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemTrailerType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemTrailerType.cs index 2bb648138a..db329ad2af 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemTrailerType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemTrailerType.cs @@ -1,6 +1,6 @@ using System; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Enum TrailerTypes. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Chapter.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Chapter.cs index 579442cdb6..f9b9813281 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Chapter.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Chapter.cs @@ -1,6 +1,6 @@ using System; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// The Chapter entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/CustomItemDisplayPreferences.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/CustomItemDisplayPreferences.cs index a606595122..b3d4b16bc6 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/CustomItemDisplayPreferences.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/CustomItemDisplayPreferences.cs @@ -2,7 +2,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace Jellyfin.Data.Entities +namespace Jellyfin.Database.Implementations.Entities { /// /// An entity that represents a user's custom display preferences for a specific item. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs index 82bf007a8a..ae6966e594 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Enums; -namespace Jellyfin.Data.Entities +namespace Jellyfin.Database.Implementations.Entities { /// /// An entity representing a user's display preferences. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs index 4b343c164a..9dd2486464 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities +namespace Jellyfin.Database.Implementations.Entities { /// /// An entity representing a group. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs index edffec4aba..584550ac56 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs @@ -1,7 +1,7 @@ using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Enums; -namespace Jellyfin.Data.Entities +namespace Jellyfin.Database.Implementations.Entities { /// /// An entity representing a section on the user's home page. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfo.cs index 935a53a263..9c0b36852e 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfo.cs @@ -2,7 +2,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace Jellyfin.Data.Entities +namespace Jellyfin.Database.Implementations.Entities { /// /// An entity representing an image. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfoImageType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfoImageType.cs index f78178dd22..6052a95bb2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfoImageType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ImageInfoImageType.cs @@ -1,4 +1,4 @@ -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Enum ImageType. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs index 7e75a200b6..6770531143 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Enums; -namespace Jellyfin.Data.Entities +namespace Jellyfin.Database.Implementations.Entities { /// /// An entity that represents a user's display preferences for a specific item. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValue.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValue.cs index 11d8e383ee..b5a31921d8 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValue.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValue.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Represents an ItemValue for a BaseItem. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs index e80a9aec34..23f6e0f7bc 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs @@ -1,6 +1,6 @@ using System; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Mapping table for the ItemValue BaseItem relation. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueType.cs index 3bae3beccd..9e2e11c006 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueType.cs @@ -1,5 +1,5 @@ #pragma warning disable CA1027 // Mark enums with FlagsAttribute -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Provides the Value types for an . 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 b529da8fa7..f3083a96ba 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing artwork. 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 54c30d92ce..b56c1f9403 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a book. 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 7b1a68bb55..a284d563a3 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity containing metadata for a book. 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 cbcb9a5f54..eac973060e 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a chapter. 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 8da9793f9d..03b68317a6 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs @@ -5,7 +5,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a collection. 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 4bd99d83a7..3777c705b8 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a collection item. 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 5dc1039a1f..c686751ab7 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a company. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CompanyMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CompanyMetadata.cs index a29f08c7f6..fdf1f274fb 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CompanyMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CompanyMetadata.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity holding metadata for a . 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 92307afecd..70e47d6bc6 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a custom item. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItemMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItemMetadata.cs index af2393870f..660e535e3a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItemMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItemMetadata.cs @@ -1,4 +1,4 @@ -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity containing metadata for a custom item. 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 6379755264..7cb71f06d9 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing an episode. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/EpisodeMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/EpisodeMetadata.cs index b0ef11e0f2..b5c2c3c2a3 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/EpisodeMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/EpisodeMetadata.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity containing metadata for an . 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 329b8973f5..442dced2f4 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a genre. 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 401d58ff22..e5cbab7e45 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An abstract class that holds metadata. 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 17673cb1d9..d1877ef438 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a library. 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 975614be10..4fccf6d731 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a library item. 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 0913f95be1..6e435579c7 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs @@ -5,7 +5,7 @@ using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a file on disk. 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 3170653fec..4552386fee 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a stream in a media file. 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 afaebb8e86..dc8f153500 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a metadata provider. 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 fa36e58db7..b7c9313a26 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a unique identifier for a metadata provider. 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 beae325ec5..afc0e0f435 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a movie. 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 df48ebf279..3d797d97e7 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity holding the metadata for a movie. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbum.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbum.cs index d6231bbf02..51f77ce0be 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbum.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbum.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a music album. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbumMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbumMetadata.cs index 691f3504fa..bfb94c44d6 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbumMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MusicAlbumMetadata.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity holding the metadata for a music album. 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 d9609f1cc0..25cdfdc2ee 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a person. 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 627f74140b..e1c2113908 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a person's role in media. 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 094d57139c..b113170e1d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a photo. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PhotoMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PhotoMetadata.cs index 6c284307d7..6fae4a024f 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PhotoMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PhotoMetadata.cs @@ -1,4 +1,4 @@ -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity that holds metadata for a photo. 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 6b792ffb48..627575024e 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a rating for an entity. 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 91ee8caa16..8322855991 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// This is the entity to store review ratings, not age ratings. 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 40466def1d..db148338e2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a release for a library item, eg. Director's cut vs. standard. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Season.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Season.cs index fc110b49da..dc9f695d98 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Season.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Season.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a season. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeasonMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeasonMetadata.cs index da40a075f5..af1e9fa2b7 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeasonMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeasonMetadata.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity that holds metadata for seasons. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Series.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Series.cs index ab484c96d6..1e1633248f 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Series.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Series.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a series. 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 28da91e472..b1b2b10bea 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing series metadata. 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 6d6a920225..f0bd88963a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity representing a track. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/TrackMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/TrackMetadata.cs index 042d2b90db..d9b4736a7c 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/TrackMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/TrackMetadata.cs @@ -1,4 +1,4 @@ -namespace Jellyfin.Data.Entities.Libraries +namespace Jellyfin.Database.Implementations.Entities.Libraries { /// /// An entity holding metadata for a track. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs index 8c1c071e63..c34369d889 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs @@ -2,7 +2,7 @@ using System; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Enums; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// An entity representing the metadata for a group of trickplay tiles. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs index b16b62b104..207317376d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs @@ -2,7 +2,7 @@ using System; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; public class MediaStreamInfo { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamTypeEntity.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamTypeEntity.cs index f57672a2cf..33dd81bdd6 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamTypeEntity.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamTypeEntity.cs @@ -1,4 +1,4 @@ -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Enum MediaStreamType. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/People.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/People.cs index 18c778b17a..20cf3e2d9e 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/People.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/People.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// People entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/PeopleBaseItemMap.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/PeopleBaseItemMap.cs index bfaaf82151..c719a185c4 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/PeopleBaseItemMap.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/PeopleBaseItemMap.cs @@ -1,6 +1,6 @@ using System; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Mapping table for People to BaseItems. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs index c488b90e1c..84b86574cc 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs @@ -6,7 +6,7 @@ using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities +namespace Jellyfin.Database.Implementations.Entities { /// /// An entity representing whether the associated user has a specific permission. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs index f4f9dd17ac..c02ea7375a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities +namespace Jellyfin.Database.Implementations.Entities { /// /// An entity representing a preference attached to a user or group. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ProgramAudioEntity.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ProgramAudioEntity.cs index 9d79e5ddb1..cb7255c19f 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ProgramAudioEntity.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ProgramAudioEntity.cs @@ -1,4 +1,4 @@ -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Lists types of Audio. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/ApiKey.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/ApiKey.cs index 1fcbe0f5e9..25a1d5ce90 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/ApiKey.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/ApiKey.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Globalization; -namespace Jellyfin.Data.Entities.Security +namespace Jellyfin.Database.Implementations.Entities.Security { /// /// An entity representing an API key. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/Device.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/Device.cs index 67d7f78eda..b0f9b2d569 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/Device.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/Device.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Globalization; -namespace Jellyfin.Data.Entities.Security +namespace Jellyfin.Database.Implementations.Entities.Security { /// /// An entity representing a device. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/DeviceOptions.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/DeviceOptions.cs index 531f66c627..8ac3e364c4 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/DeviceOptions.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/DeviceOptions.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations.Schema; -namespace Jellyfin.Data.Entities.Security +namespace Jellyfin.Database.Implementations.Entities.Security { /// /// An entity representing custom options for a device. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/TrickplayInfo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/TrickplayInfo.cs index ff9a68beff..06b290e4f2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/TrickplayInfo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/TrickplayInfo.cs @@ -1,7 +1,7 @@ using System; using System.Text.Json.Serialization; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// An entity representing the metadata for a group of trickplay tiles. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs index aafa92b4a6..31538b5bf3 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs @@ -6,7 +6,7 @@ using System.Text.Json.Serialization; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Database.Implementations.Interfaces; -namespace Jellyfin.Data.Entities +namespace Jellyfin.Database.Implementations.Entities { /// /// An entity representing a user. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs index ced12b9e62..cd80686615 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs @@ -1,6 +1,6 @@ using System; -namespace Jellyfin.Data.Entities; +namespace Jellyfin.Database.Implementations.Entities; /// /// Provides and related data. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs index fed092b978..a6e8732fff 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; namespace Jellyfin.Database.Implementations.Enums; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs index 03c2ca4a47..46007472a2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Entities.Libraries; +using Jellyfin.Database.Implementations.Entities.Libraries; namespace Jellyfin.Database.Implementations.Interfaces { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs index ed449a8f14..5cfefa456a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Entities.Libraries; +using Jellyfin.Database.Implementations.Entities.Libraries; namespace Jellyfin.Database.Implementations.Interfaces { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs index 606b1169b8..99b29e6d35 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; namespace Jellyfin.Database.Implementations.Interfaces; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs index 653572b6e9..742a6a3867 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Entities.Libraries; +using Jellyfin.Database.Implementations.Entities.Libraries; namespace Jellyfin.Database.Implementations.Interfaces; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs index 5cdc853319..9db70263d2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs @@ -1,7 +1,7 @@ using System; using System.Linq; -using Jellyfin.Data.Entities; -using Jellyfin.Data.Entities.Security; +using Jellyfin.Database.Implementations.Entities; +using Jellyfin.Database.Implementations.Entities.Security; using Jellyfin.Database.Implementations.Interfaces; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs index be99b46d56..a209c5b90d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs index 146df5546c..1cb4a1eb1d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs index 7c15f064d8..ea382c7183 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities.Security; +using Jellyfin.Database.Implementations.Entities.Security; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs index b5fae4053c..66cafc83cf 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs index 67a071039f..37816faece 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs index c101e0085e..a602ea65f4 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs index 175a82e091..dd28000ba6 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs index c7efef2390..2a888b7de8 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs index 5935b632a7..d97a39f4d2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs index 550fa5073b..e8a510ab97 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs index 5f87c8d403..3551f76863 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities.Security; +using Jellyfin.Database.Implementations.Entities.Security; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs index 923a53acaf..9055e80253 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities.Security; +using Jellyfin.Database.Implementations.Entities.Security; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs index 92068c8f29..45e0c64824 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs index 0e63c130e3..c8e003eaa1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs index 3860b0e161..42ef235326 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs index 37e15f5e72..075af2c053 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs index 125b9e92cd..5e3ab44433 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs index fe25d3064d..e8f77a8067 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs index 90a3ec5d00..d2aed54eb1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs index d6d3fadfc4..207051bcd1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs index a198c80f7e..1b364a05ed 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs index 4e830801ee..61b5e06e8a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs index a7e223c435..47604d3217 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs @@ -1,4 +1,4 @@ -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Jellyfin.Database.Providers.Sqlite.csproj b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Jellyfin.Database.Providers.Sqlite.csproj index 4e5f63f6fe..ac62ea59a1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Jellyfin.Database.Providers.Sqlite.csproj +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Jellyfin.Database.Providers.Sqlite.csproj @@ -23,13 +23,6 @@ - - - - - - - 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 1629c732c6..78815c3118 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/SqliteDesignTimeJellyfinDbFactory.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/SqliteDesignTimeJellyfinDbFactory.cs @@ -1,10 +1,9 @@ using Jellyfin.Database.Implementations; -using Jellyfin.Database.Providers.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Logging.Abstractions; -namespace Jellyfin.Server.Implementations.Migrations +namespace Jellyfin.Database.Providers.Sqlite.Migrations { /// /// The design time factory for . diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ModelBuilderExtensions.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ModelBuilderExtensions.cs index 0d75686198..41375874d9 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ModelBuilderExtensions.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ModelBuilderExtensions.cs @@ -1,5 +1,5 @@ using System; -using Jellyfin.Server.Implementations.ValueConverters; +using Jellyfin.Database.Providers.Sqlite.ValueConverters; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ValueConverters/DateTimeKindValueConverter.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ValueConverters/DateTimeKindValueConverter.cs index 2e585c92df..d4a9407b0d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ValueConverters/DateTimeKindValueConverter.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ValueConverters/DateTimeKindValueConverter.cs @@ -1,7 +1,7 @@ using System; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -namespace Jellyfin.Server.Implementations.ValueConverters +namespace Jellyfin.Database.Providers.Sqlite.ValueConverters { /// /// ValueConverter to specify kind. diff --git a/src/Jellyfin.Drawing/ImageProcessor.cs b/src/Jellyfin.Drawing/ImageProcessor.cs index fcb315b3a9..7718f6c6a5 100644 --- a/src/Jellyfin.Drawing/ImageProcessor.cs +++ b/src/Jellyfin.Drawing/ImageProcessor.cs @@ -9,7 +9,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; diff --git a/src/Jellyfin.LiveTv/Channels/ChannelManager.cs b/src/Jellyfin.LiveTv/Channels/ChannelManager.cs index 402a3f3b0e..0ca294a289 100644 --- a/src/Jellyfin.LiveTv/Channels/ChannelManager.cs +++ b/src/Jellyfin.LiveTv/Channels/ChannelManager.cs @@ -9,8 +9,8 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using Jellyfin.Extensions.Json; diff --git a/src/Jellyfin.LiveTv/LiveTvManager.cs b/src/Jellyfin.LiveTv/LiveTvManager.cs index 7ebcc48834..40adb51a58 100644 --- a/src/Jellyfin.LiveTv/LiveTvManager.cs +++ b/src/Jellyfin.LiveTv/LiveTvManager.cs @@ -9,9 +9,9 @@ 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; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.LiveTv.Configuration; using MediaBrowser.Common.Extensions; diff --git a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs index 0a6489d0ac..7e44b062cf 100644 --- a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs @@ -7,7 +7,7 @@ using AutoFixture.AutoMoq; using Jellyfin.Api.Auth; using Jellyfin.Api.Constants; using Jellyfin.Data; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Net; diff --git a/tests/Jellyfin.Api.Tests/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs index 162a022f5b..bfc7016d2a 100644 --- a/tests/Jellyfin.Api.Tests/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs @@ -7,7 +7,7 @@ using AutoFixture; using AutoFixture.AutoMoq; using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; using Jellyfin.Api.Constants; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Server.Implementations.Security; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Library; diff --git a/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs index 1fe9fc97ef..fc243a8730 100644 --- a/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs @@ -7,7 +7,7 @@ using AutoFixture.AutoMoq; using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; using Jellyfin.Api.Auth.FirstTimeSetupPolicy; using Jellyfin.Api.Constants; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Library; diff --git a/tests/Jellyfin.Api.Tests/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandlerTests.cs index ed5235252a..6e63c0450b 100644 --- a/tests/Jellyfin.Api.Tests/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandlerTests.cs @@ -5,7 +5,7 @@ using AutoFixture; using AutoFixture.AutoMoq; using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; using Jellyfin.Api.Constants; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Library; diff --git a/tests/Jellyfin.Api.Tests/Controllers/UserControllerTests.cs b/tests/Jellyfin.Api.Tests/Controllers/UserControllerTests.cs index c7331c7181..a74dab5f29 100644 --- a/tests/Jellyfin.Api.Tests/Controllers/UserControllerTests.cs +++ b/tests/Jellyfin.Api.Tests/Controllers/UserControllerTests.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Threading.Tasks; using AutoFixture.Xunit2; using Jellyfin.Api.Controllers; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; diff --git a/tests/Jellyfin.Api.Tests/TestHelpers.cs b/tests/Jellyfin.Api.Tests/TestHelpers.cs index 03884d7754..eff14e5f15 100644 --- a/tests/Jellyfin.Api.Tests/TestHelpers.cs +++ b/tests/Jellyfin.Api.Tests/TestHelpers.cs @@ -5,7 +5,7 @@ using System.Net; using System.Security.Claims; using Jellyfin.Api.Constants; using Jellyfin.Data; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Server.Implementations.Users; using MediaBrowser.Common.Configuration; @@ -13,7 +13,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Model.Configuration; using Microsoft.AspNetCore.Http; using Moq; -using AccessSchedule = Jellyfin.Data.Entities.AccessSchedule; +using AccessSchedule = Jellyfin.Database.Implementations.Entities.AccessSchedule; namespace Jellyfin.Api.Tests { diff --git a/tests/Jellyfin.Server.Implementations.Tests/EfMigrations/EfMigrationTests.cs b/tests/Jellyfin.Server.Implementations.Tests/EfMigrations/EfMigrationTests.cs index 3fe2caca79..ba3abd5a22 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/EfMigrations/EfMigrationTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/EfMigrations/EfMigrationTests.cs @@ -1,3 +1,4 @@ +using Jellyfin.Database.Providers.Sqlite.Migrations; using Jellyfin.Server.Implementations.Migrations; using Microsoft.EntityFrameworkCore; using Xunit; diff --git a/tests/Jellyfin.Server.Implementations.Tests/SessionManager/SessionManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/SessionManager/SessionManagerTests.cs index 9418edc5d6..a5a67046d1 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/SessionManager/SessionManagerTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/SessionManager/SessionManagerTests.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs index a71a08d8cd..e422eb9b8b 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs +++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs @@ -1,8 +1,8 @@ using System; using System.Linq; using System.Threading; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; -- cgit v1.2.3 From d06ce1f1e035d4630121f45dcadbdebc95cb07e2 Mon Sep 17 00:00:00 2001 From: JQ <81431263+scampower3@users.noreply.github.com> Date: Thu, 27 Mar 2025 10:26:47 +0800 Subject: Fix only returning one item from /Item/Latest api. (#12492) * Updated to EFcore * Remove unused using * Dont use DateCreated not from episode type or music type * use TranslateQuery to filter out instead and then do the grouping and retrival of min and max datecreated instead * Album also --- .../Library/LibraryManager.cs | 15 ++++++++ .../Library/UserViewManager.cs | 15 ++++++++ .../Item/BaseItemRepository.cs | 42 ++++++++++++++++++++++ MediaBrowser.Controller/Library/ILibraryManager.cs | 9 +++++ .../Persistence/IItemRepository.cs | 9 +++++ 5 files changed, 90 insertions(+) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 27f6826685..eb8e310729 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1364,6 +1364,21 @@ namespace Emby.Server.Implementations.Library return _itemRepository.GetItemList(query); } + public IReadOnlyList GetLatestItemList(InternalItemsQuery query, IReadOnlyList parents, CollectionType collectionType) + { + SetTopParentIdsOrAncestors(query, parents); + + if (query.AncestorIds.Length == 0 && query.TopParentIds.Length == 0) + { + if (query.User is not null) + { + AddUserToQuery(query, query.User); + } + } + + return _itemRepository.GetLatestItemList(query, collectionType); + } + public IReadOnlyList GetNextUpSeriesKeys(InternalItemsQuery query, IReadOnlyCollection parents, DateTime dateCutoff) { SetTopParentIdsOrAncestors(query, parents); diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index 5a9315a92a..87214c273b 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -372,6 +372,21 @@ namespace Emby.Server.Implementations.Library MediaTypes = mediaTypes }; + if (request.GroupItems) + { + if (parents.OfType().All(i => i.CollectionType == CollectionType.tvshows)) + { + query.Limit = limit; + return _libraryManager.GetLatestItemList(query, parents, CollectionType.tvshows); + } + + if (parents.OfType().All(i => i.CollectionType == CollectionType.music)) + { + query.Limit = limit; + return _libraryManager.GetLatestItemList(query, parents, CollectionType.music); + } + } + return _libraryManager.GetItemList(query, parents); } } diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs index 4f69022441..7b5b6b94d7 100644 --- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs +++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs @@ -264,6 +264,48 @@ public sealed class BaseItemRepository return dbQuery.AsEnumerable().Where(e => e is not null).Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToArray(); } + /// + public IReadOnlyList GetLatestItemList(InternalItemsQuery filter, CollectionType collectionType) + { + ArgumentNullException.ThrowIfNull(filter); + PrepareFilterQuery(filter); + + // Early exit if collection type is not tvshows or music + if (collectionType != CollectionType.tvshows && collectionType != CollectionType.music) + { + return Array.Empty(); + } + + using var context = _dbProvider.CreateDbContext(); + + // Subquery to group by SeriesNames/Album and get the max Date Created for each group. + var subquery = PrepareItemQuery(context, filter); + subquery = TranslateQuery(subquery, context, filter); + var subqueryGrouped = subquery.GroupBy(g => collectionType == CollectionType.tvshows ? g.SeriesName : g.Album) + .Select(g => new + { + Key = g.Key, + MaxDateCreated = g.Max(a => a.DateCreated) + }) + .OrderByDescending(g => g.MaxDateCreated) + .Select(g => g); + + if (filter.Limit.HasValue) + { + subqueryGrouped = subqueryGrouped.Take(filter.Limit.Value); + } + + filter.Limit = null; + + var mainquery = PrepareItemQuery(context, filter); + mainquery = TranslateQuery(mainquery, context, filter); + mainquery = mainquery.Where(g => g.DateCreated >= subqueryGrouped.Min(s => s.MaxDateCreated)); + mainquery = ApplyGroupingFilter(mainquery, filter); + mainquery = ApplyQueryPaging(mainquery, filter); + + return mainquery.AsEnumerable().Where(e => e is not null).Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToArray(); + } + /// public IReadOnlyList GetNextUpSeriesKeys(InternalItemsQuery filter, DateTime dateCutoff) { diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index a3e3e4991c..df90f546cd 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -567,6 +567,15 @@ namespace MediaBrowser.Controller.Library /// List of items. IReadOnlyList GetItemList(InternalItemsQuery query, List parents); + /// + /// Gets the TVShow/Album items for Latest api. + /// + /// The query to use. + /// Items to use for query. + /// Collection Type. + /// List of items. + IReadOnlyList GetLatestItemList(InternalItemsQuery query, IReadOnlyList parents, CollectionType collectionType); + /// /// Gets the list of series presentation keys for next up. /// diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index f1ed4fe274..e185898bfb 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Threading; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; @@ -59,6 +60,14 @@ public interface IItemRepository /// List<BaseItem>. IReadOnlyList GetItemList(InternalItemsQuery filter); + /// + /// Gets the item list. Used mainly by the Latest api endpoint. + /// + /// The query. + /// Collection Type. + /// List<BaseItem>. + IReadOnlyList GetLatestItemList(InternalItemsQuery filter, CollectionType collectionType); + /// /// Gets the list of series presentation keys for next up. /// -- cgit v1.2.3 From b108a8cfc538795c3e5a120c785fffa512e9abfa Mon Sep 17 00:00:00 2001 From: Tobias Kloy Date: Mon, 10 Feb 2025 23:11:22 +0100 Subject: Fix IsInMixedFolder not being set for Extras in mixed subfolders --- Emby.Server.Implementations/Library/LibraryManager.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index eb8e310729..6a19a41cd6 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2721,6 +2721,8 @@ namespace Emby.Server.Implementations.Library if (current.IsDirectory && _namingOptions.AllExtrasTypesFolderNames.ContainsKey(current.Name)) { var filesInSubFolder = _fileSystem.GetFiles(current.FullName, null, false, false); + bool subFolderIsMixedFolder = filesInSubFolder.Count() > 1; + foreach (var file in filesInSubFolder) { if (!_extraResolver.TryGetExtraTypeForOwner(file.FullName, ownerVideoInfo, out var extraType)) @@ -2728,7 +2730,7 @@ namespace Emby.Server.Implementations.Library continue; } - var extra = GetExtra(file, extraType.Value); + var extra = GetExtra(file, extraType.Value, subFolderIsMixedFolder); if (extra is not null) { yield return extra; @@ -2737,7 +2739,7 @@ namespace Emby.Server.Implementations.Library } else if (!current.IsDirectory && _extraResolver.TryGetExtraTypeForOwner(current.FullName, ownerVideoInfo, out var extraType)) { - var extra = GetExtra(current, extraType.Value); + var extra = GetExtra(current, extraType.Value, false); if (extra is not null) { yield return extra; @@ -2745,7 +2747,7 @@ namespace Emby.Server.Implementations.Library } } - BaseItem? GetExtra(FileSystemMetadata file, ExtraType extraType) + BaseItem? GetExtra(FileSystemMetadata file, ExtraType extraType, bool isInMixedFolder) { var extra = ResolvePath(_fileSystem.GetFileInfo(file.FullName), directoryService, _extraResolver.GetResolversForExtraType(extraType)); if (extra is not Video && extra is not Audio) @@ -2768,6 +2770,7 @@ namespace Emby.Server.Implementations.Library extra.ParentId = Guid.Empty; extra.OwnerId = owner.Id; + extra.IsInMixedFolder = isInMixedFolder; return extra; } } -- cgit v1.2.3 From 7717d2e26171d9d932cba66a2813b7c0d02869e2 Mon Sep 17 00:00:00 2001 From: Tobias Kloy Date: Mon, 10 Feb 2025 23:33:25 +0100 Subject: Avoid multiple enumerations --- Emby.Server.Implementations/Library/LibraryManager.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 6a19a41cd6..c6b8501cbc 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2721,9 +2721,11 @@ namespace Emby.Server.Implementations.Library if (current.IsDirectory && _namingOptions.AllExtrasTypesFolderNames.ContainsKey(current.Name)) { var filesInSubFolder = _fileSystem.GetFiles(current.FullName, null, false, false); - bool subFolderIsMixedFolder = filesInSubFolder.Count() > 1; + var filesInSubFolderList = filesInSubFolder.ToList(); - foreach (var file in filesInSubFolder) + bool subFolderIsMixedFolder = filesInSubFolderList.Count > 1; + + foreach (var file in filesInSubFolderList) { if (!_extraResolver.TryGetExtraTypeForOwner(file.FullName, ownerVideoInfo, out var extraType)) { -- cgit v1.2.3 From 88ceaa39b0347c7b7626d38a48baa64923c66eeb Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Thu, 27 Mar 2025 18:16:54 -0600 Subject: Implement limiting caches (#13605) * Implement basic expiring cache for LibraryManager * Add expiring cache to more places * Rider why * Make DirectoryService caches static * Use FastConcurrentLru * Reduce default cache size * Simplify DirectoryService caches * Make directory service cache size at least 128 --- Directory.Packages.props | 3 ++- .../Emby.Server.Implementations.csproj | 1 + Emby.Server.Implementations/Library/LibraryManager.cs | 19 ++++++++++--------- .../Library/UserDataManager.cs | 14 ++++++-------- .../MediaBrowser.Controller.csproj | 1 + MediaBrowser.Controller/Providers/DirectoryService.cs | 17 ++++++++--------- .../Configuration/ServerConfiguration.cs | 5 +++++ .../DirectoryServiceTests.cs | 8 ++++---- 8 files changed, 37 insertions(+), 31 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Directory.Packages.props b/Directory.Packages.props index 89311142cd..f9e111b389 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -9,6 +9,7 @@ + @@ -87,4 +88,4 @@ - + \ No newline at end of file diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 8f89f35ac9..6722c20da6 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -22,6 +22,7 @@ + diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index eb8e310729..62f1f3d3aa 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2,7 +2,6 @@ #pragma warning disable CA5394 using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -11,6 +10,7 @@ using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using BitFaster.Caching.Lru; using Emby.Naming.Common; using Emby.Naming.TV; using Emby.Server.Implementations.Library.Resolvers; @@ -64,7 +64,6 @@ namespace Emby.Server.Implementations.Library private const string ShortcutFileExtension = ".mblink"; private readonly ILogger _logger; - private readonly ConcurrentDictionary _cache; private readonly ITaskManager _taskManager; private readonly IUserManager _userManager; private readonly IUserDataManager _userDataRepository; @@ -81,6 +80,7 @@ namespace Emby.Server.Implementations.Library private readonly IPeopleRepository _peopleRepository; private readonly ExtraResolver _extraResolver; private readonly IPathManager _pathManager; + private readonly FastConcurrentLru _cache; /// /// The _root folder sync lock. @@ -150,7 +150,9 @@ namespace Emby.Server.Implementations.Library _mediaEncoder = mediaEncoder; _itemRepository = itemRepository; _imageProcessor = imageProcessor; - _cache = new ConcurrentDictionary(); + + _cache = new FastConcurrentLru(_configurationManager.Configuration.CacheSize); + _namingOptions = namingOptions; _peopleRepository = peopleRepository; _pathManager = pathManager; @@ -158,7 +160,7 @@ namespace Emby.Server.Implementations.Library _configurationManager.ConfigurationUpdated += ConfigurationUpdated; - RecordConfigurationValues(configurationManager.Configuration); + RecordConfigurationValues(_configurationManager.Configuration); } /// @@ -306,7 +308,7 @@ namespace Emby.Server.Implementations.Library } } - _cache[item.Id] = item; + _cache.AddOrUpdate(item.Id, item); } public void DeleteItem(BaseItem item, DeleteOptions options) @@ -460,14 +462,13 @@ namespace Emby.Server.Implementations.Library item.SetParent(null); _itemRepository.DeleteItem(item.Id); + _cache.TryRemove(item.Id, out _); foreach (var child in children) { _itemRepository.DeleteItem(child.Id); _cache.TryRemove(child.Id, out _); } - _cache.TryRemove(item.Id, out _); - ReportItemRemoved(item, parent); } @@ -1255,7 +1256,7 @@ namespace Emby.Server.Implementations.Library throw new ArgumentException("Guid can't be empty", nameof(id)); } - if (_cache.TryGetValue(id, out BaseItem? item)) + if (_cache.TryGet(id, out var item)) { return item; } @@ -1272,7 +1273,7 @@ namespace Emby.Server.Implementations.Library /// public T? GetItemById(Guid id) - where T : BaseItem + where T : BaseItem { var item = GetItemById(id); if (item is T typedItem) diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index 8b88b904bb..be1d96bf0b 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -1,14 +1,13 @@ #pragma warning disable RS0030 // Do not use banned APIs using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; +using BitFaster.Caching.Lru; using Jellyfin.Database.Implementations; using Jellyfin.Database.Implementations.Entities; -using Jellyfin.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -26,11 +25,9 @@ namespace Emby.Server.Implementations.Library /// public class UserDataManager : IUserDataManager { - private readonly ConcurrentDictionary _userData = - new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - private readonly IServerConfigurationManager _config; private readonly IDbContextFactory _repository; + private readonly FastConcurrentLru _cache; /// /// Initializes a new instance of the class. @@ -43,6 +40,7 @@ namespace Emby.Server.Implementations.Library { _config = config; _repository = repository; + _cache = new FastConcurrentLru(Environment.ProcessorCount, _config.Configuration.CacheSize, StringComparer.OrdinalIgnoreCase); } /// @@ -81,7 +79,7 @@ namespace Emby.Server.Implementations.Library var userId = user.InternalId; var cacheKey = GetCacheKey(userId, item.Id); - _userData.AddOrUpdate(cacheKey, userData, (_, _) => userData); + _cache.AddOrUpdate(cacheKey, userData); UserDataSaved?.Invoke(this, new UserDataSaveEventArgs { @@ -182,7 +180,7 @@ namespace Emby.Server.Implementations.Library { var cacheKey = GetCacheKey(user.InternalId, itemId); - if (_userData.TryGetValue(cacheKey, out var data)) + if (_cache.TryGet(cacheKey, out var data)) { return data; } @@ -197,7 +195,7 @@ namespace Emby.Server.Implementations.Library }; } - return _userData.GetOrAdd(cacheKey, data); + return _cache.GetOrAdd(cacheKey, _ => data); } private UserItemData? GetUserDataInternal(Guid userId, Guid itemId, List keys) diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index ba4a2a59c4..d8aaf5ba01 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -18,6 +18,7 @@ + diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs index 474f09dc5e..4fca944771 100644 --- a/MediaBrowser.Controller/Providers/DirectoryService.cs +++ b/MediaBrowser.Controller/Providers/DirectoryService.cs @@ -1,22 +1,21 @@ #pragma warning disable CS1591 using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using BitFaster.Caching.Lru; using MediaBrowser.Model.IO; namespace MediaBrowser.Controller.Providers { public class DirectoryService : IDirectoryService { - private readonly IFileSystem _fileSystem; - - private readonly ConcurrentDictionary _cache = new(StringComparer.Ordinal); + // These caches are primarily used for scanning so no reason to have them be large. + private static readonly FastConcurrentLru _cache = new(Environment.ProcessorCount, Math.Max(128, Environment.ProcessorCount * 10), StringComparer.Ordinal); + private static readonly FastConcurrentLru _fileCache = new(Environment.ProcessorCount, Math.Max(128, Environment.ProcessorCount * 10), StringComparer.Ordinal); + private static readonly FastConcurrentLru> _filePathCache = new(Environment.ProcessorCount, Math.Max(128, Environment.ProcessorCount * 10), StringComparer.Ordinal); - private readonly ConcurrentDictionary _fileCache = new(StringComparer.Ordinal); - - private readonly ConcurrentDictionary> _filePathCache = new(StringComparer.Ordinal); + private readonly IFileSystem _fileSystem; public DirectoryService(IFileSystem fileSystem) { @@ -74,13 +73,13 @@ namespace MediaBrowser.Controller.Providers public FileSystemMetadata? GetFileSystemEntry(string path) { - if (!_fileCache.TryGetValue(path, out var result)) + if (!_fileCache.TryGet(path, out var result)) { var file = _fileSystem.GetFileSystemInfo(path); if (file?.Exists ?? false) { result = file; - _fileCache.TryAdd(path, result); + _fileCache.AddOrUpdate(path, result); } } diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 693bf90e71..f4e6c8e2c5 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -177,6 +177,11 @@ public class ServerConfiguration : BaseApplicationConfiguration /// The library update duration. public int LibraryUpdateDuration { get; set; } = 30; + /// + /// Gets or sets the maximum amount of items to cache. + /// + public int CacheSize { get; set; } = Environment.ProcessorCount * 100; + /// /// Gets or sets the image saving convention. /// diff --git a/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs b/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs index 07b53bf74c..9e7a8c8440 100644 --- a/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs +++ b/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs @@ -181,8 +181,8 @@ namespace Jellyfin.Controller.Tests fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == path))).Returns(newFileSystemMetadata); var secondResult = directoryService.GetFile(path); - Assert.Equal(cachedFileSystemMetadata, result); - Assert.Equal(cachedFileSystemMetadata, secondResult); + Assert.Equivalent(cachedFileSystemMetadata, result); + Assert.Equivalent(cachedFileSystemMetadata, secondResult); } [Fact] @@ -209,7 +209,7 @@ namespace Jellyfin.Controller.Tests fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(cachedPaths); var directoryService = new DirectoryService(fileSystemMock.Object); - var result = directoryService.GetFilePaths(path); + var result = directoryService.GetFilePaths(path, true); fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(newPaths); var secondResult = directoryService.GetFilePaths(path); @@ -241,7 +241,7 @@ namespace Jellyfin.Controller.Tests fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(cachedPaths); var directoryService = new DirectoryService(fileSystemMock.Object); - var result = directoryService.GetFilePaths(path); + var result = directoryService.GetFilePaths(path, true); fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(newPaths); var secondResult = directoryService.GetFilePaths(path, true); -- cgit v1.2.3 From f02190c394ad300c00dec4cc4f3b9d42ac6aaca2 Mon Sep 17 00:00:00 2001 From: Michael McElroy <44167199+mcmcelro@users.noreply.github.com> Date: Thu, 27 Mar 2025 20:18:19 -0400 Subject: Fix for Issue #12142: Fix ExtraRuleResolver filtering out top level folders (#12170) * Fix ExtraRuleResolver to stop filtering out libraries where the name of the base folder matches an 'videos extras' rule with an ExtraRuleType of DirectoryName Currently the ExtraRuleResolver code doesn't know anything about the root folder of the current library. As a result, when we're attempting to add items in a library where the root folder has a name with a match in Emby.Naming.Common.NamingOptions.VideoExtraRules, the entire library is being ignored as a Video Extras folder. Need to pass in the root folder of the current library to compare to the path of the current item being evaluated, and if we match the current item's folder to the root folder, then we ignore the ExtraRules with a type of DirectoryName and we continue to scan deeper in the library. Filters still apply to subfolders within the library itself. * Update CONTRIBUTORS.md * Update Emby.Naming/Video/ExtraRuleResolver.cs * Update ExtraTests.cs Add tests for this fix. Also add missing tests in TestKodiExtras, TestExpandedExtras, and TestSample, and expanded TestDirectories into TestDirectoriesAudioExtras and TestDirectoriesVideoExtras. There were no checks for the theme-music folder name previously. * Update ExtraTests.cs Removed unnecessary "using System" * In MediaBrowser.Model, upgrade System.Text.Json from 8.0.3 (vulnerable - high risk) to 8.0.4 * Update ExtraTests.cs Remove empty lines in usings * Revert "In MediaBrowser.Model, upgrade System.Text.Json from 8.0.3 (vulnerable - high risk) to 8.0.4" --- CONTRIBUTORS.md | 1 + Emby.Naming/Video/ExtraRuleResolver.cs | 7 ++- Emby.Naming/Video/VideoListResolver.cs | 5 +- Emby.Naming/Video/VideoResolver.cs | 15 +++--- .../Library/LibraryManager.cs | 2 +- .../Library/Resolvers/ExtraResolver.cs | 4 +- .../Library/Resolvers/Movies/MovieResolver.cs | 4 +- tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs | 62 +++++++++++++++++++++- 8 files changed, 84 insertions(+), 16 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index ae1a2fd71e..0dcce1ea18 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -269,3 +269,4 @@ - [Robert Lützner](https://github.com/rluetzner) - [Nathan McCrina](https://github.com/nfmccrina) - [Martin Reuter](https://github.com/reuterma24) + - [Michael McElroy](https://github.com/mcmcelro) diff --git a/Emby.Naming/Video/ExtraRuleResolver.cs b/Emby.Naming/Video/ExtraRuleResolver.cs index 3219472eff..5289065898 100644 --- a/Emby.Naming/Video/ExtraRuleResolver.cs +++ b/Emby.Naming/Video/ExtraRuleResolver.cs @@ -18,8 +18,9 @@ namespace Emby.Naming.Video /// /// Path to file. /// The naming options. + /// Top-level folder for the containing library. /// Returns object. - public static ExtraResult GetExtraInfo(string path, NamingOptions namingOptions) + public static ExtraResult GetExtraInfo(string path, NamingOptions namingOptions, string? libraryRoot = "") { var result = new ExtraResult(); @@ -69,7 +70,9 @@ namespace Emby.Naming.Video else if (rule.RuleType == ExtraRuleType.DirectoryName) { var directoryName = Path.GetFileName(Path.GetDirectoryName(pathSpan)); - if (directoryName.Equals(rule.Token, StringComparison.OrdinalIgnoreCase)) + string fullDirectory = Path.GetDirectoryName(pathSpan).ToString(); + if (directoryName.Equals(rule.Token, StringComparison.OrdinalIgnoreCase) + && !string.Equals(fullDirectory, libraryRoot, StringComparison.OrdinalIgnoreCase)) { result.ExtraType = rule.ExtraType; result.Rule = rule; diff --git a/Emby.Naming/Video/VideoListResolver.cs b/Emby.Naming/Video/VideoListResolver.cs index 12bc22a6ac..a3134f3f68 100644 --- a/Emby.Naming/Video/VideoListResolver.cs +++ b/Emby.Naming/Video/VideoListResolver.cs @@ -27,8 +27,9 @@ namespace Emby.Naming.Video /// The naming options. /// Indication we should consider multi-versions of content. /// Whether to parse the name or use the filename. + /// Top-level folder for the containing library. /// Returns enumerable of which groups files together when related. - public static IReadOnlyList Resolve(IReadOnlyList videoInfos, NamingOptions namingOptions, bool supportMultiVersion = true, bool parseName = true) + public static IReadOnlyList Resolve(IReadOnlyList videoInfos, NamingOptions namingOptions, bool supportMultiVersion = true, bool parseName = true, string? libraryRoot = "") { // Filter out all extras, otherwise they could cause stacks to not be resolved // See the unit test TestStackedWithTrailer @@ -65,7 +66,7 @@ namespace Emby.Naming.Video { var info = new VideoInfo(stack.Name) { - Files = stack.Files.Select(i => VideoResolver.Resolve(i, stack.IsDirectoryStack, namingOptions, parseName)) + Files = stack.Files.Select(i => VideoResolver.Resolve(i, stack.IsDirectoryStack, namingOptions, parseName, libraryRoot)) .OfType() .ToList() }; diff --git a/Emby.Naming/Video/VideoResolver.cs b/Emby.Naming/Video/VideoResolver.cs index db5bfdbf94..afbf6f8fae 100644 --- a/Emby.Naming/Video/VideoResolver.cs +++ b/Emby.Naming/Video/VideoResolver.cs @@ -17,10 +17,11 @@ namespace Emby.Naming.Video /// The path. /// The naming options. /// Whether to parse the name or use the filename. + /// Top-level folder for the containing library. /// VideoFileInfo. - public static VideoFileInfo? ResolveDirectory(string? path, NamingOptions namingOptions, bool parseName = true) + public static VideoFileInfo? ResolveDirectory(string? path, NamingOptions namingOptions, bool parseName = true, string? libraryRoot = "") { - return Resolve(path, true, namingOptions, parseName); + return Resolve(path, true, namingOptions, parseName, libraryRoot); } /// @@ -28,10 +29,11 @@ namespace Emby.Naming.Video /// /// The path. /// The naming options. + /// Top-level folder for the containing library. /// VideoFileInfo. - public static VideoFileInfo? ResolveFile(string? path, NamingOptions namingOptions) + public static VideoFileInfo? ResolveFile(string? path, NamingOptions namingOptions, string? libraryRoot = "") { - return Resolve(path, false, namingOptions); + return Resolve(path, false, namingOptions, libraryRoot: libraryRoot); } /// @@ -41,9 +43,10 @@ namespace Emby.Naming.Video /// if set to true [is folder]. /// The naming options. /// Whether or not the name should be parsed for info. + /// Top-level folder for the containing library. /// VideoFileInfo. /// path is null. - public static VideoFileInfo? Resolve(string? path, bool isDirectory, NamingOptions namingOptions, bool parseName = true) + public static VideoFileInfo? Resolve(string? path, bool isDirectory, NamingOptions namingOptions, bool parseName = true, string? libraryRoot = "") { if (string.IsNullOrEmpty(path)) { @@ -75,7 +78,7 @@ namespace Emby.Naming.Video var format3DResult = Format3DParser.Parse(path, namingOptions); - var extraResult = ExtraRuleResolver.GetExtraInfo(path, namingOptions); + var extraResult = ExtraRuleResolver.GetExtraInfo(path, namingOptions, libraryRoot); var name = Path.GetFileNameWithoutExtension(path); diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 62f1f3d3aa..c8026960df 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2709,7 +2709,7 @@ namespace Emby.Server.Implementations.Library public IEnumerable FindExtras(BaseItem owner, IReadOnlyList fileSystemChildren, IDirectoryService directoryService) { - var ownerVideoInfo = VideoResolver.Resolve(owner.Path, owner.IsFolder, _namingOptions); + var ownerVideoInfo = VideoResolver.Resolve(owner.Path, owner.IsFolder, _namingOptions, libraryRoot: owner.ContainingFolderPath); if (ownerVideoInfo is null) { yield break; diff --git a/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs b/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs index b4791b9456..b9f9f29723 100644 --- a/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs @@ -54,9 +54,9 @@ namespace Emby.Server.Implementations.Library.Resolvers _ => _videoResolvers }; - public bool TryGetExtraTypeForOwner(string path, VideoFileInfo ownerVideoFileInfo, [NotNullWhen(true)] out ExtraType? extraType) + public bool TryGetExtraTypeForOwner(string path, VideoFileInfo ownerVideoFileInfo, [NotNullWhen(true)] out ExtraType? extraType, string? libraryRoot = "") { - var extraResult = GetExtraInfo(path, _namingOptions); + var extraResult = GetExtraInfo(path, _namingOptions, libraryRoot); if (extraResult.ExtraType is null) { extraType = null; diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 4debe722b9..f1aeb1340a 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -270,11 +270,11 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies } var videoInfos = files - .Select(i => VideoResolver.Resolve(i.FullName, i.IsDirectory, NamingOptions, parseName)) + .Select(i => VideoResolver.Resolve(i.FullName, i.IsDirectory, NamingOptions, parseName, parent.ContainingFolderPath)) .Where(f => f is not null) .ToList(); - var resolverResult = VideoListResolver.Resolve(videoInfos, NamingOptions, supportMultiEditions, parseName); + var resolverResult = VideoListResolver.Resolve(videoInfos, NamingOptions, supportMultiEditions, parseName, parent.ContainingFolderPath); var result = new MultiItemResolverResult { diff --git a/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs b/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs index 2c33ab4929..51eb99f496 100644 --- a/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs +++ b/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs @@ -2,6 +2,7 @@ using Emby.Naming.Common; using Emby.Naming.Video; using MediaBrowser.Model.Entities; using Xunit; + using MediaType = Emby.Naming.Common.MediaType; namespace Jellyfin.Naming.Tests.Video @@ -20,6 +21,9 @@ namespace Jellyfin.Naming.Tests.Video { Test("trailer.mp4", ExtraType.Trailer); Test("300-trailer.mp4", ExtraType.Trailer); + Test("300.trailer.mp4", ExtraType.Trailer); + Test("300_trailer.mp4", ExtraType.Trailer); + Test("300 trailer.mp4", ExtraType.Trailer); Test("theme.mp3", ExtraType.ThemeSong); } @@ -43,6 +47,19 @@ namespace Jellyfin.Naming.Tests.Video Test("300-deletedscene.mp4", ExtraType.DeletedScene); Test("300-interview.mp4", ExtraType.Interview); Test("300-behindthescenes.mp4", ExtraType.BehindTheScenes); + Test("300-featurette.mp4", ExtraType.Featurette); + Test("300-short.mp4", ExtraType.Short); + Test("300-extra.mp4", ExtraType.Unknown); + Test("300-other.mp4", ExtraType.Unknown); + } + + [Theory] + [InlineData(ExtraType.ThemeSong, "theme-music")] + public void TestDirectoriesAudioExtras(ExtraType type, string dirName) + { + Test(dirName + "/300.mp3", type); + Test("300/" + dirName + "/something.mp3", type); + Test("/data/something/Movies/300/" + dirName + "/whoknows.mp3", type); } [Theory] @@ -52,11 +69,14 @@ namespace Jellyfin.Naming.Tests.Video [InlineData(ExtraType.Scene, "scenes")] [InlineData(ExtraType.Sample, "samples")] [InlineData(ExtraType.Short, "shorts")] + [InlineData(ExtraType.Trailer, "trailers")] [InlineData(ExtraType.Featurette, "featurettes")] [InlineData(ExtraType.Clip, "clips")] [InlineData(ExtraType.ThemeVideo, "backdrops")] + [InlineData(ExtraType.Unknown, "extra")] [InlineData(ExtraType.Unknown, "extras")] - public void TestDirectories(ExtraType type, string dirName) + [InlineData(ExtraType.Unknown, "other")] + public void TestDirectoriesVideoExtras(ExtraType type, string dirName) { Test(dirName + "/300.mp4", type); Test("300/" + dirName + "/something.mkv", type); @@ -75,10 +95,44 @@ namespace Jellyfin.Naming.Tests.Video Test("/data/something/Movies/" + dirName + "/" + dirName + ".mp4", null); } + [Theory] + [InlineData(ExtraType.ThemeSong, "theme-music")] + public void TestTopLevelDirectoriesWithAudioExtraNames(ExtraType typicalType, string dirName) + { + string libraryRoot = "/data/something/" + dirName; + TestWithLibraryRoot(libraryRoot + "/300.mp3", libraryRoot, null); + TestWithLibraryRoot(libraryRoot + "/300/" + dirName + "/something.mp3", libraryRoot, typicalType); + } + + [Theory] + [InlineData(ExtraType.Trailer, "trailers")] + [InlineData(ExtraType.ThemeVideo, "backdrops")] + [InlineData(ExtraType.BehindTheScenes, "behind the scenes")] + [InlineData(ExtraType.DeletedScene, "deleted scenes")] + [InlineData(ExtraType.Interview, "interviews")] + [InlineData(ExtraType.Scene, "scenes")] + [InlineData(ExtraType.Sample, "samples")] + [InlineData(ExtraType.Short, "shorts")] + [InlineData(ExtraType.Featurette, "featurettes")] + [InlineData(ExtraType.Unknown, "extras")] + [InlineData(ExtraType.Unknown, "extra")] + [InlineData(ExtraType.Unknown, "other")] + [InlineData(ExtraType.Clip, "clips")] + public void TestTopLevelDirectoriesWithVideoExtraNames(ExtraType typicalType, string dirName) + { + string libraryRoot = "/data/something/" + dirName; + TestWithLibraryRoot(libraryRoot + "/300.mp4", libraryRoot, null); + TestWithLibraryRoot(libraryRoot + "/300/" + dirName + "/something.mkv", libraryRoot, typicalType); + } + [Fact] public void TestSample() { + Test("sample.mp4", ExtraType.Sample); Test("300-sample.mp4", ExtraType.Sample); + Test("300.sample.mp4", ExtraType.Sample); + Test("300_sample.mp4", ExtraType.Sample); + Test("300 sample.mp4", ExtraType.Sample); } private void Test(string input, ExtraType? expectedType) @@ -88,6 +142,12 @@ namespace Jellyfin.Naming.Tests.Video Assert.Equal(expectedType, extraType); } + private void TestWithLibraryRoot(string input, string libraryRoot, ExtraType? expectedType) + { + var extraType = ExtraRuleResolver.GetExtraInfo(input, _videoOptions, libraryRoot).ExtraType; + Assert.Equal(expectedType, extraType); + } + [Fact] public void TestExtraInfo_InvalidRuleType() { -- cgit v1.2.3 From 3fc3b04daf929d1d3a9533fc410cb77885eb2e8a Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Mon, 31 Mar 2025 05:51:54 +0200 Subject: Rework parental ratings (#12615) --- .../Emby.Server.Implementations.csproj | 2 +- .../Library/SplashscreenPostScanTask.cs | 13 +- .../Localization/LocalizationManager.cs | 168 +- .../Localization/Ratings/0-prefer.csv | 11 - .../Localization/Ratings/0-prefer.json | 34 + .../Localization/Ratings/au.csv | 17 - .../Localization/Ratings/au.json | 69 + .../Localization/Ratings/be.csv | 11 - .../Localization/Ratings/be.json | 55 + .../Localization/Ratings/br.csv | 14 - .../Localization/Ratings/br.json | 55 + .../Localization/Ratings/ca.csv | 18 - .../Localization/Ratings/ca.json | 90 ++ .../Localization/Ratings/cl.json | 41 + .../Localization/Ratings/co.csv | 7 - .../Localization/Ratings/co.json | 55 + .../Localization/Ratings/de.csv | 17 - .../Localization/Ratings/de.json | 41 + .../Localization/Ratings/dk.csv | 7 - .../Localization/Ratings/dk.json | 48 + .../Localization/Ratings/es.csv | 25 - .../Localization/Ratings/es.json | 90 ++ .../Localization/Ratings/fi.csv | 10 - .../Localization/Ratings/fi.json | 41 + .../Localization/Ratings/fr.csv | 13 - .../Localization/Ratings/fr.json | 69 + .../Localization/Ratings/gb.csv | 23 - .../Localization/Ratings/gb.json | 97 ++ .../Localization/Ratings/ie.csv | 10 - .../Localization/Ratings/ie.json | 55 + .../Localization/Ratings/jp.csv | 11 - .../Localization/Ratings/jp.json | 62 + .../Localization/Ratings/kz.csv | 6 - .../Localization/Ratings/kz.json | 41 + .../Localization/Ratings/mx.csv | 6 - .../Localization/Ratings/mx.json | 41 + .../Localization/Ratings/nl.csv | 8 - .../Localization/Ratings/nl.json | 55 + .../Localization/Ratings/no.csv | 10 - .../Localization/Ratings/no.json | 69 + .../Localization/Ratings/nz.csv | 16 - .../Localization/Ratings/nz.json | 69 + .../Localization/Ratings/ro.csv | 6 - .../Localization/Ratings/ro.json | 48 + .../Localization/Ratings/ru.csv | 6 - .../Localization/Ratings/ru.json | 48 + .../Localization/Ratings/se.csv | 10 - .../Localization/Ratings/se.json | 55 + .../Localization/Ratings/sk.csv | 6 - .../Localization/Ratings/sk.json | 41 + .../Localization/Ratings/uk.csv | 22 - .../Localization/Ratings/uk.json | 97 ++ .../Localization/Ratings/us.csv | 52 - .../Localization/Ratings/us.json | 83 + .../Sorting/OfficialRatingComparer.cs | 71 +- Jellyfin.Api/Controllers/ItemsController.cs | 4 +- Jellyfin.Api/Controllers/LocalizationController.cs | 5 +- .../Extensions/ExpressionExtensions.cs | 70 + .../Item/BaseItemRepository.cs | 83 +- .../Users/UserManager.cs | 6 +- Jellyfin.Server/Migrations/MigrationRunner.cs | 2 +- .../Migrations/Routines/MigrateRatingLevels.cs | 88 +- .../Migrations/Routines/MigrateUserDb.cs | 3 +- MediaBrowser.Controller/Entities/BaseItem.cs | 52 +- .../Entities/InternalItemsQuery.cs | 19 +- MediaBrowser.Model/Dto/MetadataEditorInfo.cs | 70 +- MediaBrowser.Model/Entities/ParentalRating.cs | 55 +- MediaBrowser.Model/Entities/ParentalRatingEntry.cs | 22 + MediaBrowser.Model/Entities/ParentalRatingScore.cs | 32 + .../Entities/ParentalRatingSystem.cs | 28 + .../Globalization/ILocalizationManager.cs | 101 +- MediaBrowser.Model/Querying/ItemFields.cs | 1 + MediaBrowser.Model/Users/UserPolicy.cs | 2 + MediaBrowser.Providers/Manager/MetadataService.cs | 1 + .../Entities/BaseItemEntity.cs | 2 + .../Entities/User.cs | 9 +- ..._AddInheritedParentalRatingSubValue.Designer.cs | 1658 ++++++++++++++++++++ ...326065026_AddInheritedParentalRatingSubValue.cs | 48 + .../Migrations/JellyfinDbModelSnapshot.cs | 222 ++- .../Localization/LocalizationManagerTests.cs | 66 +- 80 files changed, 3992 insertions(+), 802 deletions(-) delete mode 100644 Emby.Server.Implementations/Localization/Ratings/0-prefer.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/0-prefer.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/au.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/au.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/be.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/be.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/br.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/br.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/ca.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/ca.json create mode 100644 Emby.Server.Implementations/Localization/Ratings/cl.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/co.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/co.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/de.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/de.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/dk.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/dk.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/es.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/es.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/fi.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/fi.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/fr.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/fr.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/gb.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/gb.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/ie.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/ie.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/jp.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/jp.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/kz.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/kz.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/mx.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/mx.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/nl.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/nl.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/no.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/no.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/nz.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/nz.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/ro.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/ro.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/ru.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/ru.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/se.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/se.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/sk.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/sk.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/uk.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/uk.json delete mode 100644 Emby.Server.Implementations/Localization/Ratings/us.csv create mode 100644 Emby.Server.Implementations/Localization/Ratings/us.json create mode 100644 Jellyfin.Server.Implementations/Extensions/ExpressionExtensions.cs create mode 100644 MediaBrowser.Model/Entities/ParentalRatingEntry.cs create mode 100644 MediaBrowser.Model/Entities/ParentalRatingScore.cs create mode 100644 MediaBrowser.Model/Entities/ParentalRatingSystem.cs create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250326065026_AddInheritedParentalRatingSubValue.Designer.cs create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250326065026_AddInheritedParentalRatingSubValue.cs (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 6722c20da6..d99923b4fc 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -68,6 +68,6 @@ - + diff --git a/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs b/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs index 0c9edd8398..71ce3b6012 100644 --- a/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs +++ b/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs @@ -11,7 +11,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Querying; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Library; @@ -78,15 +77,15 @@ public class SplashscreenPostScanTask : ILibraryPostScanTask CollapseBoxSetItems = false, Recursive = true, DtoOptions = new DtoOptions(false), - ImageTypes = new[] { imageType }, + ImageTypes = [imageType], Limit = 30, // TODO max parental rating configurable - MaxParentalRating = 10, - OrderBy = new[] - { + MaxParentalRating = new(10, null), + OrderBy = + [ (ItemSortBy.Random, SortOrder.Ascending) - }, - IncludeItemTypes = new[] { BaseItemKind.Movie, BaseItemKind.Series } + ], + IncludeItemTypes = [BaseItemKind.Movie, BaseItemKind.Series] }); } } diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 754a01329b..9598f9e6c7 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Linq; using System.Reflection; @@ -26,20 +25,18 @@ namespace Emby.Server.Implementations.Localization private const string CulturesPath = "Emby.Server.Implementations.Localization.iso6392.txt"; private const string CountriesPath = "Emby.Server.Implementations.Localization.countries.json"; private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly; - private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated", "nr" }; + private static readonly string[] _unratedValues = ["n/a", "unrated", "not rated", "nr"]; private readonly IServerConfigurationManager _configurationManager; private readonly ILogger _logger; - private readonly Dictionary> _allParentalRatings = - new Dictionary>(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary> _allParentalRatings = new(StringComparer.OrdinalIgnoreCase); - private readonly ConcurrentDictionary> _dictionaries = - new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase); + private readonly ConcurrentDictionary> _dictionaries = new(StringComparer.OrdinalIgnoreCase); private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; - private List _cultures = new List(); + private List _cultures = []; /// /// Initializes a new instance of the class. @@ -68,35 +65,26 @@ namespace Emby.Server.Implementations.Localization continue; } - string countryCode = resource.Substring(RatingsPath.Length, 2); - var dict = new Dictionary(StringComparer.OrdinalIgnoreCase); - - var stream = _assembly.GetManifestResourceStream(resource); - await using (stream!.ConfigureAwait(false)) // shouldn't be null here, we just got the resource path from Assembly.GetManifestResourceNames() + using var stream = _assembly.GetManifestResourceStream(resource); + if (stream is not null) { - using var reader = new StreamReader(stream!); - await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false)) + var ratingSystem = await JsonSerializer.DeserializeAsync(stream, _jsonOptions).ConfigureAwait(false) + ?? throw new InvalidOperationException($"Invalid resource path: '{CountriesPath}'"); + + var dict = new Dictionary(); + if (ratingSystem.Ratings is not null) { - if (string.IsNullOrWhiteSpace(line)) + foreach (var ratingEntry in ratingSystem.Ratings) { - continue; + foreach (var ratingString in ratingEntry.RatingStrings) + { + dict[ratingString] = ratingEntry.RatingScore; + } } - string[] parts = line.Split(','); - if (parts.Length == 2 - && int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) - { - var name = parts[0]; - dict.Add(name, new ParentalRating(name, value)); - } - else - { - _logger.LogWarning("Malformed line in ratings file for country {CountryCode}", countryCode); - } + _allParentalRatings[ratingSystem.CountryCode] = dict; } } - - _allParentalRatings[countryCode] = dict; } await LoadCultures().ConfigureAwait(false); @@ -111,22 +99,29 @@ namespace Emby.Server.Implementations.Localization private async Task LoadCultures() { - List list = new List(); + List list = []; - await using var stream = _assembly.GetManifestResourceStream(CulturesPath) - ?? throw new InvalidOperationException($"Invalid resource path: '{CulturesPath}'"); - using var reader = new StreamReader(stream); - await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false)) + using var stream = _assembly.GetManifestResourceStream(CulturesPath); + if (stream is null) + { + throw new InvalidOperationException($"Invalid resource path: '{CulturesPath}'"); + } + else { - if (string.IsNullOrWhiteSpace(line)) + using var reader = new StreamReader(stream); + await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false)) { - continue; - } + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } - var parts = line.Split('|'); + var parts = line.Split('|'); + if (parts.Length != 5) + { + throw new InvalidDataException($"Invalid culture data found at: '{line}'"); + } - if (parts.Length == 5) - { string name = parts[3]; if (string.IsNullOrWhiteSpace(name)) { @@ -139,21 +134,21 @@ namespace Emby.Server.Implementations.Localization continue; } - string[] threeletterNames; + string[] threeLetterNames; if (string.IsNullOrWhiteSpace(parts[1])) { - threeletterNames = new[] { parts[0] }; + threeLetterNames = [parts[0]]; } else { - threeletterNames = new[] { parts[0], parts[1] }; + threeLetterNames = [parts[0], parts[1]]; } - list.Add(new CultureDto(name, name, twoCharName, threeletterNames)); + list.Add(new CultureDto(name, name, twoCharName, threeLetterNames)); } - } - _cultures = list; + _cultures = list; + } } /// @@ -176,82 +171,80 @@ namespace Emby.Server.Implementations.Localization } /// - public IEnumerable GetCountries() + public IReadOnlyList GetCountries() { - using StreamReader reader = new StreamReader( - _assembly.GetManifestResourceStream(CountriesPath) ?? throw new InvalidOperationException($"Invalid resource path: '{CountriesPath}'")); - return JsonSerializer.Deserialize>(reader.ReadToEnd(), _jsonOptions) - ?? throw new InvalidOperationException($"Resource contains invalid data: '{CountriesPath}'"); + using var stream = _assembly.GetManifestResourceStream(CountriesPath) ?? throw new InvalidOperationException($"Invalid resource path: '{CountriesPath}'"); + + return JsonSerializer.Deserialize>(stream, _jsonOptions) ?? []; } /// - public IEnumerable GetParentalRatings() + public IReadOnlyList GetParentalRatings() { // Use server default language for ratings // Fall back to empty list if there are no parental ratings for that language - var ratings = GetParentalRatingsDictionary()?.Values.ToList() - ?? new List(); + var ratings = GetParentalRatingsDictionary()?.Select(x => new ParentalRating(x.Key, x.Value)).ToList() ?? []; // Add common ratings to ensure them being available for selection // Based on the US rating system due to it being the main source of rating in the metadata providers // Unrated - if (!ratings.Any(x => x.Value is null)) + if (!ratings.Any(x => x is null)) { - ratings.Add(new ParentalRating("Unrated", null)); + ratings.Add(new("Unrated", null)); } // Minimum rating possible - if (ratings.All(x => x.Value != 0)) + if (ratings.All(x => x.RatingScore?.Score != 0)) { - ratings.Add(new ParentalRating("Approved", 0)); + ratings.Add(new("Approved", new(0, null))); } // Matches PG (this has different age restrictions depending on country) - if (ratings.All(x => x.Value != 10)) + if (ratings.All(x => x.RatingScore?.Score != 10)) { - ratings.Add(new ParentalRating("10", 10)); + ratings.Add(new("10", new(10, null))); } // Matches PG-13 - if (ratings.All(x => x.Value != 13)) + if (ratings.All(x => x.RatingScore?.Score != 13)) { - ratings.Add(new ParentalRating("13", 13)); + ratings.Add(new("13", new(13, null))); } // Matches TV-14 - if (ratings.All(x => x.Value != 14)) + if (ratings.All(x => x.RatingScore?.Score != 14)) { - ratings.Add(new ParentalRating("14", 14)); + ratings.Add(new("14", new(14, null))); } // Catchall if max rating of country is less than 21 // Using 21 instead of 18 to be sure to allow access to all rated content except adult and banned - if (!ratings.Any(x => x.Value >= 21)) + if (!ratings.Any(x => x.RatingScore?.Score >= 21)) { - ratings.Add(new ParentalRating("21", 21)); + ratings.Add(new ParentalRating("21", new(21, null))); } // A lot of countries don't explicitly have a separate rating for adult content - if (ratings.All(x => x.Value != 1000)) + if (ratings.All(x => x.RatingScore?.Score != 1000)) { - ratings.Add(new ParentalRating("XXX", 1000)); + ratings.Add(new ParentalRating("XXX", new(1000, null))); } // A lot of countries don't explicitly have a separate rating for banned content - if (ratings.All(x => x.Value != 1001)) + if (ratings.All(x => x.RatingScore?.Score != 1001)) { - ratings.Add(new ParentalRating("Banned", 1001)); + ratings.Add(new ParentalRating("Banned", new(1001, null))); } - return ratings.OrderBy(r => r.Value); + return [.. ratings.OrderBy(r => r.RatingScore?.Score).ThenBy(r => r.RatingScore?.SubScore)]; } /// /// Gets the parental ratings dictionary. /// /// The optional two letter ISO language string. - /// . - private Dictionary? GetParentalRatingsDictionary(string? countryCode = null) + /// . + private Dictionary? GetParentalRatingsDictionary(string? countryCode = null) { // Fallback to server default if no country code is specified. if (string.IsNullOrEmpty(countryCode)) @@ -268,7 +261,7 @@ namespace Emby.Server.Implementations.Localization } /// - public int? GetRatingLevel(string rating, string? countryCode = null) + public ParentalRatingScore? GetRatingScore(string rating, string? countryCode = null) { ArgumentException.ThrowIfNullOrEmpty(rating); @@ -278,11 +271,11 @@ namespace Emby.Server.Implementations.Localization return null; } - // Convert integers directly + // Convert ints directly // This may override some of the locale specific age ratings (but those always map to the same age) if (int.TryParse(rating, out var ratingAge)) { - return ratingAge; + return new(ratingAge, null); } // Fairly common for some users to have "Rated R" in their rating field @@ -295,9 +288,9 @@ namespace Emby.Server.Implementations.Localization if (!string.IsNullOrEmpty(countryCode)) { var ratingsDictionary = GetParentalRatingsDictionary(countryCode); - if (ratingsDictionary is not null && ratingsDictionary.TryGetValue(rating, out ParentalRating? value)) + if (ratingsDictionary is not null && ratingsDictionary.TryGetValue(rating, out ParentalRatingScore? value)) { - return value.Value; + return value; } } else @@ -305,9 +298,9 @@ namespace Emby.Server.Implementations.Localization // Fall back to server default language for ratings check // If it has no ratings, use the US ratings var ratingsDictionary = GetParentalRatingsDictionary() ?? GetParentalRatingsDictionary("us"); - if (ratingsDictionary is not null && ratingsDictionary.TryGetValue(rating, out ParentalRating? value)) + if (ratingsDictionary is not null && ratingsDictionary.TryGetValue(rating, out ParentalRatingScore? value)) { - return value.Value; + return value; } } @@ -316,7 +309,7 @@ namespace Emby.Server.Implementations.Localization { if (dictionary.TryGetValue(rating, out var value)) { - return value.Value; + return value; } } @@ -326,7 +319,7 @@ namespace Emby.Server.Implementations.Localization var ratingLevelRightPart = rating.AsSpan().RightPart(':'); if (ratingLevelRightPart.Length != 0) { - return GetRatingLevel(ratingLevelRightPart.ToString()); + return GetRatingScore(ratingLevelRightPart.ToString()); } } @@ -342,7 +335,7 @@ namespace Emby.Server.Implementations.Localization if (ratingLevelRightPart.Length != 0) { // Check rating system of culture - return GetRatingLevel(ratingLevelRightPart.ToString(), culture?.TwoLetterISOLanguageName); + return GetRatingScore(ratingLevelRightPart.ToString(), culture?.TwoLetterISOLanguageName); } } @@ -406,7 +399,7 @@ namespace Emby.Server.Implementations.Localization private async Task CopyInto(IDictionary dictionary, string resourcePath) { - await using var stream = _assembly.GetManifestResourceStream(resourcePath); + using var stream = _assembly.GetManifestResourceStream(resourcePath); // If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain if (stream is null) { @@ -414,12 +407,7 @@ namespace Emby.Server.Implementations.Localization return; } - var dict = await JsonSerializer.DeserializeAsync>(stream, _jsonOptions).ConfigureAwait(false); - if (dict is null) - { - throw new InvalidOperationException($"Resource contains invalid data: '{stream}'"); - } - + var dict = await JsonSerializer.DeserializeAsync>(stream, _jsonOptions).ConfigureAwait(false) ?? throw new InvalidOperationException($"Resource contains invalid data: '{stream}'"); foreach (var key in dict.Keys) { dictionary[key] = dict[key]; diff --git a/Emby.Server.Implementations/Localization/Ratings/0-prefer.csv b/Emby.Server.Implementations/Localization/Ratings/0-prefer.csv deleted file mode 100644 index 36886ba760..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/0-prefer.csv +++ /dev/null @@ -1,11 +0,0 @@ -E,0 -EC,0 -T,7 -M,18 -AO,18 -UR,18 -RP,18 -X,1000 -XX,1000 -XXX,1000 -XXXX,1000 diff --git a/Emby.Server.Implementations/Localization/Ratings/0-prefer.json b/Emby.Server.Implementations/Localization/Ratings/0-prefer.json new file mode 100644 index 0000000000..b390151611 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/0-prefer.json @@ -0,0 +1,34 @@ +{ + "countryCode": "0-prefer", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["E", "EC"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["T"], + "ratingScore": { + "score": 7, + "subScore": null + } + }, + { + "ratingStrings": ["M", "AO", "UR", "RP"], + "ratingScore": { + "score": 18, + "subScore": null + } + }, + { + "ratingStrings": ["X", "XX", "XXX", "XXXX"], + "ratingScore": { + "score": 1000, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/au.csv b/Emby.Server.Implementations/Localization/Ratings/au.csv deleted file mode 100644 index 6e12759a46..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/au.csv +++ /dev/null @@ -1,17 +0,0 @@ -Exempt,0 -G,0 -7+,7 -PG,15 -M,15 -MA,15 -MA15+,15 -MA 15+,15 -16+,16 -R,18 -R18+,18 -R 18+,18 -18+,18 -X18+,1000 -X 18+,1000 -X,1000 -RC,1001 diff --git a/Emby.Server.Implementations/Localization/Ratings/au.json b/Emby.Server.Implementations/Localization/Ratings/au.json new file mode 100644 index 0000000000..a563df899d --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/au.json @@ -0,0 +1,69 @@ +{ + "countryCode": "au", + "supportsSubScores": true, + "ratings": [ + { + "ratingStrings": ["Exempt", "G"], + "ratingScore": { + "score": 0, + "subScore": 0 + } + }, + { + "ratingStrings": ["7+"], + "ratingScore": { + "score": 7, + "subScore": 0 + } + }, + { + "ratingStrings": ["PG"], + "ratingScore": { + "score": 15, + "subScore": 1 + } + }, + { + "ratingStrings": ["M"], + "ratingScore": { + "score": 15, + "subScore": 2 + } + }, + { + "ratingStrings": ["MA", "MA 15+", "MA15+"], + "ratingScore": { + "score": 15, + "subScore": 3 + } + }, + { + "ratingStrings": ["16+"], + "ratingScore": { + "score": 16, + "subScore": 0 + } + }, + { + "ratingStrings": ["18+", "R", "R18+", "R 18+"], + "ratingScore": { + "score": 18, + "subScore": 1 + } + }, + { + "ratingStrings": ["X", "X18", "X 18"], + "ratingScore": { + "score": 1000, + "subScore": 0 + } + }, + { + "ratingStrings": ["RC"], + "ratingScore": { + "score": 1001, + "subScore": 0 + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/be.csv b/Emby.Server.Implementations/Localization/Ratings/be.csv deleted file mode 100644 index d171a71328..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/be.csv +++ /dev/null @@ -1,11 +0,0 @@ -AL,0 -KT,0 -TOUS,0 -MG6,6 -6,6 -9,9 -KNT,12 -12,12 -14,14 -16,16 -18,18 diff --git a/Emby.Server.Implementations/Localization/Ratings/be.json b/Emby.Server.Implementations/Localization/Ratings/be.json new file mode 100644 index 0000000000..18ea2c2605 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/be.json @@ -0,0 +1,55 @@ +{ + "countryCode": "be", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["AL", "KT", "TOUS"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["6", "MG6"], + "ratingScore": { + "score": 6, + "subScore": null + } + }, + { + "ratingStrings": ["9"], + "ratingScore": { + "score": 9, + "subScore": null + } + }, + { + "ratingStrings": ["12", "KNT"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["14"], + "ratingScore": { + "score": 14, + "subScore": null + } + }, + { + "ratingStrings": ["16"], + "ratingScore": { + "score": 16, + "subScore": null + } + }, + { + "ratingStrings": ["18"], + "ratingScore": { + "score": 18, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/br.csv b/Emby.Server.Implementations/Localization/Ratings/br.csv deleted file mode 100644 index f6053c88c7..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/br.csv +++ /dev/null @@ -1,14 +0,0 @@ -Livre,0 -L,0 -AL,0 -ER,10 -10,10 -A10,10 -12,12 -A12,12 -14,14 -A14,14 -16,16 -A16,16 -18,18 -A18,18 diff --git a/Emby.Server.Implementations/Localization/Ratings/br.json b/Emby.Server.Implementations/Localization/Ratings/br.json new file mode 100644 index 0000000000..f455b6643f --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/br.json @@ -0,0 +1,55 @@ +{ + "countryCode": "br", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["L", "AL", "Livre"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["9"], + "ratingScore": { + "score": 9, + "subScore": null + } + }, + { + "ratingStrings": ["10", "A10", "ER"], + "ratingScore": { + "score": 10, + "subScore": null + } + }, + { + "ratingStrings": ["12", "A12"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["14", "A14"], + "ratingScore": { + "score": 14, + "subScore": null + } + }, + { + "ratingStrings": ["16", "A16"], + "ratingScore": { + "score": 16, + "subScore": null + } + }, + { + "ratingStrings": ["18", "A18"], + "ratingScore": { + "score": 18, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/ca.csv b/Emby.Server.Implementations/Localization/Ratings/ca.csv deleted file mode 100644 index 41dbda1349..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/ca.csv +++ /dev/null @@ -1,18 +0,0 @@ -E,0 -G,0 -TV-Y,0 -TV-G,0 -TV-Y7,7 -TV-Y7-FV,7 -PG,9 -TV-PG,9 -TV-14,14 -14A,14 -16+,16 -NC-17,17 -R,18 -TV-MA,18 -18A,18 -18+,18 -A,1000 -Prohibited,1001 diff --git a/Emby.Server.Implementations/Localization/Ratings/ca.json b/Emby.Server.Implementations/Localization/Ratings/ca.json new file mode 100644 index 0000000000..fa43a8f2b7 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/ca.json @@ -0,0 +1,90 @@ +{ + "countryCode": "ca", + "supportsSubScores": true, + "ratings": [ + { + "ratingStrings": ["E", "G", "TV-Y", "TV-G"], + "ratingScore": { + "score": 0, + "subScore": 0 + } + }, + { + "ratingStrings": ["TV-Y7"], + "ratingScore": { + "score": 7, + "subScore": 0 + } + }, + { + "ratingStrings": ["TV-Y7-FV"], + "ratingScore": { + "score": 7, + "subScore": 1 + } + }, + { + "ratingStrings": ["PG", "TV-PG"], + "ratingScore": { + "score": 9, + "subScore": 0 + } + }, + { + "ratingStrings": ["14A"], + "ratingScore": { + "score": 14, + "subScore": 0 + } + }, + { + "ratingStrings": ["TV-14"], + "ratingScore": { + "score": 14, + "subScore": 1 + } + }, + { + "ratingStrings": ["16+"], + "ratingScore": { + "score": 16, + "subScore": 0 + } + }, + { + "ratingStrings": ["NC-17"], + "ratingScore": { + "score": 17, + "subScore": 0 + } + }, + { + "ratingStrings": ["18A"], + "ratingScore": { + "score": 18, + "subScore": 0 + } + }, + { + "ratingStrings": ["18+", "TV-MA", "R"], + "ratingScore": { + "score": 18, + "subScore": 1 + } + }, + { + "ratingStrings": ["A"], + "ratingScore": { + "score": 1000, + "subScore": 0 + } + }, + { + "ratingStrings": ["Prohibited"], + "ratingScore": { + "score": 1001, + "subScore": 0 + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/cl.json b/Emby.Server.Implementations/Localization/Ratings/cl.json new file mode 100644 index 0000000000..0866194715 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/cl.json @@ -0,0 +1,41 @@ +{ + "countryCode": "cl", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["TE"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["6"], + "ratingScore": { + "score": 6, + "subScore": null + } + }, + { + "ratingStrings": ["TE+7"], + "ratingScore": { + "score": 7, + "subScore": null + } + }, + { + "ratingStrings": ["14"], + "ratingScore": { + "score": 14, + "subScore": null + } + }, + { + "ratingStrings": ["18", "18V", "18S"], + "ratingScore": { + "score": 18, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/co.csv b/Emby.Server.Implementations/Localization/Ratings/co.csv deleted file mode 100644 index e1e96c5909..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/co.csv +++ /dev/null @@ -1,7 +0,0 @@ -T,0 -7,7 -12,12 -15,15 -18,18 -X,1000 -Prohibited,1001 diff --git a/Emby.Server.Implementations/Localization/Ratings/co.json b/Emby.Server.Implementations/Localization/Ratings/co.json new file mode 100644 index 0000000000..4eff6dcc53 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/co.json @@ -0,0 +1,55 @@ +{ + "countryCode": "co", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["T"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["7"], + "ratingScore": { + "score": 7, + "subScore": null + } + }, + { + "ratingStrings": ["12"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["15"], + "ratingScore": { + "score": 15, + "subScore": null + } + }, + { + "ratingStrings": ["18"], + "ratingScore": { + "score": 18, + "subScore": null + } + }, + { + "ratingStrings": ["X"], + "ratingScore": { + "score": 1000, + "subScore": null + } + }, + { + "ratingStrings": ["Prohibited"], + "ratingScore": { + "score": 1001, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/de.csv b/Emby.Server.Implementations/Localization/Ratings/de.csv deleted file mode 100644 index f6181575e2..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/de.csv +++ /dev/null @@ -1,17 +0,0 @@ -Educational,0 -Infoprogramm,0 -FSK-0,0 -FSK 0,0 -0,0 -FSK-6,6 -FSK 6,6 -6,6 -FSK-12,12 -FSK 12,12 -12,12 -FSK-16,16 -FSK 16,16 -16,16 -FSK-18,18 -FSK 18,18 -18,18 diff --git a/Emby.Server.Implementations/Localization/Ratings/de.json b/Emby.Server.Implementations/Localization/Ratings/de.json new file mode 100644 index 0000000000..30c34b230c --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/de.json @@ -0,0 +1,41 @@ +{ + "countryCode": "de", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["0", "FSK 0", "FSK-0", "Educational", "Infoprogramm"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["6", "FSK 6", "FSK-6"], + "ratingScore": { + "score": 6, + "subScore": null + } + }, + { + "ratingStrings": ["12", "FSK 12", "FSK-12"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["16", "FSK 16", "FSK-16"], + "ratingScore": { + "score": 16, + "subScore": null + } + }, + { + "ratingStrings": ["18", "FSK 18", "FSK-18"], + "ratingScore": { + "score": 18, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/dk.csv b/Emby.Server.Implementations/Localization/Ratings/dk.csv deleted file mode 100644 index 4ef63b2eac..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/dk.csv +++ /dev/null @@ -1,7 +0,0 @@ -F,0 -A,0 -7,7 -11,11 -12,12 -15,15 -16,16 diff --git a/Emby.Server.Implementations/Localization/Ratings/dk.json b/Emby.Server.Implementations/Localization/Ratings/dk.json new file mode 100644 index 0000000000..9fcd6d44fd --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/dk.json @@ -0,0 +1,48 @@ +{ + "countryCode": "dk", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["F", "A"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["7"], + "ratingScore": { + "score": 7, + "subScore": null + } + }, + { + "ratingStrings": ["11"], + "ratingScore": { + "score": 11, + "subScore": null + } + }, + { + "ratingStrings": ["12"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["15"], + "ratingScore": { + "score": 15, + "subScore": null + } + }, + { + "ratingStrings": ["16"], + "ratingScore": { + "score": 16, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/es.csv b/Emby.Server.Implementations/Localization/Ratings/es.csv deleted file mode 100644 index ee58660900..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/es.csv +++ /dev/null @@ -1,25 +0,0 @@ -A,0 -A/fig,0 -A/i,0 -A/i/fig,0 -APTA,0 -ERI,0 -TP,0 -0+,0 -6+,6 -7/fig,7 -7/i,7 -7/i/fig,7 -7,7 -9+,9 -10,10 -12,12 -12/fig,12 -13,13 -14,14 -16,16 -16/fig,16 -18,18 -18/fig,18 -X,1000 -Banned,1001 diff --git a/Emby.Server.Implementations/Localization/Ratings/es.json b/Emby.Server.Implementations/Localization/Ratings/es.json new file mode 100644 index 0000000000..c19629939d --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/es.json @@ -0,0 +1,90 @@ +{ + "countryCode": "es", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["0+", "A", "A/i", "A/fig", "A/i/fig", "APTA", "ERI", "TP"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["6+"], + "ratingScore": { + "score": 6, + "subScore": null + } + }, + { + "ratingStrings": ["7", "7/i", "7/fig", "7/i/fig"], + "ratingScore": { + "score": 11, + "subScore": null + } + }, + { + "ratingStrings": ["9+"], + "ratingScore": { + "score": 9, + "subScore": null + } + }, + { + "ratingStrings": ["10"], + "ratingScore": { + "score": 10, + "subScore": null + } + }, + { + "ratingStrings": ["12", "12/fig"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["13"], + "ratingScore": { + "score": 13, + "subScore": null + } + }, + { + "ratingStrings": ["14"], + "ratingScore": { + "score": 14, + "subScore": null + } + }, + { + "ratingStrings": ["16", "16/fig"], + "ratingScore": { + "score": 16, + "subScore": null + } + }, + { + "ratingStrings": ["18", "18/fig"], + "ratingScore": { + "score": 18, + "subScore": null + } + }, + { + "ratingStrings": ["X"], + "ratingScore": { + "score": 1000, + "subScore": null + } + }, + { + "ratingStrings": ["Banned"], + "ratingScore": { + "score": 1001, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/fi.csv b/Emby.Server.Implementations/Localization/Ratings/fi.csv deleted file mode 100644 index 7ff92f259b..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/fi.csv +++ /dev/null @@ -1,10 +0,0 @@ -S,0 -T,0 -K7,7 -7,7 -K12,12 -12,12 -K16,16 -16,16 -K18,18 -18,18 diff --git a/Emby.Server.Implementations/Localization/Ratings/fi.json b/Emby.Server.Implementations/Localization/Ratings/fi.json new file mode 100644 index 0000000000..3152317b59 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/fi.json @@ -0,0 +1,41 @@ +{ + "countryCode": "fi", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["S", "T"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["7", "K7"], + "ratingScore": { + "score": 7, + "subScore": null + } + }, + { + "ratingStrings": ["12", "K12"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["16", "K16"], + "ratingScore": { + "score": 16, + "subScore": null + } + }, + { + "ratingStrings": ["18", "K18"], + "ratingScore": { + "score": 18, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/fr.csv b/Emby.Server.Implementations/Localization/Ratings/fr.csv deleted file mode 100644 index 139ea376b7..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/fr.csv +++ /dev/null @@ -1,13 +0,0 @@ -Public Averti,0 -Tous Publics,0 -TP,0 -U,0 -0+,0 -6+,6 -9+,9 -10,10 -12,12 -14+,14 -16,16 -18,18 -X,1000 diff --git a/Emby.Server.Implementations/Localization/Ratings/fr.json b/Emby.Server.Implementations/Localization/Ratings/fr.json new file mode 100644 index 0000000000..e8bafd6b87 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/fr.json @@ -0,0 +1,69 @@ +{ + "countryCode": "fr", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["0+", "Public Averti", "Tous Publics", "TP", "U"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["6+"], + "ratingScore": { + "score": 6, + "subScore": null + } + }, + { + "ratingStrings": ["9+"], + "ratingScore": { + "score": 9, + "subScore": null + } + }, + { + "ratingStrings": ["10"], + "ratingScore": { + "score": 10, + "subScore": null + } + }, + { + "ratingStrings": ["12"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["14+"], + "ratingScore": { + "score": 14, + "subScore": null + } + }, + { + "ratingStrings": ["16"], + "ratingScore": { + "score": 16, + "subScore": null + } + }, + { + "ratingStrings": ["18"], + "ratingScore": { + "score": 18, + "subScore": null + } + }, + { + "ratingStrings": ["X"], + "ratingScore": { + "score": 1000, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/gb.csv b/Emby.Server.Implementations/Localization/Ratings/gb.csv deleted file mode 100644 index 858b9a32dd..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/gb.csv +++ /dev/null @@ -1,23 +0,0 @@ -All,0 -E,0 -G,0 -U,0 -0+,0 -6+,6 -7+,7 -PG,8 -9,9 -12,12 -12+,12 -12A,12 -12PG,12 -Teen,13 -13+,13 -14+,14 -15,15 -16,16 -Caution,18 -18,18 -Mature,1000 -Adult,1000 -R18,1000 diff --git a/Emby.Server.Implementations/Localization/Ratings/gb.json b/Emby.Server.Implementations/Localization/Ratings/gb.json new file mode 100644 index 0000000000..7fc88272cf --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/gb.json @@ -0,0 +1,97 @@ +{ + "countryCode": "gb", + "supportsSubScores": true, + "ratings": [ + { + "ratingStrings": ["0+", "All", "E", "G", "U"], + "ratingScore": { + "score": 0, + "subScore": 0 + } + }, + { + "ratingStrings": ["6+"], + "ratingScore": { + "score": 6, + "subScore": 0 + } + }, + { + "ratingStrings": ["7+"], + "ratingScore": { + "score": 7, + "subScore": 0 + } + }, + { + "ratingStrings": ["PG"], + "ratingScore": { + "score": 8, + "subScore": 0 + } + }, + { + "ratingStrings": ["9"], + "ratingScore": { + "score": 9, + "subScore": 0 + } + }, + { + "ratingStrings": ["12A", "12PG"], + "ratingScore": { + "score": 12, + "subScore": 0 + } + }, + { + "ratingStrings": ["12", "12+"], + "ratingScore": { + "score": 12, + "subScore": 1 + } + }, + { + "ratingStrings": ["13+", "Teen"], + "ratingScore": { + "score": 13, + "subScore": 0 + } + }, + { + "ratingStrings": ["14+"], + "ratingScore": { + "score": 14, + "subScore": 0 + } + }, + { + "ratingStrings": ["15"], + "ratingScore": { + "score": 15, + "subScore": 3 + } + }, + { + "ratingStrings": ["16"], + "ratingScore": { + "score": 16, + "subScore": 0 + } + }, + { + "ratingStrings": ["18", "Caution"], + "ratingScore": { + "score": 18, + "subScore": 1 + } + }, + { + "ratingStrings": ["Mature", "Adult", "R18"], + "ratingScore": { + "score": 1000, + "subScore": 0 + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/ie.csv b/Emby.Server.Implementations/Localization/Ratings/ie.csv deleted file mode 100644 index d3c634fc93..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/ie.csv +++ /dev/null @@ -1,10 +0,0 @@ -G,4 -PG,12 -12,12 -12A,12 -12PG,12 -15,15 -15PG,15 -15A,15 -16,16 -18,18 diff --git a/Emby.Server.Implementations/Localization/Ratings/ie.json b/Emby.Server.Implementations/Localization/Ratings/ie.json new file mode 100644 index 0000000000..f6cc56ed6d --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/ie.json @@ -0,0 +1,55 @@ +{ + "countryCode": "ie", + "supportsSubScores": true, + "ratings": [ + { + "ratingStrings": ["G"], + "ratingScore": { + "score": 4, + "subScore": 0 + } + }, + { + "ratingStrings": ["12A", "12PG", "PG"], + "ratingScore": { + "score": 12, + "subScore": 0 + } + }, + { + "ratingStrings": ["12"], + "ratingScore": { + "score": 12, + "subScore": 1 + } + }, + { + "ratingStrings": ["15A", "15PG"], + "ratingScore": { + "score": 15, + "subScore": 0 + } + }, + { + "ratingStrings": ["15"], + "ratingScore": { + "score": 15, + "subScore": 3 + } + }, + { + "ratingStrings": ["16"], + "ratingScore": { + "score": 16, + "subScore": 0 + } + }, + { + "ratingStrings": ["18"], + "ratingScore": { + "score": 18, + "subScore": 1 + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/jp.csv b/Emby.Server.Implementations/Localization/Ratings/jp.csv deleted file mode 100644 index bfb5fdaae9..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/jp.csv +++ /dev/null @@ -1,11 +0,0 @@ -A,0 -G,0 -B,12 -PG12,12 -C,15 -15+,15 -R15+,15 -16+,16 -D,17 -Z,18 -18+,18 diff --git a/Emby.Server.Implementations/Localization/Ratings/jp.json b/Emby.Server.Implementations/Localization/Ratings/jp.json new file mode 100644 index 0000000000..efff9e92ce --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/jp.json @@ -0,0 +1,62 @@ +{ + "countryCode": "jp", + "supportsSubScores": true, + "ratings": [ + { + "ratingStrings": ["A", "G"], + "ratingScore": { + "score": 0, + "subScore": 0 + } + }, + { + "ratingStrings": ["PG12"], + "ratingScore": { + "score": 12, + "subScore": 0 + } + }, + { + "ratingStrings": ["B"], + "ratingScore": { + "score": 12, + "subScore": 1 + } + }, + { + "ratingStrings": ["15A", "15PG"], + "ratingScore": { + "score": 15, + "subScore": 0 + } + }, + { + "ratingStrings": ["C", "15+", "R15+"], + "ratingScore": { + "score": 15, + "subScore": 1 + } + }, + { + "ratingStrings": ["16+"], + "ratingScore": { + "score": 16, + "subScore": null + } + }, + { + "ratingStrings": ["D"], + "ratingScore": { + "score": 17, + "subScore": null + } + }, + { + "ratingStrings": ["18+", "Z"], + "ratingScore": { + "score": 18, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/kz.csv b/Emby.Server.Implementations/Localization/Ratings/kz.csv deleted file mode 100644 index e26b32b67e..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/kz.csv +++ /dev/null @@ -1,6 +0,0 @@ -K,0 -БА,12 -Б14,14 -E16,16 -E18,18 -HA,18 diff --git a/Emby.Server.Implementations/Localization/Ratings/kz.json b/Emby.Server.Implementations/Localization/Ratings/kz.json new file mode 100644 index 0000000000..0f8f0c68e5 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/kz.json @@ -0,0 +1,41 @@ +{ + "countryCode": "kz", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["K"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["БА"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["Б14"], + "ratingScore": { + "score": 14, + "subScore": null + } + }, + { + "ratingStrings": ["E16"], + "ratingScore": { + "score": 16, + "subScore": null + } + }, + { + "ratingStrings": ["E18", "HA"], + "ratingScore": { + "score": 18, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/mx.csv b/Emby.Server.Implementations/Localization/Ratings/mx.csv deleted file mode 100644 index 305912f239..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/mx.csv +++ /dev/null @@ -1,6 +0,0 @@ -A,0 -AA,0 -B,12 -B-15,15 -C,18 -D,1000 diff --git a/Emby.Server.Implementations/Localization/Ratings/mx.json b/Emby.Server.Implementations/Localization/Ratings/mx.json new file mode 100644 index 0000000000..9dc3b89bd6 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/mx.json @@ -0,0 +1,41 @@ +{ + "countryCode": "mx", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["A", "AA"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["B"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["B-15"], + "ratingScore": { + "score": 15, + "subScore": null + } + }, + { + "ratingStrings": ["C"], + "ratingScore": { + "score": 18, + "subScore": null + } + }, + { + "ratingStrings": ["D"], + "ratingScore": { + "score": 1000, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/nl.csv b/Emby.Server.Implementations/Localization/Ratings/nl.csv deleted file mode 100644 index 44f372b2d6..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/nl.csv +++ /dev/null @@ -1,8 +0,0 @@ -AL,0 -MG6,6 -6,6 -9,9 -12,12 -14,14 -16,16 -18,18 diff --git a/Emby.Server.Implementations/Localization/Ratings/nl.json b/Emby.Server.Implementations/Localization/Ratings/nl.json new file mode 100644 index 0000000000..2e43eb83ab --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/nl.json @@ -0,0 +1,55 @@ +{ + "countryCode": "nl", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["AL"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["6", "MG6"], + "ratingScore": { + "score": 6, + "subScore": null + } + }, + { + "ratingStrings": ["9"], + "ratingScore": { + "score": 9, + "subScore": null + } + }, + { + "ratingStrings": ["12"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["14"], + "ratingScore": { + "score": 14, + "subScore": null + } + }, + { + "ratingStrings": ["16"], + "ratingScore": { + "score": 16, + "subScore": null + } + }, + { + "ratingStrings": ["18"], + "ratingScore": { + "score": 18, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/no.csv b/Emby.Server.Implementations/Localization/Ratings/no.csv deleted file mode 100644 index 6856a2dbbb..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/no.csv +++ /dev/null @@ -1,10 +0,0 @@ -A,0 -6,6 -7,7 -9,9 -11,11 -12,12 -15,15 -18,18 -C,18 -Not approved,1001 diff --git a/Emby.Server.Implementations/Localization/Ratings/no.json b/Emby.Server.Implementations/Localization/Ratings/no.json new file mode 100644 index 0000000000..a5e9523163 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/no.json @@ -0,0 +1,69 @@ +{ + "countryCode": "no", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["A"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["6"], + "ratingScore": { + "score": 6, + "subScore": null + } + }, + { + "ratingStrings": ["7"], + "ratingScore": { + "score": 7, + "subScore": null + } + }, + { + "ratingStrings": ["9"], + "ratingScore": { + "score": 9, + "subScore": null + } + }, + { + "ratingStrings": ["11"], + "ratingScore": { + "score": 11, + "subScore": null + } + }, + { + "ratingStrings": ["12"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["15"], + "ratingScore": { + "score": 15, + "subScore": null + } + }, + { + "ratingStrings": ["18"], + "ratingScore": { + "score": 18, + "subScore": null + } + }, + { + "ratingStrings": ["Not approved"], + "ratingScore": { + "score": 1001, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/nz.csv b/Emby.Server.Implementations/Localization/Ratings/nz.csv deleted file mode 100644 index 633da78fe1..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/nz.csv +++ /dev/null @@ -1,16 +0,0 @@ -Exempt,0 -G,0 -GY,13 -PG,13 -R13,13 -RP13,13 -R15,15 -M,16 -R16,16 -RP16,16 -GA,18 -R18,18 -RP18,18 -MA,1000 -R,1001 -Objectionable,1001 diff --git a/Emby.Server.Implementations/Localization/Ratings/nz.json b/Emby.Server.Implementations/Localization/Ratings/nz.json new file mode 100644 index 0000000000..3c1332271e --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/nz.json @@ -0,0 +1,69 @@ +{ + "countryCode": "nz", + "supportsSubScores": true, + "ratings": [ + { + "ratingStrings": ["Exempt", "G"], + "ratingScore": { + "score": 0, + "subScore": 0 + } + }, + { + "ratingStrings": ["RP13", "PG"], + "ratingScore": { + "score": 13, + "subScore": 0 + } + }, + { + "ratingStrings": ["GY", "R13"], + "ratingScore": { + "score": 13, + "subScore": 1 + } + }, + { + "ratingStrings": ["RP16", "M"], + "ratingScore": { + "score": 16, + "subScore": 0 + } + }, + { + "ratingStrings": ["R16"], + "ratingScore": { + "score": 16, + "subScore": 1 + } + }, + { + "ratingStrings": ["RP18"], + "ratingScore": { + "score": 18, + "subScore": 0 + } + }, + { + "ratingStrings": ["R18", "GA"], + "ratingScore": { + "score": 18, + "subScore": 1 + } + }, + { + "ratingStrings": ["MA"], + "ratingScore": { + "score": 1000, + "subScore": 0 + } + }, + { + "ratingStrings": ["Objectionable", "R"], + "ratingScore": { + "score": 1001, + "subScore": 0 + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/ro.csv b/Emby.Server.Implementations/Localization/Ratings/ro.csv deleted file mode 100644 index 44c23e2486..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/ro.csv +++ /dev/null @@ -1,6 +0,0 @@ -AG,0 -AP-12,12 -N-15,15 -IM-18,18 -IM-18-XXX,1000 -IC,1001 diff --git a/Emby.Server.Implementations/Localization/Ratings/ro.json b/Emby.Server.Implementations/Localization/Ratings/ro.json new file mode 100644 index 0000000000..9cf735a54c --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/ro.json @@ -0,0 +1,48 @@ +{ + "countryCode": "ro", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["AG"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["AP-12"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["N-15"], + "ratingScore": { + "score": 15, + "subScore": null + } + }, + { + "ratingStrings": ["IM-18"], + "ratingScore": { + "score": 18, + "subScore": null + } + }, + { + "ratingStrings": ["IM-18-XXX"], + "ratingScore": { + "score": 1000, + "subScore": null + } + }, + { + "ratingStrings": ["IC"], + "ratingScore": { + "score": 1001, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/ru.csv b/Emby.Server.Implementations/Localization/Ratings/ru.csv deleted file mode 100644 index 8b264070ba..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/ru.csv +++ /dev/null @@ -1,6 +0,0 @@ -0+,0 -6+,6 -12+,12 -16+,16 -18+,18 -Refused classification,1001 diff --git a/Emby.Server.Implementations/Localization/Ratings/ru.json b/Emby.Server.Implementations/Localization/Ratings/ru.json new file mode 100644 index 0000000000..d1b8b13aa0 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/ru.json @@ -0,0 +1,48 @@ +{ + "countryCode": "ru", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["0+"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["6+"], + "ratingScore": { + "score": 6, + "subScore": null + } + }, + { + "ratingStrings": ["12+"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["16+"], + "ratingScore": { + "score": 16, + "subScore": null + } + }, + { + "ratingStrings": ["18+"], + "ratingScore": { + "score": 18, + "subScore": null + } + }, + { + "ratingStrings": ["Refused classification"], + "ratingScore": { + "score": 1001, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/se.csv b/Emby.Server.Implementations/Localization/Ratings/se.csv deleted file mode 100644 index e129c35617..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/se.csv +++ /dev/null @@ -1,10 +0,0 @@ -Alla,0 -Barntillåten,0 -Btl,0 -0+,0 -7,7 -9+,9 -10+,10 -11,11 -14,14 -15,15 diff --git a/Emby.Server.Implementations/Localization/Ratings/se.json b/Emby.Server.Implementations/Localization/Ratings/se.json new file mode 100644 index 0000000000..70084995d1 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/se.json @@ -0,0 +1,55 @@ +{ + "countryCode": "se", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["0+", "Alla", "Barntillåten", "Btl"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["7"], + "ratingScore": { + "score": 7, + "subScore": null + } + }, + { + "ratingStrings": ["9+"], + "ratingScore": { + "score": 9, + "subScore": null + } + }, + { + "ratingStrings": ["10+"], + "ratingScore": { + "score": 10, + "subScore": null + } + }, + { + "ratingStrings": ["11"], + "ratingScore": { + "score": 11, + "subScore": null + } + }, + { + "ratingStrings": ["14"], + "ratingScore": { + "score": 14, + "subScore": null + } + }, + { + "ratingStrings": ["15"], + "ratingScore": { + "score": 15, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/sk.csv b/Emby.Server.Implementations/Localization/Ratings/sk.csv deleted file mode 100644 index dbafd8efa3..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/sk.csv +++ /dev/null @@ -1,6 +0,0 @@ -NR,0 -U,0 -7,7 -12,12 -15,15 -18,18 diff --git a/Emby.Server.Implementations/Localization/Ratings/sk.json b/Emby.Server.Implementations/Localization/Ratings/sk.json new file mode 100644 index 0000000000..5ec6111ecd --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/sk.json @@ -0,0 +1,41 @@ +{ + "countryCode": "sk", + "supportsSubScores": false, + "ratings": [ + { + "ratingStrings": ["U", "NR"], + "ratingScore": { + "score": 0, + "subScore": null + } + }, + { + "ratingStrings": ["7"], + "ratingScore": { + "score": 7, + "subScore": null + } + }, + { + "ratingStrings": ["12"], + "ratingScore": { + "score": 12, + "subScore": null + } + }, + { + "ratingStrings": ["15"], + "ratingScore": { + "score": 15, + "subScore": null + } + }, + { + "ratingStrings": ["18"], + "ratingScore": { + "score": 18, + "subScore": null + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/uk.csv b/Emby.Server.Implementations/Localization/Ratings/uk.csv deleted file mode 100644 index 75b1c20589..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/uk.csv +++ /dev/null @@ -1,22 +0,0 @@ -All,0 -E,0 -G,0 -U,0 -0+,0 -6+,6 -7+,7 -PG,8 -9+,9 -12,12 -12+,12 -12A,12 -Teen,13 -13+,13 -14+,14 -15,15 -16,16 -Caution,18 -18,18 -Mature,1000 -Adult,1000 -R18,1000 diff --git a/Emby.Server.Implementations/Localization/Ratings/uk.json b/Emby.Server.Implementations/Localization/Ratings/uk.json new file mode 100644 index 0000000000..7fc88272cf --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/uk.json @@ -0,0 +1,97 @@ +{ + "countryCode": "gb", + "supportsSubScores": true, + "ratings": [ + { + "ratingStrings": ["0+", "All", "E", "G", "U"], + "ratingScore": { + "score": 0, + "subScore": 0 + } + }, + { + "ratingStrings": ["6+"], + "ratingScore": { + "score": 6, + "subScore": 0 + } + }, + { + "ratingStrings": ["7+"], + "ratingScore": { + "score": 7, + "subScore": 0 + } + }, + { + "ratingStrings": ["PG"], + "ratingScore": { + "score": 8, + "subScore": 0 + } + }, + { + "ratingStrings": ["9"], + "ratingScore": { + "score": 9, + "subScore": 0 + } + }, + { + "ratingStrings": ["12A", "12PG"], + "ratingScore": { + "score": 12, + "subScore": 0 + } + }, + { + "ratingStrings": ["12", "12+"], + "ratingScore": { + "score": 12, + "subScore": 1 + } + }, + { + "ratingStrings": ["13+", "Teen"], + "ratingScore": { + "score": 13, + "subScore": 0 + } + }, + { + "ratingStrings": ["14+"], + "ratingScore": { + "score": 14, + "subScore": 0 + } + }, + { + "ratingStrings": ["15"], + "ratingScore": { + "score": 15, + "subScore": 3 + } + }, + { + "ratingStrings": ["16"], + "ratingScore": { + "score": 16, + "subScore": 0 + } + }, + { + "ratingStrings": ["18", "Caution"], + "ratingScore": { + "score": 18, + "subScore": 1 + } + }, + { + "ratingStrings": ["Mature", "Adult", "R18"], + "ratingScore": { + "score": 1000, + "subScore": 0 + } + } + ] +} diff --git a/Emby.Server.Implementations/Localization/Ratings/us.csv b/Emby.Server.Implementations/Localization/Ratings/us.csv deleted file mode 100644 index 9aa5c00eb3..0000000000 --- a/Emby.Server.Implementations/Localization/Ratings/us.csv +++ /dev/null @@ -1,52 +0,0 @@ -Approved,0 -G,0 -TV-G,0 -TV-Y,0 -TV-Y7,7 -TV-Y7-FV,7 -PG,10 -TV-PG,10 -TV-PG-D,10 -TV-PG-L,10 -TV-PG-S,10 -TV-PG-V,10 -TV-PG-DL,10 -TV-PG-DS,10 -TV-PG-DV,10 -TV-PG-LS,10 -TV-PG-LV,10 -TV-PG-SV,10 -TV-PG-DLS,10 -TV-PG-DLV,10 -TV-PG-DSV,10 -TV-PG-LSV,10 -TV-PG-DLSV,10 -PG-13,13 -TV-14,14 -TV-14-D,14 -TV-14-L,14 -TV-14-S,14 -TV-14-V,14 -TV-14-DL,14 -TV-14-DS,14 -TV-14-DV,14 -TV-14-LS,14 -TV-14-LV,14 -TV-14-SV,14 -TV-14-DLS,14 -TV-14-DLV,14 -TV-14-DSV,14 -TV-14-LSV,14 -TV-14-DLSV,14 -NC-17,17 -R,17 -TV-MA,17 -TV-MA-L,17 -TV-MA-S,17 -TV-MA-V,17 -TV-MA-LS,17 -TV-MA-LV,17 -TV-MA-SV,17 -TV-MA-LSV,17 -TV-X,18 -TV-AO,18 diff --git a/Emby.Server.Implementations/Localization/Ratings/us.json b/Emby.Server.Implementations/Localization/Ratings/us.json new file mode 100644 index 0000000000..08a6373129 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/us.json @@ -0,0 +1,83 @@ +{ + "countryCode": "us", + "supportsSubScores": true, + "ratings": [ + { + "ratingStrings": ["Approved", "G", "TV-G", "TV-Y"], + "ratingScore": { + "score": 0, + "subScore": 0 + } + }, + { + "ratingStrings": ["TV-Y7"], + "ratingScore": { + "score": 7, + "subScore": 0 + } + }, + { + "ratingStrings": ["TV-Y7-FV"], + "ratingScore": { + "score": 7, + "subScore": 1 + } + }, + { + "ratingStrings": ["PG", "TV-PG"], + "ratingScore": { + "score": 10, + "subScore": 0 + } + }, + { + "ratingStrings": ["TV-PG-D", "TV-PG-L", "TV-PG-S", "TV-PG-V", "TV-PG-DL", "TV-PG-DS", "TV-PG-DV", "TV-PG-LS", "TV-PG-LV", "TV-PG-SV", "TV-PG-DLS", "TV-PG-DLV", "TV-PG-DSV", "TV-PG-LSV", "TV-PG-DLSV"], + "ratingScore": { + "score": 10, + "subScore": 1 + } + }, + { + "ratingStrings": ["PG-13"], + "ratingScore": { + "score": 13, + "subScore": 0 + } + }, + { + "ratingStrings": ["TV-14"], + "ratingScore": { + "score": 14, + "subScore": 0 + } + }, + { + "ratingStrings": ["TV-14-D", "TV-14-L", "TV-14-S", "TV-14-V", "TV-14-DL", "TV-14-DS", "TV-14-DV", "TV-14-LS", "TV-14-LV", "TV-14-SV", "TV-14-DLS", "TV-14-DLV", "TV-14-DSV", "TV-14-LSV", "TV-14-DLSV"], + "ratingScore": { + "score": 14, + "subScore": 1 + } + }, + { + "ratingStrings": ["R"], + "ratingScore": { + "score": 17, + "subScore": 0 + } + }, + { + "ratingStrings": ["NC-17", "TV-MA", "TV-MA-L", "TV-MA-S", "TV-MA-V", "TV-MA-LS", "TV-MA-LV", "TV-MA-SV", "TV-MA-LSV"], + "ratingScore": { + "score": 17, + "subScore": 1 + } + }, + { + "ratingStrings": ["TV-X", "TV-AO"], + "ratingScore": { + "score": 18, + "subScore": 0 + } + } + ] +} diff --git a/Emby.Server.Implementations/Sorting/OfficialRatingComparer.cs b/Emby.Server.Implementations/Sorting/OfficialRatingComparer.cs index b4ee2c7234..789af01cc3 100644 --- a/Emby.Server.Implementations/Sorting/OfficialRatingComparer.cs +++ b/Emby.Server.Implementations/Sorting/OfficialRatingComparer.cs @@ -1,45 +1,54 @@ -#pragma warning disable CS1591 - using System; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.Querying; -namespace Emby.Server.Implementations.Sorting +namespace Emby.Server.Implementations.Sorting; + +/// +/// Class providing comparison for official ratings. +/// +public class OfficialRatingComparer : IBaseItemComparer { - public class OfficialRatingComparer : IBaseItemComparer + private readonly ILocalizationManager _localizationManager; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + public OfficialRatingComparer(ILocalizationManager localizationManager) { - private readonly ILocalizationManager _localization; + _localizationManager = localizationManager; + } - public OfficialRatingComparer(ILocalizationManager localization) + /// + /// Gets the name. + /// + /// The name. + public ItemSortBy Type => ItemSortBy.OfficialRating; + + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem? x, BaseItem? y) + { + ArgumentNullException.ThrowIfNull(x); + ArgumentNullException.ThrowIfNull(y); + var zeroRating = new ParentalRatingScore(0, 0); + + var ratingX = string.IsNullOrEmpty(x.OfficialRating) ? zeroRating : _localizationManager.GetRatingScore(x.OfficialRating) ?? zeroRating; + var ratingY = string.IsNullOrEmpty(y.OfficialRating) ? zeroRating : _localizationManager.GetRatingScore(y.OfficialRating) ?? zeroRating; + var scoreCompare = ratingX.Score.CompareTo(ratingY.Score); + if (scoreCompare is 0) { - _localization = localization; + return (ratingX.SubScore ?? 0).CompareTo(ratingY.SubScore ?? 0); } - /// - /// Gets the name. - /// - /// The name. - public ItemSortBy Type => ItemSortBy.OfficialRating; - - /// - /// Compares the specified x. - /// - /// The x. - /// The y. - /// System.Int32. - public int Compare(BaseItem? x, BaseItem? y) - { - ArgumentNullException.ThrowIfNull(x); - - ArgumentNullException.ThrowIfNull(y); - - var levelX = string.IsNullOrEmpty(x.OfficialRating) ? 0 : _localization.GetRatingLevel(x.OfficialRating) ?? 0; - var levelY = string.IsNullOrEmpty(y.OfficialRating) ? 0 : _localization.GetRatingLevel(y.OfficialRating) ?? 0; - - return levelX.CompareTo(levelY); - } + return scoreCompare; } } diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 803c2f1f78..a491283363 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -448,13 +448,13 @@ public class ItemsController : BaseJellyfinApiController // Min official rating if (!string.IsNullOrWhiteSpace(minOfficialRating)) { - query.MinParentalRating = _localization.GetRatingLevel(minOfficialRating); + query.MinParentalRating = _localization.GetRatingScore(minOfficialRating); } // Max official rating if (!string.IsNullOrWhiteSpace(maxOfficialRating)) { - query.MaxParentalRating = _localization.GetRatingLevel(maxOfficialRating); + query.MaxParentalRating = _localization.GetRatingScore(maxOfficialRating); } // Artists diff --git a/Jellyfin.Api/Controllers/LocalizationController.cs b/Jellyfin.Api/Controllers/LocalizationController.cs index f65d95c411..bbce5a9e13 100644 --- a/Jellyfin.Api/Controllers/LocalizationController.cs +++ b/Jellyfin.Api/Controllers/LocalizationController.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using Jellyfin.Api.Constants; using MediaBrowser.Common.Api; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; @@ -45,7 +44,7 @@ public class LocalizationController : BaseJellyfinApiController /// An containing the list of countries. [HttpGet("Countries")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetCountries() + public ActionResult> GetCountries() { return Ok(_localization.GetCountries()); } @@ -57,7 +56,7 @@ public class LocalizationController : BaseJellyfinApiController /// An containing the list of parental ratings. [HttpGet("ParentalRatings")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetParentalRatings() + public ActionResult> GetParentalRatings() { return Ok(_localization.GetParentalRatings()); } diff --git a/Jellyfin.Server.Implementations/Extensions/ExpressionExtensions.cs b/Jellyfin.Server.Implementations/Extensions/ExpressionExtensions.cs new file mode 100644 index 0000000000..d70ac672f2 --- /dev/null +++ b/Jellyfin.Server.Implementations/Extensions/ExpressionExtensions.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace Jellyfin.Server.Implementations.Extensions; + +/// +/// Provides extension methods. +/// +public static class ExpressionExtensions +{ + /// + /// Combines two predicates into a single predicate using a logical OR operation. + /// + /// The predicate parameter type. + /// The first predicate expression to combine. + /// The second predicate expression to combine. + /// A new expression representing the OR combination of the input predicates. + public static Expression> Or(this Expression> firstPredicate, Expression> secondPredicate) + { + ArgumentNullException.ThrowIfNull(firstPredicate); + ArgumentNullException.ThrowIfNull(secondPredicate); + + var invokedExpression = Expression.Invoke(secondPredicate, firstPredicate.Parameters); + return Expression.Lambda>(Expression.OrElse(firstPredicate.Body, invokedExpression), firstPredicate.Parameters); + } + + /// + /// Combines multiple predicates into a single predicate using a logical OR operation. + /// + /// The predicate parameter type. + /// A collection of predicate expressions to combine. + /// A new expression representing the OR combination of all input predicates. + public static Expression> Or(this IEnumerable>> predicates) + { + ArgumentNullException.ThrowIfNull(predicates); + + return predicates.Aggregate((aggregatePredicate, nextPredicate) => aggregatePredicate.Or(nextPredicate)); + } + + /// + /// Combines two predicates into a single predicate using a logical AND operation. + /// + /// The predicate parameter type. + /// The first predicate expression to combine. + /// The second predicate expression to combine. + /// A new expression representing the AND combination of the input predicates. + public static Expression> And(this Expression> firstPredicate, Expression> secondPredicate) + { + ArgumentNullException.ThrowIfNull(firstPredicate); + ArgumentNullException.ThrowIfNull(secondPredicate); + + var invokedExpression = Expression.Invoke(secondPredicate, firstPredicate.Parameters); + return Expression.Lambda>(Expression.AndAlso(firstPredicate.Body, invokedExpression), firstPredicate.Parameters); + } + + /// + /// Combines multiple predicates into a single predicate using a logical AND operation. + /// + /// The predicate parameter type. + /// A collection of predicate expressions to combine. + /// A new expression representing the AND combination of all input predicates. + public static Expression> And(this IEnumerable>> predicates) + { + ArgumentNullException.ThrowIfNull(predicates); + + return predicates.Aggregate((aggregatePredicate, nextPredicate) => aggregatePredicate.And(nextPredicate)); + } +} diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs index b0a36b3ae6..08c024f437 100644 --- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs +++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs @@ -9,6 +9,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Linq.Expressions; using System.Reflection; using System.Text; using System.Text.Json; @@ -19,6 +20,7 @@ using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using Jellyfin.Extensions.Json; +using Jellyfin.Server.Implementations.Extensions; using MediaBrowser.Common; using MediaBrowser.Controller; using MediaBrowser.Controller.Channels; @@ -781,6 +783,7 @@ public sealed class BaseItemRepository entity.PreferredMetadataCountryCode = dto.PreferredMetadataCountryCode; entity.IsInMixedFolder = dto.IsInMixedFolder; entity.InheritedParentalRatingValue = dto.InheritedParentalRatingValue; + entity.InheritedParentalRatingSubValue = dto.InheritedParentalRatingSubValue; entity.CriticRating = dto.CriticRating; entity.PresentationUniqueKey = dto.PresentationUniqueKey; entity.OriginalTitle = dto.OriginalTitle; @@ -1796,61 +1799,73 @@ public sealed class BaseItemRepository .Where(e => filter.OfficialRatings.Contains(e.OfficialRating)); } - if (filter.HasParentalRating ?? false) + Expression>? minParentalRatingFilter = null; + if (filter.MinParentalRating != null) { - if (filter.MinParentalRating.HasValue) + var min = filter.MinParentalRating; + minParentalRatingFilter = e => e.InheritedParentalRatingValue >= min.Score || e.InheritedParentalRatingValue == null; + if (min.SubScore != null) { - baseQuery = baseQuery - .Where(e => e.InheritedParentalRatingValue >= filter.MinParentalRating.Value); + minParentalRatingFilter = minParentalRatingFilter.And(e => e.InheritedParentalRatingValue >= min.SubScore || e.InheritedParentalRatingValue == null); } + } - if (filter.MaxParentalRating.HasValue) + Expression>? maxParentalRatingFilter = null; + if (filter.MaxParentalRating != null) + { + var max = filter.MaxParentalRating; + maxParentalRatingFilter = e => e.InheritedParentalRatingValue <= max.Score || e.InheritedParentalRatingValue == null; + if (max.SubScore != null) { - baseQuery = baseQuery - .Where(e => e.InheritedParentalRatingValue < filter.MaxParentalRating.Value); + maxParentalRatingFilter = maxParentalRatingFilter.And(e => e.InheritedParentalRatingValue <= max.SubScore || e.InheritedParentalRatingValue == null); } } - else if (filter.BlockUnratedItems.Length > 0) + + if (filter.HasParentalRating ?? false) { - var unratedItems = filter.BlockUnratedItems.Select(f => f.ToString()).ToArray(); - if (filter.MinParentalRating.HasValue) + if (minParentalRatingFilter != null) { - if (filter.MaxParentalRating.HasValue) - { - baseQuery = baseQuery - .Where(e => (e.InheritedParentalRatingValue == null && !unratedItems.Contains(e.UnratedType)) - || (e.InheritedParentalRatingValue >= filter.MinParentalRating && e.InheritedParentalRatingValue <= filter.MaxParentalRating)); - } - else - { - baseQuery = baseQuery - .Where(e => (e.InheritedParentalRatingValue == null && !unratedItems.Contains(e.UnratedType)) - || e.InheritedParentalRatingValue >= filter.MinParentalRating); - } + baseQuery = baseQuery.Where(minParentalRatingFilter); } - else + + if (maxParentalRatingFilter != null) { - baseQuery = baseQuery - .Where(e => e.InheritedParentalRatingValue != null && !unratedItems.Contains(e.UnratedType)); + baseQuery = baseQuery.Where(maxParentalRatingFilter); } } - else if (filter.MinParentalRating.HasValue) + else if (filter.BlockUnratedItems.Length > 0) { - if (filter.MaxParentalRating.HasValue) + var unratedItemTypes = filter.BlockUnratedItems.Select(f => f.ToString()).ToArray(); + Expression> unratedItemFilter = e => e.InheritedParentalRatingValue != null || !unratedItemTypes.Contains(e.UnratedType); + + if (minParentalRatingFilter != null && maxParentalRatingFilter != null) { - baseQuery = baseQuery - .Where(e => e.InheritedParentalRatingValue != null && e.InheritedParentalRatingValue >= filter.MinParentalRating.Value && e.InheritedParentalRatingValue <= filter.MaxParentalRating.Value); + baseQuery = baseQuery.Where(unratedItemFilter.And(minParentalRatingFilter.And(maxParentalRatingFilter))); + } + else if (minParentalRatingFilter != null) + { + baseQuery = baseQuery.Where(unratedItemFilter.And(minParentalRatingFilter)); + } + else if (maxParentalRatingFilter != null) + { + baseQuery = baseQuery.Where(unratedItemFilter.And(maxParentalRatingFilter)); } else { - baseQuery = baseQuery - .Where(e => e.InheritedParentalRatingValue != null && e.InheritedParentalRatingValue >= filter.MinParentalRating.Value); + baseQuery = baseQuery.Where(unratedItemFilter); } } - else if (filter.MaxParentalRating.HasValue) + else if (minParentalRatingFilter != null || maxParentalRatingFilter != null) { - baseQuery = baseQuery - .Where(e => e.InheritedParentalRatingValue != null && e.InheritedParentalRatingValue >= filter.MaxParentalRating.Value); + if (minParentalRatingFilter != null) + { + baseQuery = baseQuery.Where(minParentalRatingFilter); + } + + if (maxParentalRatingFilter != null) + { + baseQuery = baseQuery.Where(maxParentalRatingFilter); + } } else if (!filter.HasParentalRating ?? false) { diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 3c39e5503b..3dfb14d716 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -342,7 +342,8 @@ namespace Jellyfin.Server.Implementations.Users }, Policy = new UserPolicy { - MaxParentalRating = user.MaxParentalAgeRating, + MaxParentalRating = user.MaxParentalRatingScore, + MaxParentalSubRating = user.MaxParentalRatingSubScore, EnableUserPreferenceAccess = user.EnableUserPreferenceAccess, RemoteClientBitrateLimit = user.RemoteClientBitrateLimit ?? 0, AuthenticationProviderId = user.AuthenticationProviderId, @@ -668,7 +669,8 @@ namespace Jellyfin.Server.Implementations.Users _ => policy.LoginAttemptsBeforeLockout }; - user.MaxParentalAgeRating = policy.MaxParentalRating; + user.MaxParentalRatingScore = policy.MaxParentalRating; + user.MaxParentalRatingSubScore = policy.MaxParentalSubRating; user.EnableUserPreferenceAccess = policy.EnableUserPreferenceAccess; user.RemoteClientBitrateLimit = policy.RemoteClientBitrateLimit; user.AuthenticationProviderId = policy.AuthenticationProviderId; diff --git a/Jellyfin.Server/Migrations/MigrationRunner.cs b/Jellyfin.Server/Migrations/MigrationRunner.cs index 49568b087a..68a3491b57 100644 --- a/Jellyfin.Server/Migrations/MigrationRunner.cs +++ b/Jellyfin.Server/Migrations/MigrationRunner.cs @@ -49,12 +49,12 @@ namespace Jellyfin.Server.Migrations typeof(Routines.RemoveDownloadImagesInAdvance), typeof(Routines.MigrateAuthenticationDb), typeof(Routines.FixPlaylistOwner), - typeof(Routines.MigrateRatingLevels), typeof(Routines.AddDefaultCastReceivers), typeof(Routines.UpdateDefaultPluginRepository), typeof(Routines.FixAudioData), typeof(Routines.RemoveDuplicatePlaylistChildren), typeof(Routines.MigrateLibraryDb), + typeof(Routines.MigrateRatingLevels), typeof(Routines.MoveTrickplayFiles), }; diff --git a/Jellyfin.Server/Migrations/Routines/MigrateRatingLevels.cs b/Jellyfin.Server/Migrations/Routines/MigrateRatingLevels.cs index 9c2184029c..c38beb7232 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateRatingLevels.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateRatingLevels.cs @@ -1,36 +1,33 @@ using System; -using System.Globalization; -using System.IO; -using Emby.Server.Implementations.Data; -using MediaBrowser.Controller; +using System.Linq; +using Jellyfin.Database.Implementations; using MediaBrowser.Model.Globalization; -using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace Jellyfin.Server.Migrations.Routines { /// - /// Migrate rating levels to new rating level system. + /// Migrate rating levels. /// - internal class MigrateRatingLevels : IMigrationRoutine + internal class MigrateRatingLevels : IDatabaseMigrationRoutine { - private const string DbFilename = "library.db"; private readonly ILogger _logger; - private readonly IServerApplicationPaths _applicationPaths; + private readonly IDbContextFactory _provider; private readonly ILocalizationManager _localizationManager; public MigrateRatingLevels( - IServerApplicationPaths applicationPaths, + IDbContextFactory provider, ILoggerFactory loggerFactory, ILocalizationManager localizationManager) { - _applicationPaths = applicationPaths; + _provider = provider; _localizationManager = localizationManager; _logger = loggerFactory.CreateLogger(); } /// - public Guid Id => Guid.Parse("{73DAB92A-178B-48CD-B05B-FE18733ACDC8}"); + public Guid Id => Guid.Parse("{98724538-EB11-40E3-931A-252C55BDDE7A}"); /// public string Name => "MigrateRatingLevels"; @@ -41,54 +38,37 @@ namespace Jellyfin.Server.Migrations.Routines /// public void Perform() { - var dbPath = Path.Combine(_applicationPaths.DataPath, DbFilename); - - // Back up the database before modifying any entries - for (int i = 1; ; i++) + _logger.LogInformation("Recalculating parental rating levels based on rating string."); + using var context = _provider.CreateDbContext(); + using var transaction = context.Database.BeginTransaction(); + var ratings = context.BaseItems.AsNoTracking().Select(e => e.OfficialRating).Distinct(); + foreach (var rating in ratings) { - var bakPath = string.Format(CultureInfo.InvariantCulture, "{0}.bak{1}", dbPath, i); - if (!File.Exists(bakPath)) + if (string.IsNullOrEmpty(rating)) { - try - { - File.Copy(dbPath, bakPath); - _logger.LogInformation("Library database backed up to {BackupPath}", bakPath); - break; - } - catch (Exception ex) - { - _logger.LogError(ex, "Cannot make a backup of {Library} at path {BackupPath}", DbFilename, bakPath); - throw; - } + int? value = null; + context.BaseItems + .Where(e => e.OfficialRating == null || e.OfficialRating == string.Empty) + .ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingValue, value)); + context.BaseItems + .Where(e => e.OfficialRating == null || e.OfficialRating == string.Empty) + .ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingSubValue, value)); } - } - - // Migrate parental rating strings to new levels - _logger.LogInformation("Recalculating parental rating levels based on rating string."); - using var connection = new SqliteConnection($"Filename={dbPath}"); - connection.Open(); - using (var transaction = connection.BeginTransaction()) - { - var queryResult = connection.Query("SELECT DISTINCT OfficialRating FROM TypedBaseItems"); - foreach (var entry in queryResult) + else { - if (!entry.TryGetString(0, out var ratingString) || string.IsNullOrEmpty(ratingString)) - { - connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = NULL WHERE OfficialRating IS NULL OR OfficialRating='';"); - } - else - { - var ratingValue = _localizationManager.GetRatingLevel(ratingString)?.ToString(CultureInfo.InvariantCulture) ?? "NULL"; - - using var statement = connection.PrepareStatement("UPDATE TypedBaseItems SET InheritedParentalRatingValue = @Value WHERE OfficialRating = @Rating;"); - statement.TryBind("@Value", ratingValue); - statement.TryBind("@Rating", ratingString); - statement.ExecuteNonQuery(); - } + var ratingValue = _localizationManager.GetRatingScore(rating); + var score = ratingValue?.Score; + var subScore = ratingValue?.SubScore; + context.BaseItems + .Where(e => e.OfficialRating == rating) + .ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingValue, score)); + context.BaseItems + .Where(e => e.OfficialRating == rating) + .ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingSubValue, subScore)); } - - transaction.Commit(); } + + transaction.Commit(); } } } diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index c40560660d..1b5fab7a89 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -112,7 +112,8 @@ namespace Jellyfin.Server.Migrations.Routines { Id = entry.GetGuid(1), InternalId = entry.GetInt64(0), - MaxParentalAgeRating = policy.MaxParentalRating, + MaxParentalRatingScore = policy.MaxParentalRating, + MaxParentalRatingSubScore = null, EnableUserPreferenceAccess = policy.EnableUserPreferenceAccess, RemoteClientBitrateLimit = policy.RemoteClientBitrateLimit, InvalidLoginAttemptCount = policy.InvalidLoginAttemptCount, diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 53c832ff37..d484266726 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -581,6 +581,9 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public int? InheritedParentalRatingValue { get; set; } + [JsonIgnore] + public int? InheritedParentalRatingSubValue { get; set; } + /// /// Gets or sets the critic rating. /// @@ -1540,7 +1543,8 @@ namespace MediaBrowser.Controller.Entities return false; } - var maxAllowedRating = user.MaxParentalAgeRating; + var maxAllowedRating = user.MaxParentalRatingScore; + var maxAllowedSubRating = user.MaxParentalRatingSubScore; var rating = CustomRatingForComparison; if (string.IsNullOrEmpty(rating)) @@ -1554,10 +1558,10 @@ namespace MediaBrowser.Controller.Entities return !GetBlockUnratedValue(user); } - var value = LocalizationManager.GetRatingLevel(rating); + var ratingScore = LocalizationManager.GetRatingScore(rating); // Could not determine rating level - if (!value.HasValue) + if (ratingScore is null) { var isAllowed = !GetBlockUnratedValue(user); @@ -1569,10 +1573,15 @@ namespace MediaBrowser.Controller.Entities return isAllowed; } - return !maxAllowedRating.HasValue || value.Value <= maxAllowedRating.Value; + if (maxAllowedSubRating is not null) + { + return (ratingScore.SubScore ?? 0) <= maxAllowedSubRating && ratingScore.Score <= maxAllowedRating.Value; + } + + return !maxAllowedRating.HasValue || ratingScore.Score <= maxAllowedRating.Value; } - public int? GetInheritedParentalRatingValue() + public ParentalRatingScore GetParentalRatingScore() { var rating = CustomRatingForComparison; @@ -1586,7 +1595,7 @@ namespace MediaBrowser.Controller.Entities return null; } - return LocalizationManager.GetRatingLevel(rating); + return LocalizationManager.GetRatingScore(rating); } public List GetInheritedTags() @@ -2518,11 +2527,29 @@ namespace MediaBrowser.Controller.Entities var item = this; - var inheritedParentalRatingValue = item.GetInheritedParentalRatingValue() ?? null; - if (inheritedParentalRatingValue != item.InheritedParentalRatingValue) + var rating = item.GetParentalRatingScore(); + if (rating is not null) { - item.InheritedParentalRatingValue = inheritedParentalRatingValue; - updateType |= ItemUpdateType.MetadataImport; + if (rating.Score != item.InheritedParentalRatingValue) + { + item.InheritedParentalRatingValue = rating.Score; + updateType |= ItemUpdateType.MetadataImport; + } + + if (rating.SubScore != item.InheritedParentalRatingSubValue) + { + item.InheritedParentalRatingSubValue = rating.SubScore; + updateType |= ItemUpdateType.MetadataImport; + } + } + else + { + if (item.InheritedParentalRatingValue is not null) + { + item.InheritedParentalRatingValue = null; + item.InheritedParentalRatingSubValue = null; + updateType |= ItemUpdateType.MetadataImport; + } } return updateType; @@ -2542,8 +2569,9 @@ namespace MediaBrowser.Controller.Entities .Select(i => i.OfficialRating) .Where(i => !string.IsNullOrEmpty(i)) .Distinct(StringComparer.OrdinalIgnoreCase) - .Select(rating => (rating, LocalizationManager.GetRatingLevel(rating))) - .OrderBy(i => i.Item2 ?? 1000) + .Select(rating => (rating, LocalizationManager.GetRatingScore(rating))) + .OrderBy(i => i.Item2 is null ? 1001 : i.Item2.Score) + .ThenBy(i => i.Item2 is null ? 1001 : i.Item2.SubScore) .Select(i => i.rating); OfficialRating = ratings.FirstOrDefault() ?? currentOfficialRating; diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 5ce5fd4fa9..9a83dba458 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -232,9 +232,9 @@ namespace MediaBrowser.Controller.Entities public int? IndexNumber { get; set; } - public int? MinParentalRating { get; set; } + public ParentalRatingScore? MinParentalRating { get; set; } - public int? MaxParentalRating { get; set; } + public ParentalRatingScore? MaxParentalRating { get; set; } public bool? HasDeadParentId { get; set; } @@ -360,16 +360,17 @@ namespace MediaBrowser.Controller.Entities public void SetUser(User user) { - MaxParentalRating = user.MaxParentalAgeRating; - - if (MaxParentalRating.HasValue) + var maxRating = user.MaxParentalRatingScore; + if (maxRating.HasValue) { - string other = UnratedItem.Other.ToString(); - BlockUnratedItems = user.GetPreference(PreferenceKind.BlockUnratedItems) - .Where(i => i != other) - .Select(e => Enum.Parse(e, true)).ToArray(); + MaxParentalRating = new(maxRating.Value, user.MaxParentalRatingSubScore); } + var other = UnratedItem.Other.ToString(); + BlockUnratedItems = user.GetPreference(PreferenceKind.BlockUnratedItems) + .Where(i => i != other) + .Select(e => Enum.Parse(e, true)).ToArray(); + ExcludeInheritedTags = user.GetPreference(PreferenceKind.BlockedTags); IncludeInheritedTags = user.GetPreference(PreferenceKind.AllowedTags); diff --git a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs index a3035bf612..2f3a5d1179 100644 --- a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs +++ b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs @@ -1,35 +1,55 @@ -#pragma warning disable CS1591 - -using System; using System.Collections.Generic; using Jellyfin.Data.Enums; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Providers; -namespace MediaBrowser.Model.Dto +namespace MediaBrowser.Model.Dto; + +/// +/// A class representing metadata editor information. +/// +public class MetadataEditorInfo { - public class MetadataEditorInfo + /// + /// Initializes a new instance of the class. + /// + public MetadataEditorInfo() { - public MetadataEditorInfo() - { - ParentalRatingOptions = Array.Empty(); - Countries = Array.Empty(); - Cultures = Array.Empty(); - ExternalIdInfos = Array.Empty(); - ContentTypeOptions = Array.Empty(); - } - - public IReadOnlyList ParentalRatingOptions { get; set; } - - public IReadOnlyList Countries { get; set; } - - public IReadOnlyList Cultures { get; set; } - - public IReadOnlyList ExternalIdInfos { get; set; } - - public CollectionType? ContentType { get; set; } - - public IReadOnlyList ContentTypeOptions { get; set; } + ParentalRatingOptions = []; + Countries = []; + Cultures = []; + ExternalIdInfos = []; + ContentTypeOptions = []; } + + /// + /// Gets or sets the parental rating options. + /// + public IReadOnlyList ParentalRatingOptions { get; set; } + + /// + /// Gets or sets the countries. + /// + public IReadOnlyList Countries { get; set; } + + /// + /// Gets or sets the cultures. + /// + public IReadOnlyList Cultures { get; set; } + + /// + /// Gets or sets the external id infos. + /// + public IReadOnlyList ExternalIdInfos { get; set; } + + /// + /// Gets or sets the content type. + /// + public CollectionType? ContentType { get; set; } + + /// + /// Gets or sets the content type options. + /// + public IReadOnlyList ContentTypeOptions { get; set; } } diff --git a/MediaBrowser.Model/Entities/ParentalRating.cs b/MediaBrowser.Model/Entities/ParentalRating.cs index c92640818c..4f11989021 100644 --- a/MediaBrowser.Model/Entities/ParentalRating.cs +++ b/MediaBrowser.Model/Entities/ParentalRating.cs @@ -1,33 +1,40 @@ -#nullable disable -#pragma warning disable CS1591 +namespace MediaBrowser.Model.Entities; -namespace MediaBrowser.Model.Entities +/// +/// Class ParentalRating. +/// +public class ParentalRating { /// - /// Class ParentalRating. + /// Initializes a new instance of the class. /// - public class ParentalRating + /// The name. + /// The score. + public ParentalRating(string name, ParentalRatingScore? score) { - public ParentalRating() - { - } + Name = name; + Value = score?.Score; + RatingScore = score; + } - public ParentalRating(string name, int? value) - { - Name = name; - Value = value; - } + /// + /// Gets or sets the name. + /// + /// The name. + public string Name { get; set; } - /// - /// Gets or sets the name. - /// - /// The name. - public string Name { get; set; } + /// + /// Gets or sets the value. + /// + /// The value. + /// + /// Deprecated. + /// + public int? Value { get; set; } - /// - /// Gets or sets the value. - /// - /// The value. - public int? Value { get; set; } - } + /// + /// Gets or sets the rating score. + /// + /// The rating score. + public ParentalRatingScore? RatingScore { get; set; } } diff --git a/MediaBrowser.Model/Entities/ParentalRatingEntry.cs b/MediaBrowser.Model/Entities/ParentalRatingEntry.cs new file mode 100644 index 0000000000..69be74ac0a --- /dev/null +++ b/MediaBrowser.Model/Entities/ParentalRatingEntry.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace MediaBrowser.Model.Entities; + +/// +/// A class representing an parental rating entry. +/// +public class ParentalRatingEntry +{ + /// + /// Gets or sets the rating strings. + /// + [JsonPropertyName("ratingStrings")] + public required IReadOnlyList RatingStrings { get; set; } + + /// + /// Gets or sets the score. + /// + [JsonPropertyName("ratingScore")] + public required ParentalRatingScore RatingScore { get; set; } +} diff --git a/MediaBrowser.Model/Entities/ParentalRatingScore.cs b/MediaBrowser.Model/Entities/ParentalRatingScore.cs new file mode 100644 index 0000000000..b9bb99685f --- /dev/null +++ b/MediaBrowser.Model/Entities/ParentalRatingScore.cs @@ -0,0 +1,32 @@ +using System.Text.Json.Serialization; + +namespace MediaBrowser.Model.Entities; + +/// +/// A class representing an parental rating score. +/// +public class ParentalRatingScore +{ + /// + /// Initializes a new instance of the class. + /// + /// The score. + /// The sub score. + public ParentalRatingScore(int score, int? subScore) + { + Score = score; + SubScore = subScore; + } + + /// + /// Gets or sets the score. + /// + [JsonPropertyName("score")] + public int Score { get; set; } + + /// + /// Gets or sets the sub score. + /// + [JsonPropertyName("subScore")] + public int? SubScore { get; set; } +} diff --git a/MediaBrowser.Model/Entities/ParentalRatingSystem.cs b/MediaBrowser.Model/Entities/ParentalRatingSystem.cs new file mode 100644 index 0000000000..b452f29018 --- /dev/null +++ b/MediaBrowser.Model/Entities/ParentalRatingSystem.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace MediaBrowser.Model.Entities; + +/// +/// A class representing a parental rating system. +/// +public class ParentalRatingSystem +{ + /// + /// Gets or sets the country code. + /// + [JsonPropertyName("countryCode")] + public required string CountryCode { get; set; } + + /// + /// Gets or sets a value indicating whether sub scores are supported. + /// + [JsonPropertyName("supportsSubScores")] + public bool SupportsSubScores { get; set; } + + /// + /// Gets or sets the ratings. + /// + [JsonPropertyName("ratings")] + public IReadOnlyList? Ratings { get; set; } +} diff --git a/MediaBrowser.Model/Globalization/ILocalizationManager.cs b/MediaBrowser.Model/Globalization/ILocalizationManager.cs index 20deaa5057..d9df95325c 100644 --- a/MediaBrowser.Model/Globalization/ILocalizationManager.cs +++ b/MediaBrowser.Model/Globalization/ILocalizationManager.cs @@ -1,65 +1,64 @@ using System.Collections.Generic; using MediaBrowser.Model.Entities; -namespace MediaBrowser.Model.Globalization +namespace MediaBrowser.Model.Globalization; + +/// +/// Interface ILocalizationManager. +/// +public interface ILocalizationManager { /// - /// Interface ILocalizationManager. + /// Gets the cultures. /// - public interface ILocalizationManager - { - /// - /// Gets the cultures. - /// - /// . - IEnumerable GetCultures(); + /// . + IEnumerable GetCultures(); - /// - /// Gets the countries. - /// - /// . - IEnumerable GetCountries(); + /// + /// Gets the countries. + /// + /// . + IReadOnlyList GetCountries(); - /// - /// Gets the parental ratings. - /// - /// . - IEnumerable GetParentalRatings(); + /// + /// Gets the parental ratings. + /// + /// . + IReadOnlyList GetParentalRatings(); - /// - /// Gets the rating level. - /// - /// The rating. - /// The optional two letter ISO language string. - /// or null. - int? GetRatingLevel(string rating, string? countryCode = null); + /// + /// Gets the rating level. + /// + /// The rating. + /// The optional two letter ISO language string. + /// or null. + ParentalRatingScore? GetRatingScore(string rating, string? countryCode = null); - /// - /// Gets the localized string. - /// - /// The phrase. - /// The culture. - /// . - string GetLocalizedString(string phrase, string culture); + /// + /// Gets the localized string. + /// + /// The phrase. + /// The culture. + /// . + string GetLocalizedString(string phrase, string culture); - /// - /// Gets the localized string. - /// - /// The phrase. - /// System.String. - string GetLocalizedString(string phrase); + /// + /// Gets the localized string. + /// + /// The phrase. + /// System.String. + string GetLocalizedString(string phrase); - /// - /// Gets the localization options. - /// - /// . - IEnumerable GetLocalizationOptions(); + /// + /// Gets the localization options. + /// + /// . + IEnumerable GetLocalizationOptions(); - /// - /// Returns the correct for the given language. - /// - /// The language. - /// The correct for the given language. - CultureDto? FindLanguageInfo(string language); - } + /// + /// Returns the correct for the given language. + /// + /// The language. + /// The correct for the given language. + CultureDto? FindLanguageInfo(string language); } diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs index 49d7c0bcb0..6605064ad6 100644 --- a/MediaBrowser.Model/Querying/ItemFields.cs +++ b/MediaBrowser.Model/Querying/ItemFields.cs @@ -209,6 +209,7 @@ namespace MediaBrowser.Model.Querying ExternalEtag, PresentationUniqueKey, InheritedParentalRatingValue, + InheritedParentalRatingSubValue, ExternalSeriesId, SeriesPresentationUniqueKey, DateLastRefreshed, diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index 3d430e1015..2c393ca862 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -111,6 +111,8 @@ namespace MediaBrowser.Model.Users /// The max parental rating. public int? MaxParentalRating { get; set; } + public int? MaxParentalSubRating { get; set; } + public string[] BlockedTags { get; set; } public string[] AllowedTags { get; set; } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index e8994693de..45f66f85fc 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -193,6 +193,7 @@ namespace MediaBrowser.Providers.Manager if (hasRefreshedMetadata && hasRefreshedImages) { item.DateLastRefreshed = DateTime.UtcNow; + updateType |= item.OnMetadataChanged(); } updateType = await SaveInternal(item, refreshOptions, updateType, isFirstRefresh, requiresRefresh, metadataResult, cancellationToken).ConfigureAwait(false); diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs index fc9695a091..332dec2e67 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs @@ -84,6 +84,8 @@ public class BaseItemEntity public int? InheritedParentalRatingValue { get; set; } + public int? InheritedParentalRatingSubValue { get; set; } + public string? UnratedType { get; set; } public float? CriticRating { get; set; } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs index 31538b5bf3..4da7074ec7 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs @@ -249,9 +249,14 @@ namespace Jellyfin.Database.Implementations.Entities public bool EnableUserPreferenceAccess { get; set; } /// - /// Gets or sets the maximum parental age rating. + /// Gets or sets the maximum parental rating score. /// - public int? MaxParentalAgeRating { get; set; } + public int? MaxParentalRatingScore { get; set; } + + /// + /// Gets or sets the maximum parental rating sub score. + /// + public int? MaxParentalRatingSubScore { get; set; } /// /// Gets or sets the remote client bitrate limit. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250326065026_AddInheritedParentalRatingSubValue.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250326065026_AddInheritedParentalRatingSubValue.Designer.cs new file mode 100644 index 0000000000..d6befbe5eb --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250326065026_AddInheritedParentalRatingSubValue.Designer.cs @@ -0,0 +1,1658 @@ +// +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("20250326065026_AddInheritedParentalRatingSubValue")] + partial class AddInheritedParentalRatingSubValue + { + /// + 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("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/20250326065026_AddInheritedParentalRatingSubValue.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250326065026_AddInheritedParentalRatingSubValue.cs new file mode 100644 index 0000000000..71f56a1492 --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250326065026_AddInheritedParentalRatingSubValue.cs @@ -0,0 +1,48 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class AddInheritedParentalRatingSubValue : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "MaxParentalAgeRating", + table: "Users", + newName: "MaxParentalRatingScore"); + + migrationBuilder.AddColumn( + name: "MaxParentalRatingSubScore", + table: "Users", + type: "INTEGER", + nullable: true); + + migrationBuilder.AddColumn( + name: "InheritedParentalRatingSubValue", + table: "BaseItems", + type: "INTEGER", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "MaxParentalRatingSubScore", + table: "Users"); + + migrationBuilder.DropColumn( + name: "InheritedParentalRatingValue", + table: "BaseItems"); + + migrationBuilder.RenameColumn( + name: "MaxParentalRatingScore", + table: "Users", + newName: "MaxParentalAgeRating"); + } + } +} 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 5d8ddde082..8b2b269345 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs @@ -15,9 +15,9 @@ namespace Jellyfin.Server.Implementations.Migrations protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "9.0.2"); + modelBuilder.HasAnnotation("ProductVersion", "9.0.3"); - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AccessSchedule", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -40,9 +40,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("UserId"); b.ToTable("AccessSchedules"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ActivityLog", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -88,9 +90,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("DateCreated"); b.ToTable("ActivityLogs"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AncestorId", b => { b.Property("ItemId") .HasColumnType("TEXT"); @@ -103,9 +107,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("ParentItemId"); b.ToTable("AncestorIds"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AttachmentStreamInfo", b => { b.Property("ItemId") .HasColumnType("TEXT"); @@ -132,9 +138,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasKey("ItemId", "Index"); b.ToTable("AttachmentStreamInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -218,6 +226,9 @@ namespace Jellyfin.Server.Implementations.Migrations b.Property("IndexNumber") .HasColumnType("INTEGER"); + b.Property("InheritedParentalRatingSubValue") + .HasColumnType("INTEGER"); + b.Property("InheritedParentalRatingValue") .HasColumnType("INTEGER"); @@ -380,9 +391,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); b.ToTable("BaseItems"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemImageInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -415,9 +428,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("ItemId"); b.ToTable("BaseItemImageInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemMetadataField", b => { b.Property("Id") .HasColumnType("INTEGER"); @@ -430,9 +445,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("ItemId"); b.ToTable("BaseItemMetadataFields"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemProvider", b => { b.Property("ItemId") .HasColumnType("TEXT"); @@ -449,9 +466,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("ProviderId", "ProviderValue", "ItemId"); b.ToTable("BaseItemProviders"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemTrailerType", b => { b.Property("Id") .HasColumnType("INTEGER"); @@ -464,9 +483,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("ItemId"); b.ToTable("BaseItemTrailerTypes"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Chapter", b => { b.Property("ItemId") .HasColumnType("TEXT"); @@ -489,9 +510,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasKey("ItemId", "ChapterIndex"); b.ToTable("Chapters"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.CustomItemDisplayPreferences", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -521,9 +544,11 @@ namespace Jellyfin.Server.Implementations.Migrations .IsUnique(); b.ToTable("CustomItemDisplayPreferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -578,9 +603,11 @@ namespace Jellyfin.Server.Implementations.Migrations .IsUnique(); b.ToTable("DisplayPreferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.HomeSection", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -600,9 +627,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("DisplayPreferencesId"); b.ToTable("HomeSection"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ImageInfo", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -625,9 +654,11 @@ namespace Jellyfin.Server.Implementations.Migrations .IsUnique(); b.ToTable("ImageInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemDisplayPreferences", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -669,9 +700,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("UserId"); b.ToTable("ItemDisplayPreferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValue", b => { b.Property("ItemValueId") .ValueGeneratedOnAdd() @@ -694,9 +727,11 @@ namespace Jellyfin.Server.Implementations.Migrations .IsUnique(); b.ToTable("ItemValues"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValueMap", b => { b.Property("ItemValueId") .HasColumnType("TEXT"); @@ -709,9 +744,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("ItemId"); b.ToTable("ItemValuesMap"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaSegment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -736,9 +773,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasKey("Id"); b.ToTable("MediaSegments"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaStreamInfo", b => { b.Property("ItemId") .HasColumnType("TEXT"); @@ -889,9 +928,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("StreamIndex", "StreamType", "Language"); b.ToTable("MediaStreamInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.People", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -909,9 +950,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("Name"); b.ToTable("Peoples"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.PeopleBaseItemMap", b => { b.Property("ItemId") .HasColumnType("TEXT"); @@ -937,9 +980,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("ItemId", "SortOrder"); b.ToTable("PeopleBaseItemMap"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Permission", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -968,9 +1013,11 @@ namespace Jellyfin.Server.Implementations.Migrations .HasFilter("[UserId] IS NOT NULL"); b.ToTable("Permissions"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Preference", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -1001,9 +1048,11 @@ namespace Jellyfin.Server.Implementations.Migrations .HasFilter("[UserId] IS NOT NULL"); b.ToTable("Preferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.ApiKey", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -1030,9 +1079,11 @@ namespace Jellyfin.Server.Implementations.Migrations .IsUnique(); b.ToTable("ApiKeys"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.Device", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -1088,9 +1139,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("UserId", "DeviceId"); b.ToTable("Devices"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.DeviceOptions", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -1109,9 +1162,11 @@ namespace Jellyfin.Server.Implementations.Migrations .IsUnique(); b.ToTable("DeviceOptions"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.TrickplayInfo", b => { b.Property("ItemId") .HasColumnType("TEXT"); @@ -1140,9 +1195,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasKey("ItemId", "Width"); b.ToTable("TrickplayInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.User", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -1200,7 +1257,10 @@ namespace Jellyfin.Server.Implementations.Migrations b.Property("MaxActiveSessions") .HasColumnType("INTEGER"); - b.Property("MaxParentalAgeRating") + b.Property("MaxParentalRatingScore") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalRatingSubScore") .HasColumnType("INTEGER"); b.Property("MustUpdatePassword") @@ -1252,9 +1312,11 @@ namespace Jellyfin.Server.Implementations.Migrations .IsUnique(); b.ToTable("Users"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.UserData", b => { b.Property("ItemId") .HasColumnType("TEXT"); @@ -1305,26 +1367,28 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("ItemId", "UserId", "Played"); b.ToTable("UserData"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); }); - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AccessSchedule", b => { - b.HasOne("Jellyfin.Data.Entities.User", null) + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) .WithMany("AccessSchedules") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AncestorId", b => { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") .WithMany("Children") .HasForeignKey("ItemId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "ParentItem") .WithMany("ParentAncestors") .HasForeignKey("ParentItemId") .OnDelete(DeleteBehavior.Cascade) @@ -1335,9 +1399,9 @@ namespace Jellyfin.Server.Implementations.Migrations b.Navigation("ParentItem"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AttachmentStreamInfo", b => { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") .WithMany() .HasForeignKey("ItemId") .OnDelete(DeleteBehavior.Cascade) @@ -1346,9 +1410,9 @@ namespace Jellyfin.Server.Implementations.Migrations b.Navigation("Item"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemImageInfo", b => { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") .WithMany("Images") .HasForeignKey("ItemId") .OnDelete(DeleteBehavior.Cascade) @@ -1357,9 +1421,9 @@ namespace Jellyfin.Server.Implementations.Migrations b.Navigation("Item"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemMetadataField", b => { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") .WithMany("LockedFields") .HasForeignKey("ItemId") .OnDelete(DeleteBehavior.Cascade) @@ -1368,9 +1432,9 @@ namespace Jellyfin.Server.Implementations.Migrations b.Navigation("Item"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemProvider", b => { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") .WithMany("Provider") .HasForeignKey("ItemId") .OnDelete(DeleteBehavior.Cascade) @@ -1379,9 +1443,9 @@ namespace Jellyfin.Server.Implementations.Migrations b.Navigation("Item"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemTrailerType", b => { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") .WithMany("TrailerTypes") .HasForeignKey("ItemId") .OnDelete(DeleteBehavior.Cascade) @@ -1390,9 +1454,9 @@ namespace Jellyfin.Server.Implementations.Migrations b.Navigation("Item"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Chapter", b => { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") .WithMany("Chapters") .HasForeignKey("ItemId") .OnDelete(DeleteBehavior.Cascade) @@ -1401,50 +1465,50 @@ namespace Jellyfin.Server.Implementations.Migrations b.Navigation("Item"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => { - b.HasOne("Jellyfin.Data.Entities.User", null) + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) .WithMany("DisplayPreferences") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.HomeSection", b => { - b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + b.HasOne("Jellyfin.Database.Implementations.Entities.DisplayPreferences", null) .WithMany("HomeSections") .HasForeignKey("DisplayPreferencesId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ImageInfo", b => { - b.HasOne("Jellyfin.Data.Entities.User", null) + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) .WithOne("ProfileImage") - .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .HasForeignKey("Jellyfin.Database.Implementations.Entities.ImageInfo", "UserId") .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemDisplayPreferences", b => { - b.HasOne("Jellyfin.Data.Entities.User", null) + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) .WithMany("ItemDisplayPreferences") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValueMap", b => { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") .WithMany("ItemValues") .HasForeignKey("ItemId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") + b.HasOne("Jellyfin.Database.Implementations.Entities.ItemValue", "ItemValue") .WithMany("BaseItemsMap") .HasForeignKey("ItemValueId") .OnDelete(DeleteBehavior.Cascade) @@ -1455,9 +1519,9 @@ namespace Jellyfin.Server.Implementations.Migrations b.Navigation("ItemValue"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaStreamInfo", b => { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") .WithMany("MediaStreams") .HasForeignKey("ItemId") .OnDelete(DeleteBehavior.Cascade) @@ -1466,15 +1530,15 @@ namespace Jellyfin.Server.Implementations.Migrations b.Navigation("Item"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.PeopleBaseItemMap", b => { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") .WithMany("Peoples") .HasForeignKey("ItemId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Jellyfin.Data.Entities.People", "People") + b.HasOne("Jellyfin.Database.Implementations.Entities.People", "People") .WithMany("BaseItems") .HasForeignKey("PeopleId") .OnDelete(DeleteBehavior.Cascade) @@ -1485,25 +1549,25 @@ namespace Jellyfin.Server.Implementations.Migrations b.Navigation("People"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Permission", b => { - b.HasOne("Jellyfin.Data.Entities.User", null) + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) .WithMany("Permissions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Preference", b => { - b.HasOne("Jellyfin.Data.Entities.User", null) + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) .WithMany("Preferences") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.Device", b => { - b.HasOne("Jellyfin.Data.Entities.User", "User") + b.HasOne("Jellyfin.Database.Implementations.Entities.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1512,15 +1576,15 @@ namespace Jellyfin.Server.Implementations.Migrations b.Navigation("User"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.UserData", b => { - b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") .WithMany("UserData") .HasForeignKey("ItemId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Jellyfin.Data.Entities.User", "User") + b.HasOne("Jellyfin.Database.Implementations.Entities.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -1531,7 +1595,7 @@ namespace Jellyfin.Server.Implementations.Migrations b.Navigation("User"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => { b.Navigation("Chapters"); @@ -1556,22 +1620,22 @@ namespace Jellyfin.Server.Implementations.Migrations b.Navigation("UserData"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => { b.Navigation("HomeSections"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValue", b => { b.Navigation("BaseItemsMap"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.People", b => { b.Navigation("BaseItems"); }); - modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.User", b => { b.Navigation("AccessSchedules"); diff --git a/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs index 5babc91174..026da4992a 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs @@ -88,7 +88,7 @@ namespace Jellyfin.Server.Implementations.Tests.Localization var tvma = ratings.FirstOrDefault(x => x.Name.Equals("TV-MA", StringComparison.Ordinal)); Assert.NotNull(tvma); - Assert.Equal(17, tvma!.Value); + Assert.Equal(17, tvma!.RatingScore!.Score); } [Fact] @@ -105,47 +105,49 @@ namespace Jellyfin.Server.Implementations.Tests.Localization var fsk = ratings.FirstOrDefault(x => x.Name.Equals("FSK-12", StringComparison.Ordinal)); Assert.NotNull(fsk); - Assert.Equal(12, fsk!.Value); + Assert.Equal(12, fsk!.RatingScore!.Score); } [Theory] - [InlineData("CA-R", "CA", 18)] - [InlineData("FSK-16", "DE", 16)] - [InlineData("FSK-18", "DE", 18)] - [InlineData("FSK-18", "US", 18)] - [InlineData("TV-MA", "US", 17)] - [InlineData("XXX", "asdf", 1000)] - [InlineData("Germany: FSK-18", "DE", 18)] - [InlineData("Rated : R", "US", 17)] - [InlineData("Rated: R", "US", 17)] - [InlineData("Rated R", "US", 17)] - [InlineData(" PG-13 ", "US", 13)] - public async Task GetRatingLevel_GivenValidString_Success(string value, string countryCode, int expectedLevel) + [InlineData("CA-R", "CA", 18, 1)] + [InlineData("FSK-16", "DE", 16, null)] + [InlineData("FSK-18", "DE", 18, null)] + [InlineData("FSK-18", "US", 18, null)] + [InlineData("TV-MA", "US", 17, 1)] + [InlineData("XXX", "asdf", 1000, null)] + [InlineData("Germany: FSK-18", "DE", 18, null)] + [InlineData("Rated : R", "US", 17, 0)] + [InlineData("Rated: R", "US", 17, 0)] + [InlineData("Rated R", "US", 17, 0)] + [InlineData(" PG-13 ", "US", 13, 0)] + public async Task GetRatingLevel_GivenValidString_Success(string value, string countryCode, int? expectedScore, int? expectedSubScore) { var localizationManager = Setup(new ServerConfiguration() { MetadataCountryCode = countryCode }); await localizationManager.LoadAll(); - var level = localizationManager.GetRatingLevel(value); - Assert.NotNull(level); - Assert.Equal(expectedLevel, level!); + var score = localizationManager.GetRatingScore(value); + Assert.NotNull(score); + Assert.Equal(expectedScore, score.Score); + Assert.Equal(expectedSubScore, score.SubScore); } [Theory] - [InlineData("0", 0)] - [InlineData("1", 1)] - [InlineData("6", 6)] - [InlineData("12", 12)] - [InlineData("42", 42)] - [InlineData("9999", 9999)] - public async Task GetRatingLevel_GivenValidAge_Success(string value, int expectedLevel) + [InlineData("0", 0, null)] + [InlineData("1", 1, null)] + [InlineData("6", 6, null)] + [InlineData("12", 12, null)] + [InlineData("42", 42, null)] + [InlineData("9999", 9999, null)] + public async Task GetRatingLevel_GivenValidAge_Success(string value, int? expectedScore, int? expectedSubScore) { var localizationManager = Setup(new ServerConfiguration { MetadataCountryCode = "nl" }); await localizationManager.LoadAll(); - var level = localizationManager.GetRatingLevel(value); - Assert.NotNull(level); - Assert.Equal(expectedLevel, level); + var score = localizationManager.GetRatingScore(value); + Assert.NotNull(score); + Assert.Equal(expectedScore, score.Score); + Assert.Equal(expectedSubScore, score.SubScore); } [Fact] @@ -156,10 +158,10 @@ namespace Jellyfin.Server.Implementations.Tests.Localization UICulture = "de-DE" }); await localizationManager.LoadAll(); - Assert.Null(localizationManager.GetRatingLevel("NR")); - Assert.Null(localizationManager.GetRatingLevel("unrated")); - Assert.Null(localizationManager.GetRatingLevel("Not Rated")); - Assert.Null(localizationManager.GetRatingLevel("n/a")); + Assert.Null(localizationManager.GetRatingScore("NR")); + Assert.Null(localizationManager.GetRatingScore("unrated")); + Assert.Null(localizationManager.GetRatingScore("Not Rated")); + Assert.Null(localizationManager.GetRatingScore("n/a")); } [Theory] @@ -173,7 +175,7 @@ namespace Jellyfin.Server.Implementations.Tests.Localization }); await localizationManager.LoadAll(); - Assert.Null(localizationManager.GetRatingLevel(value)); + Assert.Null(localizationManager.GetRatingScore(value)); } [Theory] -- cgit v1.2.3 From a18d60d2dedb87735e23e050a2d6d79c395947c1 Mon Sep 17 00:00:00 2001 From: JPVenson Date: Thu, 3 Apr 2025 02:19:31 +0200 Subject: Trim library names (#13828) --- Emby.Server.Implementations/Library/LibraryManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index c8026960df..ab8884f17b 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2899,7 +2899,7 @@ namespace Emby.Server.Implementations.Library throw new ArgumentNullException(nameof(name)); } - name = _fileSystem.GetValidFilename(name); + name = _fileSystem.GetValidFilename(name.Trim()); var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath; -- 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 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs index 63481b1f8c..9a80eafe50 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 ab8884f17b..1303bb3cb2 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 c910abadbc..ac004b4132 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 baeea2c14a..c3a2e1bc4e 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 f414b6e396..3fc9bea842 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 0000000000..f63c5fd409 --- /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 0368898102..7c20164a6f 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 afa962a41c..75b3f151d7 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 09840d2eea..d8d1364727 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 431fc0b178..89291c73bf 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 a731d4785b..777e335874 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 c7f9cf2ccf..0cda803d64 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 34e3eabc97..f8f7ad0f9f 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 aab3082b37..2f27d9389a 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 0000000000..d668eea92f --- /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 0000000000..f921856a20 --- /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 0bb4b31b05..08c73217f3 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 2264d58ae75477595253b53d37560dd930586365 Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Sat, 5 Apr 2025 15:53:17 +0200 Subject: Use subdirectories to organize extracted data (#13838) * Use subdirectories to organize extracted data * Apply suggestions from code review --- Emby.Server.Implementations/Library/PathManager.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/PathManager.cs b/Emby.Server.Implementations/Library/PathManager.cs index ac004b4132..83a6df9644 100644 --- a/Emby.Server.Implementations/Library/PathManager.cs +++ b/Emby.Server.Implementations/Library/PathManager.cs @@ -42,15 +42,17 @@ public class PathManager : IPathManager /// public string GetAttachmentFolderPath(string mediaSourceId) { - var id = Guid.Parse(mediaSourceId); - return Path.Join(AttachmentCachePath, id.ToString("D", CultureInfo.InvariantCulture)); + var id = Guid.Parse(mediaSourceId).ToString("D", CultureInfo.InvariantCulture).AsSpan(); + + return Path.Join(AttachmentCachePath, id[..2], id); } /// public string GetSubtitleFolderPath(string mediaSourceId) { - var id = Guid.Parse(mediaSourceId); - return Path.Join(SubtitleCachePath, id.ToString("D", CultureInfo.InvariantCulture)); + var id = Guid.Parse(mediaSourceId).ToString("D", CultureInfo.InvariantCulture).AsSpan(); + + return Path.Join(SubtitleCachePath, id[..2], id); } /// @@ -62,11 +64,10 @@ public class PathManager : IPathManager /// public string GetTrickplayDirectory(BaseItem item, bool saveWithMedia = false) { - var basePath = _config.ApplicationPaths.TrickplayPath; - var idString = item.Id.ToString("D", CultureInfo.InvariantCulture); + var id = item.Id.ToString("D", CultureInfo.InvariantCulture).AsSpan(); return saveWithMedia ? Path.Combine(item.ContainingFolderPath, Path.ChangeExtension(item.Path, ".trickplay")) - : Path.Combine(basePath, idString); + : Path.Join(_config.ApplicationPaths.TrickplayPath, id[..2], id); } } -- cgit v1.2.3 From 32fe92d8f544d6dee1f0dfb5cccada649524084a Mon Sep 17 00:00:00 2001 From: gnattu Date: Wed, 9 Apr 2025 09:22:30 +0800 Subject: Only reselect audio streams when user preference is respected (#13832) --- .../Library/MediaSourceManager.cs | 10 +++++++ Jellyfin.Api/Helpers/MediaInfoHelper.cs | 7 +++++ MediaBrowser.Model/Dlna/StreamBuilder.cs | 32 +++++++++++++++++++--- MediaBrowser.Model/Dto/MediaSourceInfo.cs | 4 +++ MediaBrowser.Model/MediaInfo/AudioIndexSource.cs | 30 ++++++++++++++++++++ 5 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 MediaBrowser.Model/MediaInfo/AudioIndexSource.cs (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index afe5b14e92..c6cfd5391a 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -427,6 +427,7 @@ namespace Emby.Server.Implementations.Library if (source.MediaStreams.Any(i => i.Type == MediaStreamType.Audio && i.Index == index)) { source.DefaultAudioStreamIndex = index; + source.DefaultAudioIndexSource = AudioIndexSource.User; return; } } @@ -434,6 +435,15 @@ namespace Emby.Server.Implementations.Library var preferredAudio = NormalizeLanguage(user.AudioLanguagePreference); source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.PlayDefaultAudioTrack); + if (user.PlayDefaultAudioTrack) + { + source.DefaultAudioIndexSource |= AudioIndexSource.Default; + } + + if (preferredAudio.Count > 0) + { + source.DefaultAudioIndexSource |= AudioIndexSource.Language; + } } public void SetDefaultAudioAndSubtitleStreamIndices(BaseItem item, MediaSourceInfo source, User user) diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs index 63c9c173b9..454d3f08e3 100644 --- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs +++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs @@ -129,6 +129,13 @@ public class MediaInfoHelper var mediaSourcesClone = JsonSerializer.Deserialize(JsonSerializer.SerializeToUtf8Bytes(mediaSources)); if (mediaSourcesClone is not null) { + // Carry over the default audio index source. + // This field is not intended to be exposed to API clients, but it is used internally by the server + for (int i = 0; i < mediaSourcesClone.Length && i < mediaSources.Length; i++) + { + mediaSourcesClone[i].DefaultAudioIndexSource = mediaSources[i].DefaultAudioIndexSource; + } + result.MediaSources = mediaSourcesClone; } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 806900e9ad..61e04a8134 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -665,15 +665,39 @@ namespace MediaBrowser.Model.Dlna // Collect candidate audio streams ICollection candidateAudioStreams = audioStream is null ? [] : [audioStream]; - if (!options.AudioStreamIndex.HasValue || options.AudioStreamIndex < 0) + // When the index is explicitly required by client or the default is specified by user, don't do any stream reselection. + if (!item.DefaultAudioIndexSource.HasFlag(AudioIndexSource.User) && (options.AudioStreamIndex is null or < 0)) { - if (audioStream?.IsDefault == true) + // When user has no preferences allow stream selection on all streams. + if (item.DefaultAudioIndexSource == AudioIndexSource.None && audioStream is not null) { - candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.IsDefault).ToArray(); + candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio).ToArray(); + if (audioStream.IsDefault) + { + // If default is picked, only allow selection within default streams. + candidateAudioStreams = candidateAudioStreams.Where(stream => stream.IsDefault).ToArray(); + } } - else + + if (item.DefaultAudioIndexSource.HasFlag(AudioIndexSource.Language)) { + // If user has language preference, only allow stream selection within the same language. candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.Language == audioStream?.Language).ToArray(); + if (item.DefaultAudioIndexSource.HasFlag(AudioIndexSource.Default)) + { + var defaultStreamsInPreferredLanguage = candidateAudioStreams.Where(stream => stream.IsDefault).ToArray(); + + // If the user also prefers default streams, try limit selection within default tracks in the same language. + // If there is no default stream in the preferred language, allow selection on all default streams to match the "Play default audio track regardless of language" setting. + candidateAudioStreams = defaultStreamsInPreferredLanguage.Length > 0 + ? defaultStreamsInPreferredLanguage + : item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.IsDefault).ToArray(); + } + } + else if (item.DefaultAudioIndexSource.HasFlag(AudioIndexSource.Default)) + { + // If user prefers default streams, only allow stream selection on default streams. + candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.IsDefault).ToArray(); } } diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index 66de18cfe1..75ccdcf276 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -24,6 +24,7 @@ namespace MediaBrowser.Model.Dto SupportsDirectPlay = true; SupportsProbing = true; UseMostCompatibleTranscodingProfile = false; + DefaultAudioIndexSource = AudioIndexSource.None; } public MediaProtocol Protocol { get; set; } @@ -118,6 +119,9 @@ namespace MediaBrowser.Model.Dto [JsonIgnore] public TranscodeReason TranscodeReasons { get; set; } + [JsonIgnore] + public AudioIndexSource DefaultAudioIndexSource { get; set; } + public int? DefaultAudioStreamIndex { get; set; } public int? DefaultSubtitleStreamIndex { get; set; } diff --git a/MediaBrowser.Model/MediaInfo/AudioIndexSource.cs b/MediaBrowser.Model/MediaInfo/AudioIndexSource.cs new file mode 100644 index 0000000000..810087b926 --- /dev/null +++ b/MediaBrowser.Model/MediaInfo/AudioIndexSource.cs @@ -0,0 +1,30 @@ +using System; + +namespace MediaBrowser.Model.MediaInfo; + +/// +/// How is the audio index determined. +/// +[Flags] +public enum AudioIndexSource +{ + /// + /// The default index when no preference is specified. + /// + None = 0, + + /// + /// The index is calculated whether the track is marked as default or not. + /// + Default = 1 << 0, + + /// + /// The index is calculated whether the track is in preferred language or not. + /// + Language = 1 << 1, + + /// + /// The index is specified by the user. + /// + User = 1 << 2 +} -- cgit v1.2.3 From cad8de97018d88ea59c4a5900d0bff9bba73212c Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Thu, 10 Apr 2025 02:40:16 +0200 Subject: Add Genre cleanup and fix cleanup filter queries (#13891) --- .../Library/Validators/GenresValidator.cs | 23 ++++++++++++++++++++++ .../Item/BaseItemRepository.cs | 10 ++++++++-- .../Entities/InternalItemsQuery.cs | 2 ++ 3 files changed, 33 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/Validators/GenresValidator.cs b/Emby.Server.Implementations/Library/Validators/GenresValidator.cs index e59c62e239..d71e91174d 100644 --- a/Emby.Server.Implementations/Library/Validators/GenresValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/GenresValidator.cs @@ -1,6 +1,9 @@ using System; +using System.Globalization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using Microsoft.Extensions.Logging; @@ -75,6 +78,26 @@ namespace Emby.Server.Implementations.Library.Validators progress.Report(percent); } + var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = [BaseItemKind.Genre], + IsDeadGenre = true, + IsLocked = false + }); + + foreach (var item in deadEntities) + { + _logger.LogInformation("Deleting dead {ItemType} {ItemId} {ItemName}", item.GetType().Name, item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name); + + _libraryManager.DeleteItem( + item, + new DeleteOptions + { + DeleteFileLocation = false + }, + false); + } + progress.Report(100); } } diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs index 75334f427b..a569aa09f5 100644 --- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs +++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs @@ -1962,13 +1962,19 @@ public sealed class BaseItemRepository if (filter.IsDeadArtist.HasValue && filter.IsDeadArtist.Value) { baseQuery = baseQuery - .Where(e => e.ItemValues!.Count(f => f.ItemValue.Type == ItemValueType.Artist || f.ItemValue.Type == ItemValueType.AlbumArtist) == 1); + .Where(e => !context.ItemValues.Where(f => _getAllArtistsValueTypes.Contains(f.Type)).Any(f => f.Value == e.Name)); } if (filter.IsDeadStudio.HasValue && filter.IsDeadStudio.Value) { baseQuery = baseQuery - .Where(e => e.ItemValues!.Count(f => f.ItemValue.Type == ItemValueType.Studios) == 1); + .Where(e => !context.ItemValues.Where(f => _getStudiosValueTypes.Contains(f.Type)).Any(f => f.Value == e.Name)); + } + + if (filter.IsDeadGenre.HasValue && filter.IsDeadGenre.Value) + { + baseQuery = baseQuery + .Where(e => !context.ItemValues.Where(f => _getGenreValueTypes.Contains(f.Type)).Any(f => f.Value == e.Name)); } if (filter.IsDeadPerson.HasValue && filter.IsDeadPerson.Value) diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 9a83dba458..d50f3d075c 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -306,6 +306,8 @@ namespace MediaBrowser.Controller.Entities public bool? IsDeadStudio { get; set; } + public bool? IsDeadGenre { get; set; } + public bool? IsDeadPerson { get; set; } /// -- cgit v1.2.3 From 6e9e2f500f18d879a9aec8e0e1b57e858bc320e4 Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Tue, 15 Apr 2025 04:43:38 +0200 Subject: Fix Genre cleanup (#13916) --- .../Library/Validators/GenresValidator.cs | 2 +- MediaBrowser.Controller/Entities/BaseItem.cs | 24 +++++++++------------- 2 files changed, 11 insertions(+), 15 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/Validators/GenresValidator.cs b/Emby.Server.Implementations/Library/Validators/GenresValidator.cs index d71e91174d..364770fcdc 100644 --- a/Emby.Server.Implementations/Library/Validators/GenresValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/GenresValidator.cs @@ -80,7 +80,7 @@ namespace Emby.Server.Implementations.Library.Validators var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery { - IncludeItemTypes = [BaseItemKind.Genre], + IncludeItemTypes = [BaseItemKind.Genre, BaseItemKind.MusicGenre], IsDeadGenre = true, IsLocked = false }); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index d484266726..d1a6b35841 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -52,7 +52,7 @@ namespace MediaBrowser.Controller.Entities /// The supported image extensions. /// public static readonly string[] SupportedImageExtensions - = new[] { ".png", ".jpg", ".jpeg", ".webp", ".tbn", ".gif", ".svg" }; + = [".png", ".jpg", ".jpeg", ".webp", ".tbn", ".gif", ".svg"]; private static readonly List _supportedExtensions = new List(SupportedImageExtensions) { @@ -448,7 +448,7 @@ namespace MediaBrowser.Controller.Entities return Array.Empty(); } - return new[] { Path }; + return [Path]; } } @@ -1984,7 +1984,7 @@ namespace MediaBrowser.Controller.Entities public void RemoveImage(ItemImageInfo image) { - RemoveImages(new[] { image }); + RemoveImages([image]); } public void RemoveImages(IEnumerable deletedImages) @@ -2019,7 +2019,7 @@ namespace MediaBrowser.Controller.Entities continue; } - (deletedImages ??= new List()).Add(imageInfo); + (deletedImages ??= []).Add(imageInfo); } var anyImagesRemoved = deletedImages?.Count > 0; @@ -2222,11 +2222,7 @@ namespace MediaBrowser.Controller.Entities { return new[] { - new FileSystemMetadata - { - FullName = Path, - IsDirectory = IsFolder - } + FileSystem.GetFileSystemInfo(Path) }.Concat(GetLocalMetadataFilesToDelete()); } @@ -2234,7 +2230,7 @@ namespace MediaBrowser.Controller.Entities { if (IsFolder || !IsInMixedFolder) { - return new List(); + return []; } var filename = System.IO.Path.GetFileNameWithoutExtension(Path); @@ -2490,10 +2486,10 @@ namespace MediaBrowser.Controller.Entities protected virtual List GetEtagValues(User user) { - return new List - { + return + [ DateLastSaved.Ticks.ToString(CultureInfo.InvariantCulture) - }; + ]; } public virtual IEnumerable GetAncestorIds() @@ -2513,7 +2509,7 @@ namespace MediaBrowser.Controller.Entities public virtual IEnumerable GetIdsForAncestorQuery() { - return new[] { Id }; + return [Id]; } public virtual double? GetRefreshProgress() -- cgit v1.2.3 From df5671263fc8370ae17b7a5d53f06a86de5cbc93 Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Sat, 26 Apr 2025 14:01:12 +0200 Subject: Merge pull request #13847 from Shadowghost/rework-chapter-management Rework chapter management --- Emby.Server.Implementations/ApplicationHost.cs | 5 +- .../Chapters/ChapterManager.cs | 313 +++++++++++++++++++++ Emby.Server.Implementations/Dto/DtoService.cs | 9 +- Emby.Server.Implementations/Library/PathManager.cs | 20 +- .../MediaEncoder/EncodingManager.cs | 272 ------------------ .../ScheduledTasks/Tasks/ChapterImagesTask.cs | 28 +- .../Item/ChapterRepository.cs | 30 +- .../Chapters/IChapterManager.cs | 55 ++++ .../Chapters/IChapterRepository.cs | 49 ---- MediaBrowser.Controller/Entities/BaseItem.cs | 7 +- MediaBrowser.Controller/IO/IPathManager.cs | 16 +- .../MediaEncoding/IEncodingManager.cs | 28 -- .../Persistence/IChapterRepository.cs | 39 +++ .../MediaInfo/AudioFileProber.cs | 4 - .../MediaInfo/FFProbeVideoInfo.cs | 16 +- MediaBrowser.Providers/MediaInfo/ProbeProvider.cs | 13 +- 16 files changed, 478 insertions(+), 426 deletions(-) create mode 100644 Emby.Server.Implementations/Chapters/ChapterManager.cs delete mode 100644 Emby.Server.Implementations/MediaEncoder/EncodingManager.cs create mode 100644 MediaBrowser.Controller/Chapters/IChapterManager.cs delete mode 100644 MediaBrowser.Controller/Chapters/IChapterRepository.cs delete mode 100644 MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs create mode 100644 MediaBrowser.Controller/Persistence/IChapterRepository.cs (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 5bb75e2b95..7b07243da7 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -15,6 +15,7 @@ using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using Emby.Naming.Common; using Emby.Photos; +using Emby.Server.Implementations.Chapters; using Emby.Server.Implementations.Collections; using Emby.Server.Implementations.Configuration; using Emby.Server.Implementations.Cryptography; @@ -552,7 +553,7 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); @@ -647,7 +648,7 @@ namespace Emby.Server.Implementations BaseItem.ProviderManager = Resolve(); BaseItem.LocalizationManager = Resolve(); BaseItem.ItemRepository = Resolve(); - BaseItem.ChapterRepository = Resolve(); + BaseItem.ChapterManager = Resolve(); BaseItem.FileSystem = Resolve(); BaseItem.UserDataManager = Resolve(); BaseItem.ChannelManager = Resolve(); diff --git a/Emby.Server.Implementations/Chapters/ChapterManager.cs b/Emby.Server.Implementations/Chapters/ChapterManager.cs new file mode 100644 index 0000000000..b4daa2a143 --- /dev/null +++ b/Emby.Server.Implementations/Chapters/ChapterManager.cs @@ -0,0 +1,313 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Extensions; +using MediaBrowser.Controller.Chapters; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.MediaInfo; +using Microsoft.Extensions.Logging; + +namespace Emby.Server.Implementations.Chapters; + +/// +/// The chapter manager. +/// +public class ChapterManager : IChapterManager +{ + private readonly IFileSystem _fileSystem; + private readonly ILogger _logger; + private readonly IMediaEncoder _encoder; + private readonly IChapterRepository _chapterRepository; + private readonly ILibraryManager _libraryManager; + private readonly IPathManager _pathManager; + + /// + /// The first chapter ticks. + /// + private static readonly long _firstChapterTicks = TimeSpan.FromSeconds(15).Ticks; + + /// + /// Initializes a new instance of the class. + /// + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + public ChapterManager( + ILogger logger, + IFileSystem fileSystem, + IMediaEncoder encoder, + IChapterRepository chapterRepository, + ILibraryManager libraryManager, + IPathManager pathManager) + { + _logger = logger; + _fileSystem = fileSystem; + _encoder = encoder; + _chapterRepository = chapterRepository; + _libraryManager = libraryManager; + _pathManager = pathManager; + } + + /// + /// Determines whether [is eligible for chapter image extraction] [the specified video]. + /// + /// The video. + /// The library options for the video. + /// true if [is eligible for chapter image extraction] [the specified video]; otherwise, false. + private bool IsEligibleForChapterImageExtraction(Video video, LibraryOptions libraryOptions) + { + if (video.IsPlaceHolder) + { + return false; + } + + if (libraryOptions is null || !libraryOptions.EnableChapterImageExtraction) + { + return false; + } + + if (video.IsShortcut) + { + return false; + } + + if (!video.IsCompleteMedia) + { + return false; + } + + // Can't extract images if there are no video streams + return video.DefaultVideoStreamIndex.HasValue; + } + + private long GetAverageDurationBetweenChapters(IReadOnlyList chapters) + { + if (chapters.Count < 2) + { + return 0; + } + + long sum = 0; + for (int i = 1; i < chapters.Count; i++) + { + sum += chapters[i].StartPositionTicks - chapters[i - 1].StartPositionTicks; + } + + return sum / chapters.Count; + } + + /// + public async Task RefreshChapterImages(Video video, IDirectoryService directoryService, IReadOnlyList chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken) + { + if (chapters.Count == 0) + { + return true; + } + + var libraryOptions = _libraryManager.GetLibraryOptions(video); + + if (!IsEligibleForChapterImageExtraction(video, libraryOptions)) + { + extractImages = false; + } + + var averageChapterDuration = GetAverageDurationBetweenChapters(chapters); + var threshold = TimeSpan.FromSeconds(1).Ticks; + if (averageChapterDuration < threshold) + { + _logger.LogInformation("Skipping chapter image extraction for {Video} as the average chapter duration {AverageDuration} was lower than the minimum threshold {Threshold}", video.Name, averageChapterDuration, threshold); + extractImages = false; + } + + var success = true; + var changesMade = false; + + var runtimeTicks = video.RunTimeTicks ?? 0; + + var currentImages = GetSavedChapterImages(video, directoryService); + + foreach (var chapter in chapters) + { + if (chapter.StartPositionTicks >= runtimeTicks) + { + _logger.LogInformation("Stopping chapter extraction for {0} because a chapter was found with a position greater than the runtime.", video.Name); + break; + } + + var path = _pathManager.GetChapterImagePath(video, chapter.StartPositionTicks); + + if (!currentImages.Contains(path, StringComparison.OrdinalIgnoreCase)) + { + if (extractImages) + { + cancellationToken.ThrowIfCancellationRequested(); + + try + { + // Add some time for the first chapter to make sure we don't end up with a black image + var time = chapter.StartPositionTicks == 0 ? TimeSpan.FromTicks(Math.Min(_firstChapterTicks, video.RunTimeTicks ?? 0)) : TimeSpan.FromTicks(chapter.StartPositionTicks); + + var inputPath = video.Path; + var directoryPath = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + + var container = video.Container; + var mediaSource = new MediaSourceInfo + { + VideoType = video.VideoType, + IsoType = video.IsoType, + Protocol = video.PathProtocol ?? MediaProtocol.File, + }; + + _logger.LogInformation("Extracting chapter image for {Name} at {Path}", video.Name, inputPath); + var tempFile = await _encoder.ExtractVideoImage(inputPath, container, mediaSource, video.GetDefaultVideoStream(), video.Video3DFormat, time, cancellationToken).ConfigureAwait(false); + File.Copy(tempFile, path, true); + + try + { + _fileSystem.DeleteFile(tempFile); + } + catch (IOException ex) + { + _logger.LogError(ex, "Error deleting temporary chapter image encoding file {Path}", tempFile); + } + + chapter.ImagePath = path; + chapter.ImageDateModified = _fileSystem.GetLastWriteTimeUtc(path); + changesMade = true; + } + catch (Exception ex) + { + _logger.LogError(ex, "Error extracting chapter images for {0}", string.Join(',', video.Path)); + success = false; + break; + } + } + else if (!string.IsNullOrEmpty(chapter.ImagePath)) + { + chapter.ImagePath = null; + changesMade = true; + } + } + else if (!string.Equals(path, chapter.ImagePath, StringComparison.OrdinalIgnoreCase)) + { + chapter.ImagePath = path; + chapter.ImageDateModified = _fileSystem.GetLastWriteTimeUtc(path); + changesMade = true; + } + else if (libraryOptions?.EnableChapterImageExtraction != true) + { + // We have an image for the current chapter but the user has disabled chapter image extraction -> delete this chapter's image + chapter.ImagePath = null; + changesMade = true; + } + } + + if (saveChapters && changesMade) + { + _chapterRepository.SaveChapters(video.Id, chapters); + } + + DeleteDeadImages(currentImages, chapters); + + return success; + } + + /// + public void SaveChapters(Video video, IReadOnlyList chapters) + { + _chapterRepository.SaveChapters(video.Id, chapters); + } + + /// + public ChapterInfo? GetChapter(Guid baseItemId, int index) + { + return _chapterRepository.GetChapter(baseItemId, index); + } + + /// + public IReadOnlyList GetChapters(Guid baseItemId) + { + return _chapterRepository.GetChapters(baseItemId); + } + + /// + public void DeleteChapterImages(Video video) + { + var path = _pathManager.GetChapterImageFolderPath(video); + try + { + if (Directory.Exists(path)) + { + _logger.LogInformation("Removing chapter images for {Name} [{Id}]", video.Name, video.Id); + Directory.Delete(path, true); + } + } + catch (Exception ex) + { + _logger.LogWarning("Failed to remove chapter image folder for {Item}: {Exception}", video.Id, ex); + } + + _chapterRepository.DeleteChapters(video.Id); + } + + private IReadOnlyList GetSavedChapterImages(Video video, IDirectoryService directoryService) + { + var path = _pathManager.GetChapterImageFolderPath(video); + if (!Directory.Exists(path)) + { + return []; + } + + try + { + return directoryService.GetFilePaths(path); + } + catch (IOException) + { + return []; + } + } + + private void DeleteDeadImages(IEnumerable images, IEnumerable chapters) + { + var existingImages = chapters.Select(i => i.ImagePath).Where(i => !string.IsNullOrEmpty(i)); + var deadImages = images + .Except(existingImages, StringComparer.OrdinalIgnoreCase) + .Where(i => BaseItem.SupportedImageExtensions.Contains(Path.GetExtension(i.AsSpan()), StringComparison.OrdinalIgnoreCase)) + .ToList(); + + foreach (var image in deadImages) + { + _logger.LogDebug("Deleting dead chapter image {Path}", image); + + try + { + _fileSystem.DeleteFile(image!); + } + catch (IOException ex) + { + _logger.LogError(ex, "Error deleting {Path}.", image); + } + } + } +} diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 5b0fc9ef3b..9e0a6080d3 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -17,7 +17,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Trickplay; @@ -51,7 +50,7 @@ namespace Emby.Server.Implementations.Dto private readonly Lazy _livetvManagerFactory; private readonly ITrickplayManager _trickplayManager; - private readonly IChapterRepository _chapterRepository; + private readonly IChapterManager _chapterManager; public DtoService( ILogger logger, @@ -64,7 +63,7 @@ namespace Emby.Server.Implementations.Dto IMediaSourceManager mediaSourceManager, Lazy livetvManagerFactory, ITrickplayManager trickplayManager, - IChapterRepository chapterRepository) + IChapterManager chapterManager) { _logger = logger; _libraryManager = libraryManager; @@ -76,7 +75,7 @@ namespace Emby.Server.Implementations.Dto _mediaSourceManager = mediaSourceManager; _livetvManagerFactory = livetvManagerFactory; _trickplayManager = trickplayManager; - _chapterRepository = chapterRepository; + _chapterManager = chapterManager; } private ILiveTvManager LivetvManager => _livetvManagerFactory.Value; @@ -1061,7 +1060,7 @@ namespace Emby.Server.Implementations.Dto if (options.ContainsField(ItemFields.Chapters)) { - dto.Chapters = _chapterRepository.GetChapters(item.Id).ToList(); + dto.Chapters = _chapterManager.GetChapters(item.Id).ToList(); } if (options.ContainsField(ItemFields.Trickplay)) diff --git a/Emby.Server.Implementations/Library/PathManager.cs b/Emby.Server.Implementations/Library/PathManager.cs index 83a6df9644..dbd2333ff3 100644 --- a/Emby.Server.Implementations/Library/PathManager.cs +++ b/Emby.Server.Implementations/Library/PathManager.cs @@ -29,9 +29,9 @@ public class PathManager : IPathManager _appPaths = appPaths; } - private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles"); + private string SubtitleCachePath => Path.Join(_appPaths.DataPath, "subtitles"); - private string AttachmentCachePath => Path.Combine(_appPaths.DataPath, "attachments"); + private string AttachmentCachePath => Path.Join(_appPaths.DataPath, "attachments"); /// public string GetAttachmentPath(string mediaSourceId, string fileName) @@ -67,7 +67,21 @@ public class PathManager : IPathManager var id = item.Id.ToString("D", CultureInfo.InvariantCulture).AsSpan(); return saveWithMedia - ? Path.Combine(item.ContainingFolderPath, Path.ChangeExtension(item.Path, ".trickplay")) + ? Path.Join(item.ContainingFolderPath, Path.ChangeExtension(item.Path, ".trickplay")) : Path.Join(_config.ApplicationPaths.TrickplayPath, id[..2], id); } + + /// + public string GetChapterImageFolderPath(BaseItem item) + { + return Path.Join(item.GetInternalMetadataPath(), "chapters"); + } + + /// + public string GetChapterImagePath(BaseItem item, long chapterPositionTicks) + { + var filename = item.DateModified.Ticks.ToString(CultureInfo.InvariantCulture) + "_" + chapterPositionTicks.ToString(CultureInfo.InvariantCulture) + ".jpg"; + + return Path.Join(GetChapterImageFolderPath(item), filename); + } } diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs deleted file mode 100644 index ea78968617..0000000000 --- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs +++ /dev/null @@ -1,272 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Jellyfin.Extensions; -using MediaBrowser.Controller.Chapters; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using Microsoft.Extensions.Logging; - -namespace Emby.Server.Implementations.MediaEncoder -{ - public class EncodingManager : IEncodingManager - { - private readonly IFileSystem _fileSystem; - private readonly ILogger _logger; - private readonly IMediaEncoder _encoder; - private readonly IChapterRepository _chapterManager; - private readonly ILibraryManager _libraryManager; - - /// - /// The first chapter ticks. - /// - private static readonly long _firstChapterTicks = TimeSpan.FromSeconds(15).Ticks; - - public EncodingManager( - ILogger logger, - IFileSystem fileSystem, - IMediaEncoder encoder, - IChapterRepository chapterManager, - ILibraryManager libraryManager) - { - _logger = logger; - _fileSystem = fileSystem; - _encoder = encoder; - _chapterManager = chapterManager; - _libraryManager = libraryManager; - } - - /// - /// Gets the chapter images data path. - /// - /// The chapter images data path. - private static string GetChapterImagesPath(BaseItem item) - { - return Path.Combine(item.GetInternalMetadataPath(), "chapters"); - } - - /// - /// Determines whether [is eligible for chapter image extraction] [the specified video]. - /// - /// The video. - /// The library options for the video. - /// true if [is eligible for chapter image extraction] [the specified video]; otherwise, false. - private bool IsEligibleForChapterImageExtraction(Video video, LibraryOptions libraryOptions) - { - if (video.IsPlaceHolder) - { - return false; - } - - if (libraryOptions is null || !libraryOptions.EnableChapterImageExtraction) - { - return false; - } - - if (video.IsShortcut) - { - return false; - } - - if (!video.IsCompleteMedia) - { - return false; - } - - // Can't extract images if there are no video streams - return video.DefaultVideoStreamIndex.HasValue; - } - - private long GetAverageDurationBetweenChapters(IReadOnlyList chapters) - { - if (chapters.Count < 2) - { - return 0; - } - - long sum = 0; - for (int i = 1; i < chapters.Count; i++) - { - sum += chapters[i].StartPositionTicks - chapters[i - 1].StartPositionTicks; - } - - return sum / chapters.Count; - } - - public async Task RefreshChapterImages(Video video, IDirectoryService directoryService, IReadOnlyList chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken) - { - if (chapters.Count == 0) - { - return true; - } - - var libraryOptions = _libraryManager.GetLibraryOptions(video); - - if (!IsEligibleForChapterImageExtraction(video, libraryOptions)) - { - extractImages = false; - } - - var averageChapterDuration = GetAverageDurationBetweenChapters(chapters); - var threshold = TimeSpan.FromSeconds(1).Ticks; - if (averageChapterDuration < threshold) - { - _logger.LogInformation("Skipping chapter image extraction for {Video} as the average chapter duration {AverageDuration} was lower than the minimum threshold {Threshold}", video.Name, averageChapterDuration, threshold); - extractImages = false; - } - - var success = true; - var changesMade = false; - - var runtimeTicks = video.RunTimeTicks ?? 0; - - var currentImages = GetSavedChapterImages(video, directoryService); - - foreach (var chapter in chapters) - { - if (chapter.StartPositionTicks >= runtimeTicks) - { - _logger.LogInformation("Stopping chapter extraction for {0} because a chapter was found with a position greater than the runtime.", video.Name); - break; - } - - var path = GetChapterImagePath(video, chapter.StartPositionTicks); - - if (!currentImages.Contains(path, StringComparison.OrdinalIgnoreCase)) - { - if (extractImages) - { - cancellationToken.ThrowIfCancellationRequested(); - - try - { - // Add some time for the first chapter to make sure we don't end up with a black image - var time = chapter.StartPositionTicks == 0 ? TimeSpan.FromTicks(Math.Min(_firstChapterTicks, video.RunTimeTicks ?? 0)) : TimeSpan.FromTicks(chapter.StartPositionTicks); - - var inputPath = video.Path; - - Directory.CreateDirectory(Path.GetDirectoryName(path)); - - var container = video.Container; - var mediaSource = new MediaSourceInfo - { - VideoType = video.VideoType, - IsoType = video.IsoType, - Protocol = video.PathProtocol.Value, - }; - - var tempFile = await _encoder.ExtractVideoImage(inputPath, container, mediaSource, video.GetDefaultVideoStream(), video.Video3DFormat, time, cancellationToken).ConfigureAwait(false); - File.Copy(tempFile, path, true); - - try - { - _fileSystem.DeleteFile(tempFile); - } - catch (IOException ex) - { - _logger.LogError(ex, "Error deleting temporary chapter image encoding file {Path}", tempFile); - } - - chapter.ImagePath = path; - chapter.ImageDateModified = _fileSystem.GetLastWriteTimeUtc(path); - changesMade = true; - } - catch (Exception ex) - { - _logger.LogError(ex, "Error extracting chapter images for {0}", string.Join(',', video.Path)); - success = false; - break; - } - } - else if (!string.IsNullOrEmpty(chapter.ImagePath)) - { - chapter.ImagePath = null; - changesMade = true; - } - } - else if (!string.Equals(path, chapter.ImagePath, StringComparison.OrdinalIgnoreCase)) - { - chapter.ImagePath = path; - chapter.ImageDateModified = _fileSystem.GetLastWriteTimeUtc(path); - changesMade = true; - } - else if (libraryOptions?.EnableChapterImageExtraction != true) - { - // We have an image for the current chapter but the user has disabled chapter image extraction -> delete this chapter's image - chapter.ImagePath = null; - changesMade = true; - } - } - - if (saveChapters && changesMade) - { - _chapterManager.SaveChapters(video.Id, chapters); - } - - DeleteDeadImages(currentImages, chapters); - - return success; - } - - private string GetChapterImagePath(Video video, long chapterPositionTicks) - { - var filename = video.DateModified.Ticks.ToString(CultureInfo.InvariantCulture) + "_" + chapterPositionTicks.ToString(CultureInfo.InvariantCulture) + ".jpg"; - - return Path.Combine(GetChapterImagesPath(video), filename); - } - - private static IReadOnlyList GetSavedChapterImages(Video video, IDirectoryService directoryService) - { - var path = GetChapterImagesPath(video); - if (!Directory.Exists(path)) - { - return Array.Empty(); - } - - try - { - return directoryService.GetFilePaths(path); - } - catch (IOException) - { - return Array.Empty(); - } - } - - private void DeleteDeadImages(IEnumerable images, IEnumerable chapters) - { - var deadImages = images - .Except(chapters.Select(i => i.ImagePath).Where(i => !string.IsNullOrEmpty(i)), StringComparer.OrdinalIgnoreCase) - .Where(i => BaseItem.SupportedImageExtensions.Contains(Path.GetExtension(i.AsSpan()), StringComparison.OrdinalIgnoreCase)) - .ToList(); - - foreach (var image in deadImages) - { - _logger.LogDebug("Deleting dead chapter image {Path}", image); - - try - { - _fileSystem.DeleteFile(image); - } - catch (IOException ex) - { - _logger.LogError(ex, "Error deleting {Path}.", image); - } - } - } - } -} diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs index 563e90fbea..b76fdeeb04 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs @@ -11,8 +11,6 @@ using MediaBrowser.Controller.Chapters; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; @@ -28,42 +26,34 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks { private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; - private readonly IItemRepository _itemRepo; private readonly IApplicationPaths _appPaths; - private readonly IEncodingManager _encodingManager; + private readonly IChapterManager _chapterManager; private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; - private readonly IChapterRepository _chapterRepository; /// /// Initializes a new instance of the class. /// /// 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. /// Instance of the interface. - /// Instance of the interface. public ChapterImagesTask( ILogger logger, ILibraryManager libraryManager, - IItemRepository itemRepo, IApplicationPaths appPaths, - IEncodingManager encodingManager, + IChapterManager chapterManager, IFileSystem fileSystem, - ILocalizationManager localization, - IChapterRepository chapterRepository) + ILocalizationManager localization) { _logger = logger; _libraryManager = libraryManager; - _itemRepo = itemRepo; _appPaths = appPaths; - _encodingManager = encodingManager; + _chapterManager = chapterManager; _fileSystem = fileSystem; _localization = localization; - _chapterRepository = chapterRepository; } /// @@ -126,12 +116,12 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks } catch (IOException) { - previouslyFailedImages = new List(); + previouslyFailedImages = []; } } else { - previouslyFailedImages = new List(); + previouslyFailedImages = []; } var directoryService = new DirectoryService(_fileSystem); @@ -146,9 +136,9 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks try { - var chapters = _chapterRepository.GetChapters(video.Id); + var chapters = _chapterManager.GetChapters(video.Id); - var success = await _encodingManager.RefreshChapterImages(video, directoryService, chapters, extract, true, cancellationToken).ConfigureAwait(false); + var success = await _chapterManager.RefreshChapterImages(video, directoryService, chapters, extract, true, cancellationToken).ConfigureAwait(false); if (!success) { diff --git a/Jellyfin.Server.Implementations/Item/ChapterRepository.cs b/Jellyfin.Server.Implementations/Item/ChapterRepository.cs index 93e15735c9..9f2d473468 100644 --- a/Jellyfin.Server.Implementations/Item/ChapterRepository.cs +++ b/Jellyfin.Server.Implementations/Item/ChapterRepository.cs @@ -1,12 +1,10 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using Jellyfin.Database.Implementations; using Jellyfin.Database.Implementations.Entities; -using MediaBrowser.Controller.Chapters; using MediaBrowser.Controller.Drawing; -using MediaBrowser.Model.Dto; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using Microsoft.EntityFrameworkCore; @@ -31,19 +29,7 @@ public class ChapterRepository : IChapterRepository _imageProcessor = imageProcessor; } - /// - public ChapterInfo? GetChapter(BaseItemDto baseItem, int index) - { - return GetChapter(baseItem.Id, index); - } - - /// - public IReadOnlyList GetChapters(BaseItemDto baseItem) - { - return GetChapters(baseItem.Id); - } - - /// + /// public ChapterInfo? GetChapter(Guid baseItemId, int index) { using var context = _dbProvider.CreateDbContext(); @@ -62,7 +48,7 @@ public class ChapterRepository : IChapterRepository return null; } - /// + /// public IReadOnlyList GetChapters(Guid baseItemId) { using var context = _dbProvider.CreateDbContext(); @@ -77,7 +63,7 @@ public class ChapterRepository : IChapterRepository .ToArray(); } - /// + /// public void SaveChapters(Guid itemId, IReadOnlyList chapters) { using var context = _dbProvider.CreateDbContext(); @@ -95,6 +81,14 @@ public class ChapterRepository : IChapterRepository } } + /// + public void DeleteChapters(Guid itemId) + { + using var context = _dbProvider.CreateDbContext(); + context.Chapters.Where(c => c.ItemId.Equals(itemId)).ExecuteDelete(); + context.SaveChanges(); + } + private Chapter Map(ChapterInfo chapterInfo, int index, Guid itemId) { return new Chapter() diff --git a/MediaBrowser.Controller/Chapters/IChapterManager.cs b/MediaBrowser.Controller/Chapters/IChapterManager.cs new file mode 100644 index 0000000000..7532e56c60 --- /dev/null +++ b/MediaBrowser.Controller/Chapters/IChapterManager.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; + +namespace MediaBrowser.Controller.Chapters; + +/// +/// Interface IChapterManager. +/// +public interface IChapterManager +{ + /// + /// Saves the chapters. + /// + /// The video. + /// The set of chapters. + void SaveChapters(Video video, IReadOnlyList chapters); + + /// + /// Gets a single chapter of a BaseItem on a specific index. + /// + /// The BaseItems id. + /// The index of that chapter. + /// A chapter instance. + ChapterInfo? GetChapter(Guid baseItemId, int index); + + /// + /// Gets all chapters associated with the baseItem. + /// + /// The BaseItems id. + /// A readonly list of chapter instances. + IReadOnlyList GetChapters(Guid baseItemId); + + /// + /// Refreshes the chapter images. + /// + /// Video to use. + /// Directory service to use. + /// Set of chapters to refresh. + /// Option to extract images. + /// Option to save chapters. + /// CancellationToken to use for operation. + /// true if successful, false if not. + Task RefreshChapterImages(Video video, IDirectoryService directoryService, IReadOnlyList chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken); + + /// + /// Deletes the chapter images. + /// + /// Video to use. + void DeleteChapterImages(Video video); +} diff --git a/MediaBrowser.Controller/Chapters/IChapterRepository.cs b/MediaBrowser.Controller/Chapters/IChapterRepository.cs deleted file mode 100644 index e22cb0f584..0000000000 --- a/MediaBrowser.Controller/Chapters/IChapterRepository.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Entities; - -namespace MediaBrowser.Controller.Chapters; - -/// -/// Interface IChapterManager. -/// -public interface IChapterRepository -{ - /// - /// Saves the chapters. - /// - /// The item. - /// The set of chapters. - void SaveChapters(Guid itemId, IReadOnlyList chapters); - - /// - /// Gets all chapters associated with the baseItem. - /// - /// The baseitem. - /// A readonly list of chapter instances. - IReadOnlyList GetChapters(BaseItemDto baseItem); - - /// - /// Gets a single chapter of a BaseItem on a specific index. - /// - /// The baseitem. - /// The index of that chapter. - /// A chapter instance. - ChapterInfo? GetChapter(BaseItemDto baseItem, int index); - - /// - /// Gets all chapters associated with the baseItem. - /// - /// The BaseItems id. - /// A readonly list of chapter instances. - IReadOnlyList GetChapters(Guid baseItemId); - - /// - /// Gets a single chapter of a BaseItem on a specific index. - /// - /// The BaseItems id. - /// The index of that chapter. - /// A chapter instance. - ChapterInfo? GetChapter(Guid baseItemId, int index); -} diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index d1a6b35841..a7ff75bb1c 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -34,7 +34,6 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.Library; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.Providers; using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Entities @@ -484,7 +483,7 @@ namespace MediaBrowser.Controller.Entities public static IItemRepository ItemRepository { get; set; } - public static IChapterRepository ChapterRepository { get; set; } + public static IChapterManager ChapterManager { get; set; } public static IFileSystem FileSystem { get; set; } @@ -2051,7 +2050,7 @@ namespace MediaBrowser.Controller.Entities { if (imageType == ImageType.Chapter) { - var chapter = ChapterRepository.GetChapter(this.Id, imageIndex); + var chapter = ChapterManager.GetChapter(Id, imageIndex); if (chapter is null) { @@ -2101,7 +2100,7 @@ namespace MediaBrowser.Controller.Entities if (image.Type == ImageType.Chapter) { - var chapters = ChapterRepository.GetChapters(this.Id); + var chapters = ChapterManager.GetChapters(Id); for (var i = 0; i < chapters.Count; i++) { if (chapters[i].ImagePath == image.Path) diff --git a/MediaBrowser.Controller/IO/IPathManager.cs b/MediaBrowser.Controller/IO/IPathManager.cs index 7c20164a6f..4e4eb514e6 100644 --- a/MediaBrowser.Controller/IO/IPathManager.cs +++ b/MediaBrowser.Controller/IO/IPathManager.cs @@ -1,5 +1,4 @@ using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Dto; namespace MediaBrowser.Controller.IO; @@ -46,4 +45,19 @@ public interface IPathManager /// The media source id. /// The absolute path. public string GetAttachmentFolderPath(string mediaSourceId); + + /// + /// Gets the chapter images data path. + /// + /// The base item. + /// The chapter images data path. + public string GetChapterImageFolderPath(BaseItem item); + + /// + /// Gets the chapter images path. + /// + /// The base item. + /// The chapter position. + /// The chapter images data path. + public string GetChapterImagePath(BaseItem item, long chapterPositionTicks); } diff --git a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs deleted file mode 100644 index 8ce40a58d1..0000000000 --- a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs +++ /dev/null @@ -1,28 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; - -namespace MediaBrowser.Controller.MediaEncoding -{ - public interface IEncodingManager - { - /// - /// Refreshes the chapter images. - /// - /// Video to use. - /// Directory service to use. - /// Set of chapters to refresh. - /// Option to extract images. - /// Option to save chapters. - /// CancellationToken to use for operation. - /// true if successful, false if not. - Task RefreshChapterImages(Video video, IDirectoryService directoryService, IReadOnlyList chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken); - } -} diff --git a/MediaBrowser.Controller/Persistence/IChapterRepository.cs b/MediaBrowser.Controller/Persistence/IChapterRepository.cs new file mode 100644 index 0000000000..0844ddb364 --- /dev/null +++ b/MediaBrowser.Controller/Persistence/IChapterRepository.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using MediaBrowser.Model.Entities; + +namespace MediaBrowser.Controller.Persistence; + +/// +/// Interface IChapterRepository. +/// +public interface IChapterRepository +{ + /// + /// Deletes the chapters. + /// + /// The item. + void DeleteChapters(Guid itemId); + + /// + /// Saves the chapters. + /// + /// The item. + /// The set of chapters. + void SaveChapters(Guid itemId, IReadOnlyList chapters); + + /// + /// Gets all chapters associated with the baseItem. + /// + /// The BaseItems id. + /// A readonly list of chapter instances. + IReadOnlyList GetChapters(Guid baseItemId); + + /// + /// Gets a single chapter of a BaseItem on a specific index. + /// + /// The BaseItems id. + /// The index of that chapter. + /// A chapter instance. + ChapterInfo? GetChapter(Guid baseItemId, int index); +} diff --git a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs index 0bb21b2878..286ba0de0d 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs @@ -32,7 +32,6 @@ namespace MediaBrowser.Providers.MediaInfo private const char InternalValueSeparator = '\u001F'; private readonly IMediaEncoder _mediaEncoder; - private readonly IItemRepository _itemRepo; private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; private readonly IMediaSourceManager _mediaSourceManager; @@ -46,7 +45,6 @@ namespace MediaBrowser.Providers.MediaInfo /// 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. @@ -55,14 +53,12 @@ namespace MediaBrowser.Providers.MediaInfo ILogger logger, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, - IItemRepository itemRepo, ILibraryManager libraryManager, LyricResolver lyricResolver, ILyricManager lyricManager, IMediaStreamRepository mediaStreamRepository) { _mediaEncoder = mediaEncoder; - _itemRepo = itemRepo; _libraryManager = libraryManager; _logger = logger; _mediaSourceManager = mediaSourceManager; diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 266e1861f9..7947ba9218 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -34,13 +34,11 @@ namespace MediaBrowser.Providers.MediaInfo private readonly ILogger _logger; private readonly IMediaSourceManager _mediaSourceManager; private readonly IMediaEncoder _mediaEncoder; - private readonly IItemRepository _itemRepo; private readonly IBlurayExaminer _blurayExaminer; private readonly ILocalizationManager _localization; - private readonly IEncodingManager _encodingManager; + private readonly IChapterManager _chapterManager; private readonly IServerConfigurationManager _config; private readonly ISubtitleManager _subtitleManager; - private readonly IChapterRepository _chapterManager; private readonly ILibraryManager _libraryManager; private readonly AudioResolver _audioResolver; private readonly SubtitleResolver _subtitleResolver; @@ -51,13 +49,11 @@ namespace MediaBrowser.Providers.MediaInfo ILogger logger, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, - IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, - IEncodingManager encodingManager, + IChapterManager chapterManager, IServerConfigurationManager config, ISubtitleManager subtitleManager, - IChapterRepository chapterManager, ILibraryManager libraryManager, AudioResolver audioResolver, SubtitleResolver subtitleResolver, @@ -67,13 +63,11 @@ namespace MediaBrowser.Providers.MediaInfo _logger = logger; _mediaSourceManager = mediaSourceManager; _mediaEncoder = mediaEncoder; - _itemRepo = itemRepo; _blurayExaminer = blurayExaminer; _localization = localization; - _encodingManager = encodingManager; + _chapterManager = chapterManager; _config = config; _subtitleManager = subtitleManager; - _chapterManager = chapterManager; _libraryManager = libraryManager; _audioResolver = audioResolver; _subtitleResolver = subtitleResolver; @@ -298,9 +292,9 @@ namespace MediaBrowser.Providers.MediaInfo extractDuringScan = libraryOptions.ExtractChapterImagesDuringLibraryScan; } - await _encodingManager.RefreshChapterImages(video, options.DirectoryService, chapters, extractDuringScan, false, cancellationToken).ConfigureAwait(false); + await _chapterManager.RefreshChapterImages(video, options.DirectoryService, chapters, extractDuringScan, false, cancellationToken).ConfigureAwait(false); - _chapterManager.SaveChapters(video.Id, chapters); + _chapterManager.SaveChapters(video, chapters); } } diff --git a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs index 1c2f8b9134..ba6034ec12 100644 --- a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs @@ -55,13 +55,11 @@ namespace MediaBrowser.Providers.MediaInfo /// /// 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. /// Instance of the interface. /// Instance of the interface. - /// Instance of the interface. /// Instance of the interface. /// Instance of the . /// Instance of the interface. @@ -72,13 +70,11 @@ namespace MediaBrowser.Providers.MediaInfo public ProbeProvider( IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, - IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, - IEncodingManager encodingManager, + IChapterManager chapterManager, IServerConfigurationManager config, ISubtitleManager subtitleManager, - IChapterRepository chapterManager, ILibraryManager libraryManager, IFileSystem fileSystem, ILoggerFactory loggerFactory, @@ -96,13 +92,11 @@ namespace MediaBrowser.Providers.MediaInfo loggerFactory.CreateLogger(), mediaSourceManager, mediaEncoder, - itemRepo, blurayExaminer, localization, - encodingManager, + chapterManager, config, subtitleManager, - chapterManager, libraryManager, _audioResolver, _subtitleResolver, @@ -113,7 +107,6 @@ namespace MediaBrowser.Providers.MediaInfo loggerFactory.CreateLogger(), mediaSourceManager, mediaEncoder, - itemRepo, libraryManager, _lyricResolver, lyricManager, -- cgit v1.2.3 From 8ee358de2ca956d22c14f28c3783ba99acd87a32 Mon Sep 17 00:00:00 2001 From: JPVenson Date: Sat, 26 Apr 2025 18:30:25 +0300 Subject: Check for path overlaps (#12832) --- .../AppBase/BaseApplicationPaths.cs | 45 +++++++++++++++++++++- .../AppBase/BaseConfigurationManager.cs | 1 + .../Library/LibraryManager.cs | 2 - .../ServerApplicationPaths.cs | 7 ++++ Jellyfin.Server/Program.cs | 1 + .../EncodingConfigurationExtensions.cs | 3 +- .../Configuration/IApplicationPaths.cs | 13 +++++++ MediaBrowser.Controller/IServerApplicationPaths.cs | 4 ++ 8 files changed, 71 insertions(+), 5 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs index f0cca9efd0..d1376f18ad 100644 --- a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs +++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using MediaBrowser.Common.Configuration; namespace Emby.Server.Implementations.AppBase @@ -30,7 +32,6 @@ namespace Emby.Server.Implementations.AppBase ConfigurationDirectoryPath = configurationDirectoryPath; CachePath = cacheDirectoryPath; WebPath = webDirectoryPath; - DataPath = Directory.CreateDirectory(Path.Combine(ProgramDataPath, "data")).FullName; } @@ -75,5 +76,47 @@ namespace Emby.Server.Implementations.AppBase /// public string TrickplayPath => Path.Combine(DataPath, "trickplay"); + + /// + public virtual void MakeSanityCheckOrThrow() + { + CreateAndCheckMarker(ConfigurationDirectoryPath, "config"); + CreateAndCheckMarker(LogDirectoryPath, "log"); + CreateAndCheckMarker(PluginsPath, "plugin"); + CreateAndCheckMarker(ProgramDataPath, "data"); + CreateAndCheckMarker(CachePath, "cache"); + CreateAndCheckMarker(DataPath, "data"); + } + + /// + public void CreateAndCheckMarker(string path, string markerName, bool recursive = false) + { + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + + CheckOrCreateMarker(path, $".jellyfin-{markerName}", recursive); + } + + private IEnumerable GetMarkers(string path, bool recursive = false) + { + return Directory.EnumerateFiles(path, ".jellyfin-*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); + } + + private void CheckOrCreateMarker(string path, string markerName, bool recursive = false) + { + var otherMarkers = GetMarkers(path, recursive).FirstOrDefault(e => Path.GetFileName(e) != markerName); + if (otherMarkers != null) + { + throw new InvalidOperationException($"Exepected to find only {markerName} but found marker for {otherMarkers}."); + } + + var markerPath = Path.Combine(path, markerName); + if (!File.Exists(markerPath)) + { + File.Create(markerPath).Dispose(); + } + } } } diff --git a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs index 9bc3a0204b..81ef0e5f9a 100644 --- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs +++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs @@ -227,6 +227,7 @@ namespace Emby.Server.Implementations.AppBase Logger.LogInformation("Setting cache path: {Path}", cachePath); ((BaseApplicationPaths)CommonApplicationPaths).CachePath = cachePath; + CommonApplicationPaths.CreateAndCheckMarker(((BaseApplicationPaths)CommonApplicationPaths).CachePath, "cache"); } /// diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 40045782b6..a6eddbbc3b 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -768,8 +768,6 @@ namespace Emby.Server.Implementations.Library { var rootFolderPath = _configurationManager.ApplicationPaths.RootFolderPath; - Directory.CreateDirectory(rootFolderPath); - var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath)) as Folder ?? throw new InvalidOperationException("Something went very wong")) .DeepCopy(); diff --git a/Emby.Server.Implementations/ServerApplicationPaths.cs b/Emby.Server.Implementations/ServerApplicationPaths.cs index 725df98da5..f049e66475 100644 --- a/Emby.Server.Implementations/ServerApplicationPaths.cs +++ b/Emby.Server.Implementations/ServerApplicationPaths.cs @@ -96,5 +96,12 @@ namespace Emby.Server.Implementations /// public string VirtualInternalMetadataPath => "%MetadataPath%"; + + /// + public override void MakeSanityCheckOrThrow() + { + base.MakeSanityCheckOrThrow(); + CreateAndCheckMarker(RootFolderPath, "root"); + } } } diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 8d0bf73f6a..511306755b 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -77,6 +77,7 @@ namespace Jellyfin.Server { _startTimestamp = Stopwatch.GetTimestamp(); ServerApplicationPaths appPaths = StartupHelpers.CreateApplicationPaths(options); + appPaths.MakeSanityCheckOrThrow(); // $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager Environment.SetEnvironmentVariable("JELLYFIN_LOG_DIR", appPaths.LogDirectoryPath); diff --git a/MediaBrowser.Common/Configuration/EncodingConfigurationExtensions.cs b/MediaBrowser.Common/Configuration/EncodingConfigurationExtensions.cs index 70a4fe4098..78e96ab47c 100644 --- a/MediaBrowser.Common/Configuration/EncodingConfigurationExtensions.cs +++ b/MediaBrowser.Common/Configuration/EncodingConfigurationExtensions.cs @@ -35,8 +35,7 @@ namespace MediaBrowser.Common.Configuration transcodingTempPath = Path.Combine(configurationManager.CommonApplicationPaths.CachePath, "transcodes"); } - // Make sure the directory exists - Directory.CreateDirectory(transcodingTempPath); + configurationManager.CommonApplicationPaths.CreateAndCheckMarker(transcodingTempPath, "transcode", true); return transcodingTempPath; } } diff --git a/MediaBrowser.Common/Configuration/IApplicationPaths.cs b/MediaBrowser.Common/Configuration/IApplicationPaths.cs index 7a8ab32361..fa0d8247b4 100644 --- a/MediaBrowser.Common/Configuration/IApplicationPaths.cs +++ b/MediaBrowser.Common/Configuration/IApplicationPaths.cs @@ -90,5 +90,18 @@ namespace MediaBrowser.Common.Configuration /// /// The trickplay path. string TrickplayPath { get; } + + /// + /// Checks and creates all known base paths. + /// + void MakeSanityCheckOrThrow(); + + /// + /// Checks and creates the given path and adds it with a marker file if non existant. + /// + /// The path to check. + /// The common marker file name. + /// Check for other settings paths recursivly. + void CreateAndCheckMarker(string path, string markerName, bool recursive = false); } } diff --git a/MediaBrowser.Controller/IServerApplicationPaths.cs b/MediaBrowser.Controller/IServerApplicationPaths.cs index 608286cd8a..a6e83a02c7 100644 --- a/MediaBrowser.Controller/IServerApplicationPaths.cs +++ b/MediaBrowser.Controller/IServerApplicationPaths.cs @@ -2,6 +2,10 @@ #pragma warning disable CS1591 +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; using MediaBrowser.Common.Configuration; namespace MediaBrowser.Controller -- cgit v1.2.3 From a0b3b7335fccf028701e94af31028184bfd4e6cb Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Sat, 26 Apr 2025 17:35:57 +0200 Subject: Add .gitignore style ignoring (#13906) --- Directory.Packages.props | 3 +- .../Emby.Server.Implementations.csproj | 4 ++ .../Library/CoreResolutionIgnoreRule.cs | 4 +- .../Library/DotIgnoreIgnoreRule.cs | 77 ++++++++++++++++++++++ .../Library/IgnorePatterns.cs | 1 - .../Library/LibraryManager.cs | 24 +++---- .../Library/DotIgnoreIgnoreRuleTest.cs | 30 +++++++++ 7 files changed, 123 insertions(+), 20 deletions(-) create mode 100644 Emby.Server.Implementations/Library/DotIgnoreIgnoreRule.cs create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Library/DotIgnoreIgnoreRuleTest.cs (limited to 'Emby.Server.Implementations/Library') diff --git a/Directory.Packages.props b/Directory.Packages.props index cdce608d9c..a24b081dd2 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -21,6 +21,7 @@ + @@ -88,4 +89,4 @@ - \ No newline at end of file + diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index d99923b4fc..15843730e9 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -64,6 +64,10 @@ + + + + diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index b01fd93a7b..f29a0b3ad7 100644 --- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.Library { if (parent is not null) { - // Ignore extras folders but allow it at the collection level + // Ignore extras for unsupported types if (_namingOptions.AllExtrasTypesFolderNames.ContainsKey(filename) && parent is not AggregateFolder && parent is not UserRootFolder) @@ -67,7 +67,7 @@ namespace Emby.Server.Implementations.Library { if (parent is not null) { - // Don't resolve these into audio files + // Don't resolve theme songs if (Path.GetFileNameWithoutExtension(filename.AsSpan()).Equals(BaseItem.ThemeSongFileName, StringComparison.Ordinal) && AudioFileParser.IsAudioFile(filename, _namingOptions)) { diff --git a/Emby.Server.Implementations/Library/DotIgnoreIgnoreRule.cs b/Emby.Server.Implementations/Library/DotIgnoreIgnoreRule.cs new file mode 100644 index 0000000000..2c186c9173 --- /dev/null +++ b/Emby.Server.Implementations/Library/DotIgnoreIgnoreRule.cs @@ -0,0 +1,77 @@ +using System; +using System.IO; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Resolvers; +using MediaBrowser.Model.IO; + +namespace Emby.Server.Implementations.Library; + +/// +/// Resolver rule class for ignoring files via .ignore. +/// +public class DotIgnoreIgnoreRule : IResolverIgnoreRule +{ + private static FileInfo? FindIgnoreFile(DirectoryInfo directory) + { + var ignoreFile = new FileInfo(Path.Join(directory.FullName, ".ignore")); + if (ignoreFile.Exists) + { + return ignoreFile; + } + + var parentDir = directory.Parent; + if (parentDir == null || parentDir.FullName == directory.FullName) + { + return null; + } + + return FindIgnoreFile(parentDir); + } + + /// + public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem? parent) + { + return IsIgnored(fileInfo, parent); + } + + /// + /// Checks whether or not the file is ignored. + /// + /// The file information. + /// The parent BaseItem. + /// True if the file should be ignored. + public static bool IsIgnored(FileSystemMetadata fileInfo, BaseItem? parent) + { + var parentDirPath = Path.GetDirectoryName(fileInfo.FullName); + if (string.IsNullOrEmpty(parentDirPath)) + { + return false; + } + + var folder = new DirectoryInfo(parentDirPath); + var ignoreFile = FindIgnoreFile(folder); + if (ignoreFile is null) + { + return false; + } + + string ignoreFileString; + using (var reader = ignoreFile.OpenText()) + { + ignoreFileString = reader.ReadToEnd(); + } + + if (string.IsNullOrEmpty(ignoreFileString)) + { + // Ignore directory if we just have the file + return true; + } + + // If file has content, base ignoring off the content .gitignore-style rules + var ignoreRules = ignoreFileString.Split('\n', StringSplitOptions.RemoveEmptyEntries); + var ignore = new Ignore.Ignore(); + ignore.Add(ignoreRules); + + return ignore.IsIgnored(fileInfo.FullName); + } +} diff --git a/Emby.Server.Implementations/Library/IgnorePatterns.cs b/Emby.Server.Implementations/Library/IgnorePatterns.cs index bb45dd87e9..25ddade829 100644 --- a/Emby.Server.Implementations/Library/IgnorePatterns.cs +++ b/Emby.Server.Implementations/Library/IgnorePatterns.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using DotNet.Globbing; namespace Emby.Server.Implementations.Library diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index a6eddbbc3b..21c953fb2d 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -649,10 +649,11 @@ namespace Emby.Server.Implementations.Library args.FileSystemChildren = files; } - // Check to see if we should resolve based on our contents - if (args.IsDirectory && !ShouldResolvePathContents(args)) + // Filter content based on ignore rules + if (args.IsDirectory) { - return null; + var filtered = args.GetActualFileSystemChildren().ToArray(); + args.FileSystemChildren = filtered ?? []; } return ResolveItem(args, resolvers); @@ -683,17 +684,6 @@ namespace Emby.Server.Implementations.Library return newList; } - /// - /// Determines whether a path should be ignored based on its contents - called after the contents have been read. - /// - /// The args. - /// true if XXXX, false otherwise. - private static bool ShouldResolvePathContents(ItemResolveArgs args) - { - // Ignore any folders containing a file called .ignore - return !args.ContainsFileSystemEntryByName(".ignore"); - } - public IEnumerable ResolvePaths(IEnumerable files, IDirectoryService directoryService, Folder parent, LibraryOptions libraryOptions, CollectionType? collectionType = null) { return ResolvePaths(files, directoryService, parent, libraryOptions, collectionType, EntityResolvers); @@ -2724,16 +2714,18 @@ namespace Emby.Server.Implementations.Library public IEnumerable FindExtras(BaseItem owner, IReadOnlyList fileSystemChildren, IDirectoryService directoryService) { + // Apply .ignore rules + var filtered = fileSystemChildren.Where(c => !DotIgnoreIgnoreRule.IsIgnored(c, owner)).ToList(); var ownerVideoInfo = VideoResolver.Resolve(owner.Path, owner.IsFolder, _namingOptions, libraryRoot: owner.ContainingFolderPath); if (ownerVideoInfo is null) { yield break; } - var count = fileSystemChildren.Count; + var count = filtered.Count; for (var i = 0; i < count; i++) { - var current = fileSystemChildren[i]; + var current = filtered[i]; if (current.IsDirectory && _namingOptions.AllExtrasTypesFolderNames.ContainsKey(current.Name)) { var filesInSubFolder = _fileSystem.GetFiles(current.FullName, null, false, false); diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/DotIgnoreIgnoreRuleTest.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/DotIgnoreIgnoreRuleTest.cs new file mode 100644 index 0000000000..d677c9f091 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Library/DotIgnoreIgnoreRuleTest.cs @@ -0,0 +1,30 @@ +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.Library; + +public class DotIgnoreIgnoreRuleTest +{ + [Fact] + public void Test() + { + var ignore = new Ignore.Ignore(); + ignore.Add("SPs"); + Assert.True(ignore.IsIgnored("f:/cd/sps/ffffff.mkv")); + Assert.True(ignore.IsIgnored("cd/sps/ffffff.mkv")); + Assert.True(ignore.IsIgnored("/cd/sps/ffffff.mkv")); + } + + [Fact] + public void TestNegatePattern() + { + var ignore = new Ignore.Ignore(); + ignore.Add("SPs"); + ignore.Add("!thebestshot.mkv"); + Assert.True(ignore.IsIgnored("f:/cd/sps/ffffff.mkv")); + Assert.True(ignore.IsIgnored("cd/sps/ffffff.mkv")); + Assert.True(ignore.IsIgnored("/cd/sps/ffffff.mkv")); + Assert.True(!ignore.IsIgnored("f:/cd/sps/thebestshot.mkv")); + Assert.True(!ignore.IsIgnored("cd/sps/thebestshot.mkv")); + Assert.True(!ignore.IsIgnored("/cd/sps/thebestshot.mkv")); + } +} -- 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 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs index 7378cf8851..f634084034 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 6af2a553d6..d87ad729ee 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 21c953fb2d..64a96c4e5a 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 d49e0753ee..50eeaeac67 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 ebf98da456..b602585863 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 a7ff75bb1c..b90ec8222d 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 d656fccb4f..dd5852823e 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 d28cd70ef5..5683de169f 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 413bf2d30b..50bbf0974a 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 0bcc301cb9..64b6273670 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 7b25bc0e49..71962d952b 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 24c4b55015..4022bedc1a 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 51a3ba0c7f..a986b0b699 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 40adb51a58..53bc6751fc 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 9ca5d7420b..846f9baf71 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 5c9f70c3752bd7297cb85bdc7ce748363a16ad8b Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Wed, 30 Apr 2025 09:29:13 +0200 Subject: Cleanup Tasks and Validators --- .../Library/Validators/ArtistsPostScanTask.cs | 69 +- .../Library/Validators/ArtistsValidator.cs | 157 ++-- .../Library/Validators/CollectionPostScanTask.cs | 217 +++-- .../Library/Validators/GenresPostScanTask.cs | 69 +- .../Library/Validators/GenresValidator.cs | 151 ++-- .../Library/Validators/MusicGenresPostScanTask.cs | 69 +- .../Library/Validators/MusicGenresValidator.cs | 117 ++- .../Library/Validators/PeopleValidator.cs | 181 ++-- .../Library/Validators/StudiosPostScanTask.cs | 69 +- .../Library/Validators/StudiosValidator.cs | 151 ++-- .../ScheduledTasks/ScheduledTaskWorker.cs | 987 ++++++++++----------- .../ScheduledTasks/TaskManager.cs | 379 ++++---- .../ScheduledTasks/Tasks/AudioNormalizationTask.cs | 15 +- .../ScheduledTasks/Tasks/ChapterImagesTask.cs | 228 +++-- .../ScheduledTasks/Tasks/CleanActivityLogTask.cs | 101 ++- .../Tasks/CleanupCollectionAndPlaylistPathsTask.cs | 11 +- .../ScheduledTasks/Tasks/DeleteCacheFileTask.cs | 203 +++-- .../ScheduledTasks/Tasks/DeleteLogFileTask.cs | 130 +-- .../Tasks/DeleteTranscodeFileTask.cs | 171 ++-- .../Tasks/MediaSegmentExtractionTask.cs | 4 +- .../ScheduledTasks/Tasks/OptimizeDatabaseTask.cs | 114 ++- .../ScheduledTasks/Tasks/PeopleValidationTask.cs | 94 +- .../ScheduledTasks/Tasks/PluginUpdateTask.cs | 164 ++-- .../Tasks/RefreshMediaLibraryTask.cs | 83 +- .../ScheduledTasks/Triggers/DailyTrigger.cs | 121 ++- .../ScheduledTasks/Triggers/IntervalTrigger.cs | 155 ++-- .../ScheduledTasks/Triggers/StartupTrigger.cs | 69 +- .../ScheduledTasks/Triggers/WeeklyTrigger.cs | 161 ++-- 28 files changed, 2199 insertions(+), 2241 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs index d51f9aaa79..a31d5eccac 100644 --- a/Emby.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs @@ -5,45 +5,44 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.Library.Validators +namespace Emby.Server.Implementations.Library.Validators; + +/// +/// Class ArtistsPostScanTask. +/// +public class ArtistsPostScanTask : ILibraryPostScanTask { /// - /// Class ArtistsPostScanTask. + /// The _library manager. /// - public class ArtistsPostScanTask : ILibraryPostScanTask - { - /// - /// The _library manager. - /// - private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; - private readonly IItemRepository _itemRepo; + private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; - /// - /// Initializes a new instance of the class. - /// - /// The library manager. - /// The logger. - /// The item repository. - public ArtistsPostScanTask( - ILibraryManager libraryManager, - ILogger logger, - IItemRepository itemRepo) - { - _libraryManager = libraryManager; - _logger = logger; - _itemRepo = itemRepo; - } + /// + /// Initializes a new instance of the class. + /// + /// The library manager. + /// The logger. + /// The item repository. + public ArtistsPostScanTask( + ILibraryManager libraryManager, + ILogger logger, + IItemRepository itemRepo) + { + _libraryManager = libraryManager; + _logger = logger; + _itemRepo = itemRepo; + } - /// - /// Runs the specified progress. - /// - /// The progress. - /// The cancellation token. - /// Task. - public Task Run(IProgress progress, CancellationToken cancellationToken) - { - return new ArtistsValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); - } + /// + /// Runs the specified progress. + /// + /// The progress. + /// The cancellation token. + /// Task. + public Task Run(IProgress progress, CancellationToken cancellationToken) + { + return new ArtistsValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); } } diff --git a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs index 7591e8391f..7cc851b73b 100644 --- a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs @@ -10,102 +10,101 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.Library.Validators +namespace Emby.Server.Implementations.Library.Validators; + +/// +/// Class ArtistsValidator. +/// +public class ArtistsValidator { /// - /// Class ArtistsValidator. + /// The library manager. /// - public class ArtistsValidator - { - /// - /// The library manager. - /// - private readonly ILibraryManager _libraryManager; + private readonly ILibraryManager _libraryManager; - /// - /// The logger. - /// - private readonly ILogger _logger; - private readonly IItemRepository _itemRepo; + /// + /// The logger. + /// + private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; - /// - /// Initializes a new instance of the class. - /// - /// The library manager. - /// The logger. - /// The item repository. - public ArtistsValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) - { - _libraryManager = libraryManager; - _logger = logger; - _itemRepo = itemRepo; - } + /// + /// Initializes a new instance of the class. + /// + /// The library manager. + /// The logger. + /// The item repository. + public ArtistsValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) + { + _libraryManager = libraryManager; + _logger = logger; + _itemRepo = itemRepo; + } - /// - /// Runs the specified progress. - /// - /// The progress. - /// The cancellation token. - /// Task. - public async Task Run(IProgress progress, CancellationToken cancellationToken) - { - var names = _itemRepo.GetAllArtistNames(); + /// + /// Runs the specified progress. + /// + /// The progress. + /// The cancellation token. + /// Task. + public async Task Run(IProgress progress, CancellationToken cancellationToken) + { + var names = _itemRepo.GetAllArtistNames(); - var numComplete = 0; - var count = names.Count; + var numComplete = 0; + var count = names.Count; - foreach (var name in names) + foreach (var name in names) + { + try { - try - { - var item = _libraryManager.GetArtist(name); - - await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - // Don't clutter the log - throw; - } - catch (Exception ex) - { - _logger.LogError(ex, "Error refreshing {ArtistName}", name); - } - - numComplete++; - double percent = numComplete; - percent /= count; - percent *= 100; + var item = _libraryManager.GetArtist(name); - progress.Report(percent); + await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); } - - var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery + catch (OperationCanceledException) { - IncludeItemTypes = new[] { BaseItemKind.MusicArtist }, - IsDeadArtist = true, - IsLocked = false - }).Cast().ToList(); - - foreach (var item in deadEntities) + // Don't clutter the log + throw; + } + catch (Exception ex) { - if (!item.IsAccessedByName) - { - continue; - } + _logger.LogError(ex, "Error refreshing {ArtistName}", name); + } - _logger.LogInformation("Deleting dead {2} {0} {1}.", item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name, item.GetType().Name); + numComplete++; + double percent = numComplete; + percent /= count; + percent *= 100; - _libraryManager.DeleteItem( - item, - new DeleteOptions - { - DeleteFileLocation = false - }, - false); + progress.Report(percent); + } + + var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = [BaseItemKind.MusicArtist], + IsDeadArtist = true, + IsLocked = false + }).Cast().ToList(); + + foreach (var item in deadEntities) + { + if (!item.IsAccessedByName) + { + continue; } - progress.Report(100); + _logger.LogInformation("Deleting dead {ItemType} {ItemId} {ItemName}", item.GetType().Name, item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name); + + _libraryManager.DeleteItem( + item, + new DeleteOptions + { + DeleteFileLocation = false + }, + false); } + + progress.Report(100); } } diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index 337b1afdd4..38631e0de8 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -9,149 +9,146 @@ using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Querying; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.Library.Validators +namespace Emby.Server.Implementations.Library.Validators; + +/// +/// Class CollectionPostScanTask. +/// +public class CollectionPostScanTask : ILibraryPostScanTask { + private readonly ILibraryManager _libraryManager; + private readonly ICollectionManager _collectionManager; + private readonly ILogger _logger; + /// - /// Class CollectionPostScanTask. + /// Initializes a new instance of the class. /// - public class CollectionPostScanTask : ILibraryPostScanTask + /// The library manager. + /// The collection manager. + /// The logger. + public CollectionPostScanTask( + ILibraryManager libraryManager, + ICollectionManager collectionManager, + ILogger logger) { - private readonly ILibraryManager _libraryManager; - private readonly ICollectionManager _collectionManager; - private readonly ILogger _logger; - - /// - /// Initializes a new instance of the class. - /// - /// The library manager. - /// The collection manager. - /// The logger. - public CollectionPostScanTask( - ILibraryManager libraryManager, - ICollectionManager collectionManager, - ILogger logger) - { - _libraryManager = libraryManager; - _collectionManager = collectionManager; - _logger = logger; - } + _libraryManager = libraryManager; + _collectionManager = collectionManager; + _logger = logger; + } - /// - /// Runs the specified progress. - /// - /// The progress. - /// The cancellation token. - /// Task. - public async Task Run(IProgress progress, CancellationToken cancellationToken) - { - var collectionNameMoviesMap = new Dictionary>(); + /// + /// Runs the specified progress. + /// + /// The progress. + /// The cancellation token. + /// Task. + public async Task Run(IProgress progress, CancellationToken cancellationToken) + { + var collectionNameMoviesMap = new Dictionary>(); - foreach (var library in _libraryManager.RootFolder.Children) + foreach (var library in _libraryManager.RootFolder.Children) + { + if (!_libraryManager.GetLibraryOptions(library).AutomaticallyAddToCollection) { - if (!_libraryManager.GetLibraryOptions(library).AutomaticallyAddToCollection) - { - continue; - } + continue; + } - var startIndex = 0; - var pagesize = 1000; + var startIndex = 0; + var pagesize = 1000; - while (true) + while (true) + { + var movies = _libraryManager.GetItemList(new InternalItemsQuery { - var movies = _libraryManager.GetItemList(new InternalItemsQuery - { - MediaTypes = new[] { MediaType.Video }, - IncludeItemTypes = new[] { BaseItemKind.Movie }, - IsVirtualItem = false, - OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }, - Parent = library, - StartIndex = startIndex, - Limit = pagesize, - Recursive = true - }); - - foreach (var m in movies) + MediaTypes = [MediaType.Video], + IncludeItemTypes = [BaseItemKind.Movie], + IsVirtualItem = false, + OrderBy = [(ItemSortBy.SortName, SortOrder.Ascending)], + Parent = library, + StartIndex = startIndex, + Limit = pagesize, + Recursive = true + }); + + foreach (var m in movies) + { + if (m is Movie movie && !string.IsNullOrEmpty(movie.CollectionName)) { - if (m is Movie movie && !string.IsNullOrEmpty(movie.CollectionName)) + if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out var movieList)) { - if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out var movieList)) - { - movieList.Add(movie.Id); - } - else - { - collectionNameMoviesMap[movie.CollectionName] = new HashSet { movie.Id }; - } + movieList.Add(movie.Id); + } + else + { + collectionNameMoviesMap[movie.CollectionName] = new HashSet { movie.Id }; } } + } - if (movies.Count < pagesize) - { - break; - } - - startIndex += pagesize; + if (movies.Count < pagesize) + { + break; } + + startIndex += pagesize; } + } - var numComplete = 0; - var count = collectionNameMoviesMap.Count; + var numComplete = 0; + var count = collectionNameMoviesMap.Count; - if (count == 0) - { - progress.Report(100); - return; - } + if (count == 0) + { + progress.Report(100); + return; + } - var boxSets = _libraryManager.GetItemList(new InternalItemsQuery - { - IncludeItemTypes = new[] { BaseItemKind.BoxSet }, - CollapseBoxSetItems = false, - Recursive = true - }); + var boxSets = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = [BaseItemKind.BoxSet], + CollapseBoxSetItems = false, + Recursive = true + }); - foreach (var (collectionName, movieIds) in collectionNameMoviesMap) + foreach (var (collectionName, movieIds) in collectionNameMoviesMap) + { + try { - try + var boxSet = boxSets.FirstOrDefault(b => b?.Name == collectionName) as BoxSet; + if (boxSet is null) { - var boxSet = boxSets.FirstOrDefault(b => b?.Name == collectionName) as BoxSet; - if (boxSet is null) + // won't automatically create collection if only one movie in it + if (movieIds.Count >= 2) { - // won't automatically create collection if only one movie in it - if (movieIds.Count >= 2) + boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions { - boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions - { - Name = collectionName, - IsLocked = true - }); + Name = collectionName, + IsLocked = true + }).ConfigureAwait(false); - await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds); - } + await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds).ConfigureAwait(false); } - else - { - await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds); - } - - numComplete++; - double percent = numComplete; - percent /= count; - percent *= 100; - - progress.Report(percent); } - catch (Exception ex) + else { - _logger.LogError(ex, "Error refreshing {CollectionName} with {@MovieIds}", collectionName, movieIds); + await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds).ConfigureAwait(false); } - } - progress.Report(100); + numComplete++; + double percent = numComplete; + percent /= count; + percent *= 100; + + progress.Report(percent); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error refreshing {CollectionName} with {@MovieIds}", collectionName, movieIds); + } } + + progress.Report(100); } } diff --git a/Emby.Server.Implementations/Library/Validators/GenresPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/GenresPostScanTask.cs index d21d2887b0..5097e0073d 100644 --- a/Emby.Server.Implementations/Library/Validators/GenresPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/GenresPostScanTask.cs @@ -5,45 +5,44 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.Library.Validators +namespace Emby.Server.Implementations.Library.Validators; + +/// +/// Class GenresPostScanTask. +/// +public class GenresPostScanTask : ILibraryPostScanTask { /// - /// Class GenresPostScanTask. + /// The _library manager. /// - public class GenresPostScanTask : ILibraryPostScanTask - { - /// - /// The _library manager. - /// - private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; - private readonly IItemRepository _itemRepo; + private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; - /// - /// Initializes a new instance of the class. - /// - /// The library manager. - /// The logger. - /// The item repository. - public GenresPostScanTask( - ILibraryManager libraryManager, - ILogger logger, - IItemRepository itemRepo) - { - _libraryManager = libraryManager; - _logger = logger; - _itemRepo = itemRepo; - } + /// + /// Initializes a new instance of the class. + /// + /// The library manager. + /// The logger. + /// The item repository. + public GenresPostScanTask( + ILibraryManager libraryManager, + ILogger logger, + IItemRepository itemRepo) + { + _libraryManager = libraryManager; + _logger = logger; + _itemRepo = itemRepo; + } - /// - /// Runs the specified progress. - /// - /// The progress. - /// The cancellation token. - /// Task. - public Task Run(IProgress progress, CancellationToken cancellationToken) - { - return new GenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); - } + /// + /// Runs the specified progress. + /// + /// The progress. + /// The cancellation token. + /// Task. + public Task Run(IProgress progress, CancellationToken cancellationToken) + { + return new GenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); } } diff --git a/Emby.Server.Implementations/Library/Validators/GenresValidator.cs b/Emby.Server.Implementations/Library/Validators/GenresValidator.cs index 364770fcdc..fbfc9f7d54 100644 --- a/Emby.Server.Implementations/Library/Validators/GenresValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/GenresValidator.cs @@ -8,97 +8,96 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.Library.Validators +namespace Emby.Server.Implementations.Library.Validators; + +/// +/// Class GenresValidator. +/// +public class GenresValidator { /// - /// Class GenresValidator. + /// The library manager. /// - public class GenresValidator - { - /// - /// The library manager. - /// - private readonly ILibraryManager _libraryManager; - private readonly IItemRepository _itemRepo; + private readonly ILibraryManager _libraryManager; + private readonly IItemRepository _itemRepo; - /// - /// The logger. - /// - private readonly ILogger _logger; + /// + /// The logger. + /// + private readonly ILogger _logger; - /// - /// Initializes a new instance of the class. - /// - /// The library manager. - /// The logger. - /// The item repository. - public GenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) - { - _libraryManager = libraryManager; - _logger = logger; - _itemRepo = itemRepo; - } + /// + /// Initializes a new instance of the class. + /// + /// The library manager. + /// The logger. + /// The item repository. + public GenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) + { + _libraryManager = libraryManager; + _logger = logger; + _itemRepo = itemRepo; + } - /// - /// Runs the specified progress. - /// - /// The progress. - /// The cancellation token. - /// Task. - public async Task Run(IProgress progress, CancellationToken cancellationToken) - { - var names = _itemRepo.GetGenreNames(); + /// + /// Runs the specified progress. + /// + /// The progress. + /// The cancellation token. + /// Task. + public async Task Run(IProgress progress, CancellationToken cancellationToken) + { + var names = _itemRepo.GetGenreNames(); - var numComplete = 0; - var count = names.Count; + var numComplete = 0; + var count = names.Count; - foreach (var name in names) + foreach (var name in names) + { + try { - try - { - var item = _libraryManager.GetGenre(name); + var item = _libraryManager.GetGenre(name); - await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - // Don't clutter the log - throw; - } - catch (Exception ex) - { - _logger.LogError(ex, "Error refreshing {GenreName}", name); - } - - numComplete++; - double percent = numComplete; - percent /= count; - percent *= 100; - - progress.Report(percent); + await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); } - - var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery + catch (OperationCanceledException) { - IncludeItemTypes = [BaseItemKind.Genre, BaseItemKind.MusicGenre], - IsDeadGenre = true, - IsLocked = false - }); - - foreach (var item in deadEntities) + // Don't clutter the log + throw; + } + catch (Exception ex) { - _logger.LogInformation("Deleting dead {ItemType} {ItemId} {ItemName}", item.GetType().Name, item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name); - - _libraryManager.DeleteItem( - item, - new DeleteOptions - { - DeleteFileLocation = false - }, - false); + _logger.LogError(ex, "Error refreshing {GenreName}", name); } - progress.Report(100); + numComplete++; + double percent = numComplete; + percent /= count; + percent *= 100; + + progress.Report(percent); } + + var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = [BaseItemKind.Genre, BaseItemKind.MusicGenre], + IsDeadGenre = true, + IsLocked = false + }); + + foreach (var item in deadEntities) + { + _logger.LogInformation("Deleting dead {ItemType} {ItemId} {ItemName}", item.GetType().Name, item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name); + + _libraryManager.DeleteItem( + item, + new DeleteOptions + { + DeleteFileLocation = false + }, + false); + } + + progress.Report(100); } } diff --git a/Emby.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs index be119866b1..76658a81b5 100644 --- a/Emby.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs @@ -5,45 +5,44 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.Library.Validators +namespace Emby.Server.Implementations.Library.Validators; + +/// +/// Class MusicGenresPostScanTask. +/// +public class MusicGenresPostScanTask : ILibraryPostScanTask { /// - /// Class MusicGenresPostScanTask. + /// The library manager. /// - public class MusicGenresPostScanTask : ILibraryPostScanTask - { - /// - /// The library manager. - /// - private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; - private readonly IItemRepository _itemRepo; + private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; - /// - /// Initializes a new instance of the class. - /// - /// The library manager. - /// The logger. - /// The item repository. - public MusicGenresPostScanTask( - ILibraryManager libraryManager, - ILogger logger, - IItemRepository itemRepo) - { - _libraryManager = libraryManager; - _logger = logger; - _itemRepo = itemRepo; - } + /// + /// Initializes a new instance of the class. + /// + /// The library manager. + /// The logger. + /// The item repository. + public MusicGenresPostScanTask( + ILibraryManager libraryManager, + ILogger logger, + IItemRepository itemRepo) + { + _libraryManager = libraryManager; + _logger = logger; + _itemRepo = itemRepo; + } - /// - /// Runs the specified progress. - /// - /// The progress. - /// The cancellation token. - /// Task. - public Task Run(IProgress progress, CancellationToken cancellationToken) - { - return new MusicGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); - } + /// + /// Runs the specified progress. + /// + /// The progress. + /// The cancellation token. + /// Task. + public Task Run(IProgress progress, CancellationToken cancellationToken) + { + return new MusicGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); } } diff --git a/Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs b/Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs index 1ecf4c87c9..6203bce2bc 100644 --- a/Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs @@ -5,77 +5,76 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.Library.Validators +namespace Emby.Server.Implementations.Library.Validators; + +/// +/// Class MusicGenresValidator. +/// +public class MusicGenresValidator { /// - /// Class MusicGenresValidator. + /// The library manager. /// - public class MusicGenresValidator - { - /// - /// The library manager. - /// - private readonly ILibraryManager _libraryManager; + private readonly ILibraryManager _libraryManager; - /// - /// The logger. - /// - private readonly ILogger _logger; - private readonly IItemRepository _itemRepo; + /// + /// The logger. + /// + private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; - /// - /// Initializes a new instance of the class. - /// - /// The library manager. - /// The logger. - /// The item repository. - public MusicGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) - { - _libraryManager = libraryManager; - _logger = logger; - _itemRepo = itemRepo; - } + /// + /// Initializes a new instance of the class. + /// + /// The library manager. + /// The logger. + /// The item repository. + public MusicGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) + { + _libraryManager = libraryManager; + _logger = logger; + _itemRepo = itemRepo; + } - /// - /// Runs the specified progress. - /// - /// The progress. - /// The cancellation token. - /// Task. - public async Task Run(IProgress progress, CancellationToken cancellationToken) - { - var names = _itemRepo.GetMusicGenreNames(); + /// + /// Runs the specified progress. + /// + /// The progress. + /// The cancellation token. + /// Task. + public async Task Run(IProgress progress, CancellationToken cancellationToken) + { + var names = _itemRepo.GetMusicGenreNames(); - var numComplete = 0; - var count = names.Count; + var numComplete = 0; + var count = names.Count; - foreach (var name in names) + foreach (var name in names) + { + try { - try - { - var item = _libraryManager.GetMusicGenre(name); + var item = _libraryManager.GetMusicGenre(name); - await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - // Don't clutter the log - throw; - } - catch (Exception ex) - { - _logger.LogError(ex, "Error refreshing {GenreName}", name); - } - - numComplete++; - double percent = numComplete; - percent /= count; - percent *= 100; - - progress.Report(percent); + await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException) + { + // Don't clutter the log + throw; + } + catch (Exception ex) + { + _logger.LogError(ex, "Error refreshing {GenreName}", name); } - progress.Report(100); + numComplete++; + double percent = numComplete; + percent /= count; + percent *= 100; + + progress.Report(percent); } + + progress.Report(100); } } diff --git a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs index 725b8f76c7..b7fd24fa5c 100644 --- a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs @@ -9,119 +9,114 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.Library.Validators +namespace Emby.Server.Implementations.Library.Validators; + +/// +/// Class PeopleValidator. +/// +public class PeopleValidator { /// - /// Class PeopleValidator. + /// The _library manager. /// - public class PeopleValidator + private readonly ILibraryManager _libraryManager; + + /// + /// The _logger. + /// + private readonly ILogger _logger; + + private readonly IFileSystem _fileSystem; + + /// + /// Initializes a new instance of the class. + /// + /// The library manager. + /// The logger. + /// The file system. + public PeopleValidator(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem) { - /// - /// The _library manager. - /// - private readonly ILibraryManager _libraryManager; - - /// - /// The _logger. - /// - private readonly ILogger _logger; - - private readonly IFileSystem _fileSystem; - - /// - /// Initializes a new instance of the class. - /// - /// The library manager. - /// The logger. - /// The file system. - public PeopleValidator(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem) - { - _libraryManager = libraryManager; - _logger = logger; - _fileSystem = fileSystem; - } + _libraryManager = libraryManager; + _logger = logger; + _fileSystem = fileSystem; + } - /// - /// Validates the people. - /// - /// The cancellation token. - /// The progress. - /// Task. - public async Task ValidatePeople(CancellationToken cancellationToken, IProgress progress) - { - var people = _libraryManager.GetPeopleNames(new InternalPeopleQuery()); + /// + /// Validates the people. + /// + /// The cancellation token. + /// The progress. + /// Task. + public async Task ValidatePeople(CancellationToken cancellationToken, IProgress progress) + { + var people = _libraryManager.GetPeopleNames(new InternalPeopleQuery()); - var numComplete = 0; + var numComplete = 0; - var numPeople = people.Count; + var numPeople = people.Count; - _logger.LogDebug("Will refresh {0} people", numPeople); + _logger.LogDebug("Will refresh {Amount} people", numPeople); - foreach (var person in people) - { - cancellationToken.ThrowIfCancellationRequested(); + foreach (var person in people) + { + cancellationToken.ThrowIfCancellationRequested(); - try - { - var item = _libraryManager.GetPerson(person); - if (item is null) - { - _logger.LogWarning("Failed to get person: {Name}", person); - continue; - } - - var options = new MetadataRefreshOptions(new DirectoryService(_fileSystem)) - { - ImageRefreshMode = MetadataRefreshMode.ValidationOnly, - MetadataRefreshMode = MetadataRefreshMode.ValidationOnly - }; - - await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - throw; - } - catch (Exception ex) + try + { + var item = _libraryManager.GetPerson(person); + if (item is null) { - _logger.LogError(ex, "Error validating IBN entry {Person}", person); + _logger.LogWarning("Failed to get person: {Name}", person); + continue; } - // Update progress - numComplete++; - double percent = numComplete; - percent /= numPeople; + var options = new MetadataRefreshOptions(new DirectoryService(_fileSystem)) + { + ImageRefreshMode = MetadataRefreshMode.ValidationOnly, + MetadataRefreshMode = MetadataRefreshMode.ValidationOnly + }; - progress.Report(100 * percent); + await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); } - - var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery + catch (OperationCanceledException) { - IncludeItemTypes = [BaseItemKind.Person], - IsDeadPerson = true, - IsLocked = false - }); - - foreach (var item in deadEntities) + throw; + } + catch (Exception ex) { - _logger.LogInformation( - "Deleting dead {2} {0} {1}.", - item.Id.ToString("N", CultureInfo.InvariantCulture), - item.Name, - item.GetType().Name); - - _libraryManager.DeleteItem( - item, - new DeleteOptions - { - DeleteFileLocation = false - }, - false); + _logger.LogError(ex, "Error validating IBN entry {Person}", person); } - progress.Report(100); + // Update progress + numComplete++; + double percent = numComplete; + percent /= numPeople; - _logger.LogInformation("People validation complete"); + progress.Report(100 * percent); } + + var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = [BaseItemKind.Person], + IsDeadPerson = true, + IsLocked = false + }); + + foreach (var item in deadEntities) + { + _logger.LogInformation("Deleting dead {ItemType} {ItemId} {ItemName}", item.GetType().Name, item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name); + + _libraryManager.DeleteItem( + item, + new DeleteOptions + { + DeleteFileLocation = false + }, + false); + } + + progress.Report(100); + + _logger.LogInformation("People validation complete"); } } diff --git a/Emby.Server.Implementations/Library/Validators/StudiosPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/StudiosPostScanTask.cs index c682b156b8..67c56c104d 100644 --- a/Emby.Server.Implementations/Library/Validators/StudiosPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/StudiosPostScanTask.cs @@ -5,46 +5,45 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.Library.Validators +namespace Emby.Server.Implementations.Library.Validators; + +/// +/// Class MusicGenresPostScanTask. +/// +public class StudiosPostScanTask : ILibraryPostScanTask { /// - /// Class MusicGenresPostScanTask. + /// The _library manager. /// - public class StudiosPostScanTask : ILibraryPostScanTask - { - /// - /// The _library manager. - /// - private readonly ILibraryManager _libraryManager; + private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; - private readonly IItemRepository _itemRepo; + private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; - /// - /// Initializes a new instance of the class. - /// - /// The library manager. - /// The logger. - /// The item repository. - public StudiosPostScanTask( - ILibraryManager libraryManager, - ILogger logger, - IItemRepository itemRepo) - { - _libraryManager = libraryManager; - _logger = logger; - _itemRepo = itemRepo; - } + /// + /// Initializes a new instance of the class. + /// + /// The library manager. + /// The logger. + /// The item repository. + public StudiosPostScanTask( + ILibraryManager libraryManager, + ILogger logger, + IItemRepository itemRepo) + { + _libraryManager = libraryManager; + _logger = logger; + _itemRepo = itemRepo; + } - /// - /// Runs the specified progress. - /// - /// The progress. - /// The cancellation token. - /// Task. - public Task Run(IProgress progress, CancellationToken cancellationToken) - { - return new StudiosValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); - } + /// + /// Runs the specified progress. + /// + /// The progress. + /// The cancellation token. + /// Task. + public Task Run(IProgress progress, CancellationToken cancellationToken) + { + return new StudiosValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); } } diff --git a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs index 26bc49c1f0..5b87e4d9d0 100644 --- a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs @@ -8,98 +8,97 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.Library.Validators +namespace Emby.Server.Implementations.Library.Validators; + +/// +/// Class StudiosValidator. +/// +public class StudiosValidator { /// - /// Class StudiosValidator. + /// The library manager. /// - public class StudiosValidator - { - /// - /// The library manager. - /// - private readonly ILibraryManager _libraryManager; + private readonly ILibraryManager _libraryManager; - private readonly IItemRepository _itemRepo; + private readonly IItemRepository _itemRepo; - /// - /// The logger. - /// - private readonly ILogger _logger; + /// + /// The logger. + /// + private readonly ILogger _logger; - /// - /// Initializes a new instance of the class. - /// - /// The library manager. - /// The logger. - /// The item repository. - public StudiosValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) - { - _libraryManager = libraryManager; - _logger = logger; - _itemRepo = itemRepo; - } + /// + /// Initializes a new instance of the class. + /// + /// The library manager. + /// The logger. + /// The item repository. + public StudiosValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) + { + _libraryManager = libraryManager; + _logger = logger; + _itemRepo = itemRepo; + } - /// - /// Runs the specified progress. - /// - /// The progress. - /// The cancellation token. - /// Task. - public async Task Run(IProgress progress, CancellationToken cancellationToken) - { - var names = _itemRepo.GetStudioNames(); + /// + /// Runs the specified progress. + /// + /// The progress. + /// The cancellation token. + /// Task. + public async Task Run(IProgress progress, CancellationToken cancellationToken) + { + var names = _itemRepo.GetStudioNames(); - var numComplete = 0; - var count = names.Count; + var numComplete = 0; + var count = names.Count; - foreach (var name in names) + foreach (var name in names) + { + try { - try - { - var item = _libraryManager.GetStudio(name); + var item = _libraryManager.GetStudio(name); - await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - // Don't clutter the log - throw; - } - catch (Exception ex) - { - _logger.LogError(ex, "Error refreshing {StudioName}", name); - } - - numComplete++; - double percent = numComplete; - percent /= count; - percent *= 100; - - progress.Report(percent); + await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); } - - var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery + catch (OperationCanceledException) { - IncludeItemTypes = new[] { BaseItemKind.Studio }, - IsDeadStudio = true, - IsLocked = false - }); - - foreach (var item in deadEntities) + // Don't clutter the log + throw; + } + catch (Exception ex) { - _logger.LogInformation("Deleting dead {ItemType} {ItemId} {ItemName}", item.GetType().Name, item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name); - - _libraryManager.DeleteItem( - item, - new DeleteOptions - { - DeleteFileLocation = false - }, - false); + _logger.LogError(ex, "Error refreshing {StudioName}", name); } - progress.Report(100); + numComplete++; + double percent = numComplete; + percent /= count; + percent *= 100; + + progress.Report(percent); } + + var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = [BaseItemKind.Studio], + IsDeadStudio = true, + IsLocked = false + }); + + foreach (var item in deadEntities) + { + _logger.LogInformation("Deleting dead {ItemType} {ItemId} {ItemName}", item.GetType().Name, item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name); + + _libraryManager.DeleteItem( + item, + new DeleteOptions + { + DeleteFileLocation = false + }, + false); + } + + progress.Report(100); } } diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 985f0a8f85..24f554981a 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -16,663 +16,662 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.ScheduledTasks +namespace Emby.Server.Implementations.ScheduledTasks; + +/// +/// Class ScheduledTaskWorker. +/// +public class ScheduledTaskWorker : IScheduledTaskWorker { + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; + private readonly IApplicationPaths _applicationPaths; + private readonly ILogger _logger; + private readonly ITaskManager _taskManager; + private readonly Lock _lastExecutionResultSyncLock = new(); + private bool _readFromFile; + private TaskResult _lastExecutionResult; + private Task _currentTask; + private Tuple[] _triggers; + private string _id; + /// - /// Class ScheduledTaskWorker. + /// Initializes a new instance of the class. /// - public class ScheduledTaskWorker : IScheduledTaskWorker + /// The scheduled task. + /// The application paths. + /// The task manager. + /// The logger. + /// + /// scheduledTask + /// or + /// applicationPaths + /// or + /// taskManager + /// or + /// jsonSerializer + /// or + /// logger. + /// + public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, ILogger logger) { - private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; - private readonly IApplicationPaths _applicationPaths; - private readonly ILogger _logger; - private readonly ITaskManager _taskManager; - private readonly Lock _lastExecutionResultSyncLock = new(); - private bool _readFromFile; - private TaskResult _lastExecutionResult; - private Task _currentTask; - private Tuple[] _triggers; - private string _id; - - /// - /// Initializes a new instance of the class. - /// - /// The scheduled task. - /// The application paths. - /// The task manager. - /// The logger. - /// - /// scheduledTask - /// or - /// applicationPaths - /// or - /// taskManager - /// or - /// jsonSerializer - /// or - /// logger. - /// - public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, ILogger logger) - { - ArgumentNullException.ThrowIfNull(scheduledTask); - ArgumentNullException.ThrowIfNull(applicationPaths); - ArgumentNullException.ThrowIfNull(taskManager); - ArgumentNullException.ThrowIfNull(logger); + ArgumentNullException.ThrowIfNull(scheduledTask); + ArgumentNullException.ThrowIfNull(applicationPaths); + ArgumentNullException.ThrowIfNull(taskManager); + ArgumentNullException.ThrowIfNull(logger); - ScheduledTask = scheduledTask; - _applicationPaths = applicationPaths; - _taskManager = taskManager; - _logger = logger; + ScheduledTask = scheduledTask; + _applicationPaths = applicationPaths; + _taskManager = taskManager; + _logger = logger; - InitTriggerEvents(); - } + InitTriggerEvents(); + } - /// - public event EventHandler> TaskProgress; + /// + public event EventHandler> TaskProgress; - /// - public IScheduledTask ScheduledTask { get; private set; } + /// + public IScheduledTask ScheduledTask { get; private set; } - /// - public TaskResult LastExecutionResult + /// + public TaskResult LastExecutionResult + { + get { - get - { - var path = GetHistoryFilePath(); + var path = GetHistoryFilePath(); - lock (_lastExecutionResultSyncLock) + lock (_lastExecutionResultSyncLock) + { + if (_lastExecutionResult is null && !_readFromFile) { - if (_lastExecutionResult is null && !_readFromFile) + if (File.Exists(path)) { - if (File.Exists(path)) + var bytes = File.ReadAllBytes(path); + if (bytes.Length > 0) { - var bytes = File.ReadAllBytes(path); - if (bytes.Length > 0) + try { - try - { - _lastExecutionResult = JsonSerializer.Deserialize(bytes, _jsonOptions); - } - catch (JsonException ex) - { - _logger.LogError(ex, "Error deserializing {File}", path); - } + _lastExecutionResult = JsonSerializer.Deserialize(bytes, _jsonOptions); } - else + catch (JsonException ex) { - _logger.LogDebug("Scheduled Task history file {Path} is empty. Skipping deserialization.", path); + _logger.LogError(ex, "Error deserializing {File}", path); } } - - _readFromFile = true; + else + { + _logger.LogDebug("Scheduled Task history file {Path} is empty. Skipping deserialization.", path); + } } - } - return _lastExecutionResult; + _readFromFile = true; + } } - private set - { - _lastExecutionResult = value; + return _lastExecutionResult; + } - var path = GetHistoryFilePath(); - Directory.CreateDirectory(Path.GetDirectoryName(path)); + private set + { + _lastExecutionResult = value; - lock (_lastExecutionResultSyncLock) - { - using FileStream createStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None); - using Utf8JsonWriter jsonStream = new Utf8JsonWriter(createStream); - JsonSerializer.Serialize(jsonStream, value, _jsonOptions); - } + var path = GetHistoryFilePath(); + Directory.CreateDirectory(Path.GetDirectoryName(path)); + + lock (_lastExecutionResultSyncLock) + { + using FileStream createStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None); + using Utf8JsonWriter jsonStream = new Utf8JsonWriter(createStream); + JsonSerializer.Serialize(jsonStream, value, _jsonOptions); } } + } - /// - public string Name => ScheduledTask.Name; + /// + public string Name => ScheduledTask.Name; - /// - public string Description => ScheduledTask.Description; + /// + public string Description => ScheduledTask.Description; - /// - public string Category => ScheduledTask.Category; + /// + public string Category => ScheduledTask.Category; - /// - /// Gets or sets the current cancellation token. - /// - /// The current cancellation token source. - private CancellationTokenSource CurrentCancellationTokenSource { get; set; } + /// + /// Gets or sets the current cancellation token. + /// + /// The current cancellation token source. + private CancellationTokenSource CurrentCancellationTokenSource { get; set; } - /// - /// Gets or sets the current execution start time. - /// - /// The current execution start time. - private DateTime CurrentExecutionStartTime { get; set; } + /// + /// Gets or sets the current execution start time. + /// + /// The current execution start time. + private DateTime CurrentExecutionStartTime { get; set; } - /// - public TaskState State + /// + public TaskState State + { + get { - get + if (CurrentCancellationTokenSource is not null) { - if (CurrentCancellationTokenSource is not null) - { - return CurrentCancellationTokenSource.IsCancellationRequested - ? TaskState.Cancelling - : TaskState.Running; - } - - return TaskState.Idle; + return CurrentCancellationTokenSource.IsCancellationRequested + ? TaskState.Cancelling + : TaskState.Running; } + + return TaskState.Idle; } + } - /// - public double? CurrentProgress { get; private set; } + /// + public double? CurrentProgress { get; private set; } - /// - /// Gets or sets the triggers that define when the task will run. - /// - /// The triggers. - private Tuple[] InternalTriggers + /// + /// Gets or sets the triggers that define when the task will run. + /// + /// The triggers. + private Tuple[] InternalTriggers + { + get => _triggers; + set { - get => _triggers; - set - { - ArgumentNullException.ThrowIfNull(value); + ArgumentNullException.ThrowIfNull(value); - // Cleanup current triggers - if (_triggers is not null) - { - DisposeTriggers(); - } + // Cleanup current triggers + if (_triggers is not null) + { + DisposeTriggers(); + } - _triggers = value.ToArray(); + _triggers = value.ToArray(); - ReloadTriggerEvents(false); - } + ReloadTriggerEvents(false); } + } - /// - public IReadOnlyList Triggers + /// + public IReadOnlyList Triggers + { + get { - get - { - return Array.ConvertAll(InternalTriggers, i => i.Item1); - } + return Array.ConvertAll(InternalTriggers, i => i.Item1); + } - set - { - ArgumentNullException.ThrowIfNull(value); + set + { + ArgumentNullException.ThrowIfNull(value); - // This null check is not great, but is needed to handle bad user input, or user mucking with the config file incorrectly - var triggerList = value.Where(i => i is not null).ToArray(); + // This null check is not great, but is needed to handle bad user input, or user mucking with the config file incorrectly + var triggerList = value.Where(i => i is not null).ToArray(); - SaveTriggers(triggerList); + SaveTriggers(triggerList); - InternalTriggers = Array.ConvertAll(triggerList, i => new Tuple(i, GetTrigger(i))); - } + InternalTriggers = Array.ConvertAll(triggerList, i => new Tuple(i, GetTrigger(i))); } + } - /// - public string Id + /// + public string Id + { + get { - get - { - return _id ??= ScheduledTask.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture); - } + return _id ??= ScheduledTask.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture); } + } - private void InitTriggerEvents() - { - _triggers = LoadTriggers(); - ReloadTriggerEvents(true); - } + private void InitTriggerEvents() + { + _triggers = LoadTriggers(); + ReloadTriggerEvents(true); + } - /// - public void ReloadTriggerEvents() - { - ReloadTriggerEvents(false); - } + /// + public void ReloadTriggerEvents() + { + ReloadTriggerEvents(false); + } - /// - /// Reloads the trigger events. - /// - /// if set to true [is application startup]. - private void ReloadTriggerEvents(bool isApplicationStartup) + /// + /// Reloads the trigger events. + /// + /// if set to true [is application startup]. + private void ReloadTriggerEvents(bool isApplicationStartup) + { + foreach (var triggerInfo in InternalTriggers) { - foreach (var triggerInfo in InternalTriggers) - { - var trigger = triggerInfo.Item2; + var trigger = triggerInfo.Item2; - trigger.Stop(); + trigger.Stop(); - trigger.Triggered -= OnTriggerTriggered; - trigger.Triggered += OnTriggerTriggered; - trigger.Start(LastExecutionResult, _logger, Name, isApplicationStartup); - } + trigger.Triggered -= OnTriggerTriggered; + trigger.Triggered += OnTriggerTriggered; + trigger.Start(LastExecutionResult, _logger, Name, isApplicationStartup); } + } - /// - /// Handles the Triggered event of the trigger control. - /// - /// The source of the event. - /// The instance containing the event data. - private async void OnTriggerTriggered(object sender, EventArgs e) - { - var trigger = (ITaskTrigger)sender; + /// + /// Handles the Triggered event of the trigger control. + /// + /// The source of the event. + /// The instance containing the event data. + private async void OnTriggerTriggered(object sender, EventArgs e) + { + var trigger = (ITaskTrigger)sender; - if (ScheduledTask is IConfigurableScheduledTask configurableTask && !configurableTask.IsEnabled) - { - return; - } + if (ScheduledTask is IConfigurableScheduledTask configurableTask && !configurableTask.IsEnabled) + { + return; + } - _logger.LogDebug("{0} fired for task: {1}", trigger.GetType().Name, Name); + _logger.LogDebug("{0} fired for task: {1}", trigger.GetType().Name, Name); - trigger.Stop(); + trigger.Stop(); - _taskManager.QueueScheduledTask(ScheduledTask, trigger.TaskOptions); + _taskManager.QueueScheduledTask(ScheduledTask, trigger.TaskOptions); - await Task.Delay(1000).ConfigureAwait(false); + await Task.Delay(1000).ConfigureAwait(false); - trigger.Start(LastExecutionResult, _logger, Name, false); - } + trigger.Start(LastExecutionResult, _logger, Name, false); + } - /// - /// Executes the task. - /// - /// Task options. - /// Task. - /// Cannot execute a Task that is already running. - public async Task Execute(TaskOptions options) - { - var task = Task.Run(async () => await ExecuteInternal(options).ConfigureAwait(false)); + /// + /// Executes the task. + /// + /// Task options. + /// Task. + /// Cannot execute a Task that is already running. + public async Task Execute(TaskOptions options) + { + var task = Task.Run(async () => await ExecuteInternal(options).ConfigureAwait(false)); - _currentTask = task; + _currentTask = task; - try - { - await task.ConfigureAwait(false); - } - finally - { - _currentTask = null; - GC.Collect(); - } + try + { + await task.ConfigureAwait(false); } - - private async Task ExecuteInternal(TaskOptions options) + finally { - // Cancel the current execution, if any - if (CurrentCancellationTokenSource is not null) - { - throw new InvalidOperationException("Cannot execute a Task that is already running"); - } - - var progress = new Progress(); + _currentTask = null; + GC.Collect(); + } + } - CurrentCancellationTokenSource = new CancellationTokenSource(); + private async Task ExecuteInternal(TaskOptions options) + { + // Cancel the current execution, if any + if (CurrentCancellationTokenSource is not null) + { + throw new InvalidOperationException("Cannot execute a Task that is already running"); + } - _logger.LogDebug("Executing {0}", Name); + var progress = new Progress(); - ((TaskManager)_taskManager).OnTaskExecuting(this); + CurrentCancellationTokenSource = new CancellationTokenSource(); - progress.ProgressChanged += OnProgressChanged; + _logger.LogDebug("Executing {0}", Name); - TaskCompletionStatus status; - CurrentExecutionStartTime = DateTime.UtcNow; + ((TaskManager)_taskManager).OnTaskExecuting(this); - Exception failureException = null; + progress.ProgressChanged += OnProgressChanged; - try - { - if (options is not null && options.MaxRuntimeTicks.HasValue) - { - CurrentCancellationTokenSource.CancelAfter(TimeSpan.FromTicks(options.MaxRuntimeTicks.Value)); - } + TaskCompletionStatus status; + CurrentExecutionStartTime = DateTime.UtcNow; - await ScheduledTask.ExecuteAsync(progress, CurrentCancellationTokenSource.Token).ConfigureAwait(false); + Exception failureException = null; - status = TaskCompletionStatus.Completed; - } - catch (OperationCanceledException) + try + { + if (options is not null && options.MaxRuntimeTicks.HasValue) { - status = TaskCompletionStatus.Cancelled; + CurrentCancellationTokenSource.CancelAfter(TimeSpan.FromTicks(options.MaxRuntimeTicks.Value)); } - catch (Exception ex) - { - _logger.LogError(ex, "Error executing Scheduled Task"); - failureException = ex; - - status = TaskCompletionStatus.Failed; - } + await ScheduledTask.ExecuteAsync(progress, CurrentCancellationTokenSource.Token).ConfigureAwait(false); - var startTime = CurrentExecutionStartTime; - var endTime = DateTime.UtcNow; + status = TaskCompletionStatus.Completed; + } + catch (OperationCanceledException) + { + status = TaskCompletionStatus.Cancelled; + } + catch (Exception ex) + { + _logger.LogError(ex, "Error executing Scheduled Task"); - progress.ProgressChanged -= OnProgressChanged; - CurrentCancellationTokenSource.Dispose(); - CurrentCancellationTokenSource = null; - CurrentProgress = null; + failureException = ex; - OnTaskCompleted(startTime, endTime, status, failureException); + status = TaskCompletionStatus.Failed; } - /// - /// Progress_s the progress changed. - /// - /// The sender. - /// The e. - private void OnProgressChanged(object sender, double e) - { - e = Math.Min(e, 100); + var startTime = CurrentExecutionStartTime; + var endTime = DateTime.UtcNow; - CurrentProgress = e; + progress.ProgressChanged -= OnProgressChanged; + CurrentCancellationTokenSource.Dispose(); + CurrentCancellationTokenSource = null; + CurrentProgress = null; - TaskProgress?.Invoke(this, new GenericEventArgs(e)); - } + OnTaskCompleted(startTime, endTime, status, failureException); + } - /// - /// Stops the task if it is currently executing. - /// - /// Cannot cancel a Task unless it is in the Running state. - public void Cancel() - { - if (State != TaskState.Running) - { - throw new InvalidOperationException("Cannot cancel a Task unless it is in the Running state."); - } + /// + /// Progress_s the progress changed. + /// + /// The sender. + /// The e. + private void OnProgressChanged(object sender, double e) + { + e = Math.Min(e, 100); - CancelIfRunning(); - } + CurrentProgress = e; - /// - /// Cancels if running. - /// - public void CancelIfRunning() - { - if (State == TaskState.Running) - { - _logger.LogInformation("Attempting to cancel Scheduled Task {0}", Name); - CurrentCancellationTokenSource.Cancel(); - } - } + TaskProgress?.Invoke(this, new GenericEventArgs(e)); + } - /// - /// Gets the scheduled tasks configuration directory. - /// - /// System.String. - private string GetScheduledTasksConfigurationDirectory() + /// + /// Stops the task if it is currently executing. + /// + /// Cannot cancel a Task unless it is in the Running state. + public void Cancel() + { + if (State != TaskState.Running) { - return Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "ScheduledTasks"); + throw new InvalidOperationException("Cannot cancel a Task unless it is in the Running state."); } - /// - /// Gets the scheduled tasks data directory. - /// - /// System.String. - private string GetScheduledTasksDataDirectory() - { - return Path.Combine(_applicationPaths.DataPath, "ScheduledTasks"); - } + CancelIfRunning(); + } - /// - /// Gets the history file path. - /// - /// The history file path. - private string GetHistoryFilePath() + /// + /// Cancels if running. + /// + public void CancelIfRunning() + { + if (State == TaskState.Running) { - return Path.Combine(GetScheduledTasksDataDirectory(), new Guid(Id) + ".js"); + _logger.LogInformation("Attempting to cancel Scheduled Task {0}", Name); + CurrentCancellationTokenSource.Cancel(); } + } - /// - /// Gets the configuration file path. - /// - /// System.String. - private string GetConfigurationFilePath() - { - return Path.Combine(GetScheduledTasksConfigurationDirectory(), new Guid(Id) + ".js"); - } + /// + /// Gets the scheduled tasks configuration directory. + /// + /// System.String. + private string GetScheduledTasksConfigurationDirectory() + { + return Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "ScheduledTasks"); + } - /// - /// Loads the triggers. - /// - /// IEnumerable{BaseTaskTrigger}. - private Tuple[] LoadTriggers() - { - // This null check is not great, but is needed to handle bad user input, or user mucking with the config file incorrectly - var settings = LoadTriggerSettings().Where(i => i is not null); + /// + /// Gets the scheduled tasks data directory. + /// + /// System.String. + private string GetScheduledTasksDataDirectory() + { + return Path.Combine(_applicationPaths.DataPath, "ScheduledTasks"); + } - return settings.Select(i => new Tuple(i, GetTrigger(i))).ToArray(); - } + /// + /// Gets the history file path. + /// + /// The history file path. + private string GetHistoryFilePath() + { + return Path.Combine(GetScheduledTasksDataDirectory(), new Guid(Id) + ".js"); + } - private TaskTriggerInfo[] LoadTriggerSettings() - { - string path = GetConfigurationFilePath(); - TaskTriggerInfo[] list = null; - if (File.Exists(path)) - { - var bytes = File.ReadAllBytes(path); - list = JsonSerializer.Deserialize(bytes, _jsonOptions); - } + /// + /// Gets the configuration file path. + /// + /// System.String. + private string GetConfigurationFilePath() + { + return Path.Combine(GetScheduledTasksConfigurationDirectory(), new Guid(Id) + ".js"); + } - // Return defaults if file doesn't exist. - return list ?? GetDefaultTriggers(); - } + /// + /// Loads the triggers. + /// + /// IEnumerable{BaseTaskTrigger}. + private Tuple[] LoadTriggers() + { + // This null check is not great, but is needed to handle bad user input, or user mucking with the config file incorrectly + var settings = LoadTriggerSettings().Where(i => i is not null); + + return settings.Select(i => new Tuple(i, GetTrigger(i))).ToArray(); + } - private TaskTriggerInfo[] GetDefaultTriggers() + private TaskTriggerInfo[] LoadTriggerSettings() + { + string path = GetConfigurationFilePath(); + TaskTriggerInfo[] list = null; + if (File.Exists(path)) { - try - { - return ScheduledTask.GetDefaultTriggers().ToArray(); - } - catch - { - return - [ - new() - { - IntervalTicks = TimeSpan.FromDays(1).Ticks, - Type = TaskTriggerInfoType.IntervalTrigger - } - ]; - } + var bytes = File.ReadAllBytes(path); + list = JsonSerializer.Deserialize(bytes, _jsonOptions); } - /// - /// Saves the triggers. - /// - /// The triggers. - private void SaveTriggers(TaskTriggerInfo[] triggers) - { - var path = GetConfigurationFilePath(); + // Return defaults if file doesn't exist. + return list ?? GetDefaultTriggers(); + } - Directory.CreateDirectory(Path.GetDirectoryName(path)); - using FileStream createStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None); - using Utf8JsonWriter jsonWriter = new Utf8JsonWriter(createStream); - JsonSerializer.Serialize(jsonWriter, triggers, _jsonOptions); + private TaskTriggerInfo[] GetDefaultTriggers() + { + try + { + return ScheduledTask.GetDefaultTriggers().ToArray(); } - - /// - /// Called when [task completed]. - /// - /// The start time. - /// The end time. - /// The status. - /// The exception. - private void OnTaskCompleted(DateTime startTime, DateTime endTime, TaskCompletionStatus status, Exception ex) + catch { - var elapsedTime = endTime - startTime; + return + [ + new() + { + IntervalTicks = TimeSpan.FromDays(1).Ticks, + Type = TaskTriggerInfoType.IntervalTrigger + } + ]; + } + } - _logger.LogInformation("{0} {1} after {2} minute(s) and {3} seconds", Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds); + /// + /// Saves the triggers. + /// + /// The triggers. + private void SaveTriggers(TaskTriggerInfo[] triggers) + { + var path = GetConfigurationFilePath(); - var result = new TaskResult - { - StartTimeUtc = startTime, - EndTimeUtc = endTime, - Status = status, - Name = Name, - Id = Id - }; + Directory.CreateDirectory(Path.GetDirectoryName(path)); + using FileStream createStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None); + using Utf8JsonWriter jsonWriter = new Utf8JsonWriter(createStream); + JsonSerializer.Serialize(jsonWriter, triggers, _jsonOptions); + } - result.Key = ScheduledTask.Key; + /// + /// Called when [task completed]. + /// + /// The start time. + /// The end time. + /// The status. + /// The exception. + private void OnTaskCompleted(DateTime startTime, DateTime endTime, TaskCompletionStatus status, Exception ex) + { + var elapsedTime = endTime - startTime; - if (ex is not null) - { - result.ErrorMessage = ex.Message; - result.LongErrorMessage = ex.StackTrace; - } + _logger.LogInformation("{0} {1} after {2} minute(s) and {3} seconds", Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds); - LastExecutionResult = result; + var result = new TaskResult + { + StartTimeUtc = startTime, + EndTimeUtc = endTime, + Status = status, + Name = Name, + Id = Id + }; - ((TaskManager)_taskManager).OnTaskCompleted(this, result); - } + result.Key = ScheduledTask.Key; - /// - public void Dispose() + if (ex is not null) { - Dispose(true); - GC.SuppressFinalize(this); + result.ErrorMessage = ex.Message; + result.LongErrorMessage = ex.StackTrace; } - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool dispose) + LastExecutionResult = result; + + ((TaskManager)_taskManager).OnTaskCompleted(this, result); + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool dispose) + { + if (dispose) { - if (dispose) - { - DisposeTriggers(); + DisposeTriggers(); - var wasRunning = State == TaskState.Running; - var startTime = CurrentExecutionStartTime; + var wasRunning = State == TaskState.Running; + var startTime = CurrentExecutionStartTime; - var token = CurrentCancellationTokenSource; - if (token is not null) + var token = CurrentCancellationTokenSource; + if (token is not null) + { + try { - try - { - _logger.LogInformation("{Name}: Cancelling", Name); - token.Cancel(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error calling CancellationToken.Cancel();"); - } + _logger.LogInformation("{Name}: Cancelling", Name); + token.Cancel(); } - - var task = _currentTask; - if (task is not null) + catch (Exception ex) { - try - { - _logger.LogInformation("{Name}: Waiting on Task", Name); - var exited = task.Wait(2000); - - if (exited) - { - _logger.LogInformation("{Name}: Task exited", Name); - } - else - { - _logger.LogInformation("{Name}: Timed out waiting for task to stop", Name); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Error calling Task.WaitAll();"); - } + _logger.LogError(ex, "Error calling CancellationToken.Cancel();"); } + } - if (token is not null) + var task = _currentTask; + if (task is not null) + { + try { - try + _logger.LogInformation("{Name}: Waiting on Task", Name); + var exited = task.Wait(2000); + + if (exited) { - _logger.LogDebug("{Name}: Disposing CancellationToken", Name); - token.Dispose(); + _logger.LogInformation("{Name}: Task exited", Name); } - catch (Exception ex) + else { - _logger.LogError(ex, "Error calling CancellationToken.Dispose();"); + _logger.LogInformation("{Name}: Timed out waiting for task to stop", Name); } } - - if (wasRunning) + catch (Exception ex) { - OnTaskCompleted(startTime, DateTime.UtcNow, TaskCompletionStatus.Aborted, null); + _logger.LogError(ex, "Error calling Task.WaitAll();"); } } - } - - /// - /// Converts a TaskTriggerInfo into a concrete BaseTaskTrigger. - /// - /// The info. - /// BaseTaskTrigger. - /// Invalid trigger type: + info.Type. - private ITaskTrigger GetTrigger(TaskTriggerInfo info) - { - var options = new TaskOptions - { - MaxRuntimeTicks = info.MaxRuntimeTicks - }; - if (info.Type == TaskTriggerInfoType.DailyTrigger) + if (token is not null) { - if (!info.TimeOfDayTicks.HasValue) + try { - throw new ArgumentException("Info did not contain a TimeOfDayTicks.", nameof(info)); + _logger.LogDebug("{Name}: Disposing CancellationToken", Name); + token.Dispose(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error calling CancellationToken.Dispose();"); } - - return new DailyTrigger(TimeSpan.FromTicks(info.TimeOfDayTicks.Value), options); } - if (info.Type == TaskTriggerInfoType.WeeklyTrigger) + if (wasRunning) { - if (!info.TimeOfDayTicks.HasValue) - { - throw new ArgumentException("Info did not contain a TimeOfDayTicks.", nameof(info)); - } + OnTaskCompleted(startTime, DateTime.UtcNow, TaskCompletionStatus.Aborted, null); + } + } + } - if (!info.DayOfWeek.HasValue) - { - throw new ArgumentException("Info did not contain a DayOfWeek.", nameof(info)); - } + /// + /// Converts a TaskTriggerInfo into a concrete BaseTaskTrigger. + /// + /// The info. + /// BaseTaskTrigger. + /// Invalid trigger type: + info.Type. + private ITaskTrigger GetTrigger(TaskTriggerInfo info) + { + var options = new TaskOptions + { + MaxRuntimeTicks = info.MaxRuntimeTicks + }; - return new WeeklyTrigger(TimeSpan.FromTicks(info.TimeOfDayTicks.Value), info.DayOfWeek.Value, options); + if (info.Type == TaskTriggerInfoType.DailyTrigger) + { + if (!info.TimeOfDayTicks.HasValue) + { + throw new ArgumentException("Info did not contain a TimeOfDayTicks.", nameof(info)); } - if (info.Type == TaskTriggerInfoType.IntervalTrigger) + return new DailyTrigger(TimeSpan.FromTicks(info.TimeOfDayTicks.Value), options); + } + + if (info.Type == TaskTriggerInfoType.WeeklyTrigger) + { + if (!info.TimeOfDayTicks.HasValue) { - if (!info.IntervalTicks.HasValue) - { - throw new ArgumentException("Info did not contain a IntervalTicks.", nameof(info)); - } + throw new ArgumentException("Info did not contain a TimeOfDayTicks.", nameof(info)); + } - return new IntervalTrigger(TimeSpan.FromTicks(info.IntervalTicks.Value), options); + if (!info.DayOfWeek.HasValue) + { + throw new ArgumentException("Info did not contain a DayOfWeek.", nameof(info)); } - if (info.Type == TaskTriggerInfoType.StartupTrigger) + return new WeeklyTrigger(TimeSpan.FromTicks(info.TimeOfDayTicks.Value), info.DayOfWeek.Value, options); + } + + if (info.Type == TaskTriggerInfoType.IntervalTrigger) + { + if (!info.IntervalTicks.HasValue) { - return new StartupTrigger(options); + throw new ArgumentException("Info did not contain a IntervalTicks.", nameof(info)); } - throw new ArgumentException("Unrecognized trigger type: " + info.Type); + return new IntervalTrigger(TimeSpan.FromTicks(info.IntervalTicks.Value), options); } - /// - /// Disposes each trigger. - /// - private void DisposeTriggers() + if (info.Type == TaskTriggerInfoType.StartupTrigger) { - foreach (var triggerInfo in InternalTriggers) + return new StartupTrigger(options); + } + + throw new ArgumentException("Unrecognized trigger type: " + info.Type); + } + + /// + /// Disposes each trigger. + /// + private void DisposeTriggers() + { + foreach (var triggerInfo in InternalTriggers) + { + var trigger = triggerInfo.Item2; + trigger.Triggered -= OnTriggerTriggered; + trigger.Stop(); + if (trigger is IDisposable disposable) { - var trigger = triggerInfo.Item2; - trigger.Triggered -= OnTriggerTriggered; - trigger.Stop(); - if (trigger is IDisposable disposable) - { - disposable.Dispose(); - } + disposable.Dispose(); } } } diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index a5e4104ffe..4ec2c9c786 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -8,255 +8,254 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.ScheduledTasks +namespace Emby.Server.Implementations.ScheduledTasks; + +/// +/// Class TaskManager. +/// +public class TaskManager : ITaskManager { /// - /// Class TaskManager. + /// The _task queue. /// - public class TaskManager : ITaskManager - { - /// - /// The _task queue. - /// - private readonly ConcurrentQueue> _taskQueue = - new ConcurrentQueue>(); - - private readonly IApplicationPaths _applicationPaths; - private readonly ILogger _logger; - - /// - /// Initializes a new instance of the class. - /// - /// The application paths. - /// The logger. - public TaskManager( - IApplicationPaths applicationPaths, - ILogger logger) - { - _applicationPaths = applicationPaths; - _logger = logger; + private readonly ConcurrentQueue> _taskQueue = + new ConcurrentQueue>(); - ScheduledTasks = Array.Empty(); - } + private readonly IApplicationPaths _applicationPaths; + private readonly ILogger _logger; - /// - public event EventHandler>? TaskExecuting; + /// + /// Initializes a new instance of the class. + /// + /// The application paths. + /// The logger. + public TaskManager( + IApplicationPaths applicationPaths, + ILogger logger) + { + _applicationPaths = applicationPaths; + _logger = logger; - /// - public event EventHandler? TaskCompleted; + ScheduledTasks = []; + } - /// - public IReadOnlyList ScheduledTasks { get; private set; } + /// + public event EventHandler>? TaskExecuting; - /// - public void CancelIfRunningAndQueue(TaskOptions options) - where T : IScheduledTask - { - var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T)); - ((ScheduledTaskWorker)task).CancelIfRunning(); + /// + public event EventHandler? TaskCompleted; - QueueScheduledTask(options); - } + /// + public IReadOnlyList ScheduledTasks { get; private set; } - /// - public void CancelIfRunningAndQueue() - where T : IScheduledTask - { - CancelIfRunningAndQueue(new TaskOptions()); - } + /// + public void CancelIfRunningAndQueue(TaskOptions options) + where T : IScheduledTask + { + var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T)); + ((ScheduledTaskWorker)task).CancelIfRunning(); - /// - public void CancelIfRunning() - where T : IScheduledTask - { - var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T)); - ((ScheduledTaskWorker)task).CancelIfRunning(); - } + QueueScheduledTask(options); + } - /// - public void QueueScheduledTask(TaskOptions options) + /// + public void CancelIfRunningAndQueue() where T : IScheduledTask - { - var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == typeof(T)); + { + CancelIfRunningAndQueue(new TaskOptions()); + } - if (scheduledTask is null) - { - _logger.LogError("Unable to find scheduled task of type {0} in QueueScheduledTask.", typeof(T).Name); - } - else - { - QueueScheduledTask(scheduledTask, options); - } - } + /// + public void CancelIfRunning() + where T : IScheduledTask + { + var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T)); + ((ScheduledTaskWorker)task).CancelIfRunning(); + } - /// - public void QueueScheduledTask() - where T : IScheduledTask - { - QueueScheduledTask(new TaskOptions()); - } + /// + public void QueueScheduledTask(TaskOptions options) + where T : IScheduledTask + { + var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == typeof(T)); - /// - public void QueueIfNotRunning() - where T : IScheduledTask + if (scheduledTask is null) { - var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T)); - - if (task.State != TaskState.Running) - { - QueueScheduledTask(new TaskOptions()); - } + _logger.LogError("Unable to find scheduled task of type {Type} in QueueScheduledTask.", typeof(T).Name); } - - /// - public void Execute() - where T : IScheduledTask + else { - var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == typeof(T)); + QueueScheduledTask(scheduledTask, options); + } + } - if (scheduledTask is null) - { - _logger.LogError("Unable to find scheduled task of type {0} in Execute.", typeof(T).Name); - } - else - { - var type = scheduledTask.ScheduledTask.GetType(); + /// + public void QueueScheduledTask() + where T : IScheduledTask + { + QueueScheduledTask(new TaskOptions()); + } - _logger.LogDebug("Queuing task {0}", type.Name); + /// + public void QueueIfNotRunning() + where T : IScheduledTask + { + var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T)); - lock (_taskQueue) - { - if (scheduledTask.State == TaskState.Idle) - { - Execute(scheduledTask, new TaskOptions()); - } - } - } + if (task.State != TaskState.Running) + { + QueueScheduledTask(new TaskOptions()); } + } - /// - public void QueueScheduledTask(IScheduledTask task, TaskOptions options) - { - var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == task.GetType()); + /// + public void Execute() + where T : IScheduledTask + { + var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == typeof(T)); - if (scheduledTask is null) - { - _logger.LogError("Unable to find scheduled task of type {0} in QueueScheduledTask.", task.GetType().Name); - } - else - { - QueueScheduledTask(scheduledTask, options); - } + if (scheduledTask is null) + { + _logger.LogError("Unable to find scheduled task of type {Type} in Execute.", typeof(T).Name); } - - /// - /// Queues the scheduled task. - /// - /// The task. - /// The task options. - private void QueueScheduledTask(IScheduledTaskWorker task, TaskOptions options) + else { - var type = task.ScheduledTask.GetType(); + var type = scheduledTask.ScheduledTask.GetType(); - _logger.LogDebug("Queuing task {0}", type.Name); + _logger.LogDebug("Queuing task {Name}", type.Name); lock (_taskQueue) { - if (task.State == TaskState.Idle) + if (scheduledTask.State == TaskState.Idle) { - Execute(task, options); - return; + Execute(scheduledTask, new TaskOptions()); } - - _taskQueue.Enqueue(new Tuple(type, options)); } } + } - /// - public void AddTasks(IEnumerable tasks) - { - var list = tasks.Select(t => new ScheduledTaskWorker(t, _applicationPaths, this, _logger)); + /// + public void QueueScheduledTask(IScheduledTask task, TaskOptions options) + { + var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == task.GetType()); - ScheduledTasks = ScheduledTasks.Concat(list).ToArray(); + if (scheduledTask is null) + { + _logger.LogError("Unable to find scheduled task of type {Type} in QueueScheduledTask.", task.GetType().Name); } - - /// - public void Dispose() + else { - Dispose(true); - GC.SuppressFinalize(this); + QueueScheduledTask(scheduledTask, options); } + } + + /// + /// Queues the scheduled task. + /// + /// The task. + /// The task options. + private void QueueScheduledTask(IScheduledTaskWorker task, TaskOptions options) + { + var type = task.ScheduledTask.GetType(); + + _logger.LogDebug("Queuing task {Name}", type.Name); - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool dispose) + lock (_taskQueue) { - foreach (var task in ScheduledTasks) + if (task.State == TaskState.Idle) { - task.Dispose(); + Execute(task, options); + return; } - } - /// - public void Cancel(IScheduledTaskWorker task) - { - ((ScheduledTaskWorker)task).Cancel(); + _taskQueue.Enqueue(new Tuple(type, options)); } + } - /// - public Task Execute(IScheduledTaskWorker task, TaskOptions options) - { - return ((ScheduledTaskWorker)task).Execute(options); - } + /// + public void AddTasks(IEnumerable tasks) + { + var list = tasks.Select(t => new ScheduledTaskWorker(t, _applicationPaths, this, _logger)); + + ScheduledTasks = ScheduledTasks.Concat(list).ToArray(); + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - /// - /// Called when [task executing]. - /// - /// The task. - internal void OnTaskExecuting(IScheduledTaskWorker task) + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool dispose) + { + foreach (var task in ScheduledTasks) { - TaskExecuting?.Invoke(this, new GenericEventArgs(task)); + task.Dispose(); } + } - /// - /// Called when [task completed]. - /// - /// The task. - /// The result. - internal void OnTaskCompleted(IScheduledTaskWorker task, TaskResult result) - { - TaskCompleted?.Invoke(task, new TaskCompletionEventArgs(task, result)); + /// + public void Cancel(IScheduledTaskWorker task) + { + ((ScheduledTaskWorker)task).Cancel(); + } - ExecuteQueuedTasks(); - } + /// + public Task Execute(IScheduledTaskWorker task, TaskOptions options) + { + return ((ScheduledTaskWorker)task).Execute(options); + } + + /// + /// Called when [task executing]. + /// + /// The task. + internal void OnTaskExecuting(IScheduledTaskWorker task) + { + TaskExecuting?.Invoke(this, new GenericEventArgs(task)); + } + + /// + /// Called when [task completed]. + /// + /// The task. + /// The result. + internal void OnTaskCompleted(IScheduledTaskWorker task, TaskResult result) + { + TaskCompleted?.Invoke(task, new TaskCompletionEventArgs(task, result)); + + ExecuteQueuedTasks(); + } - /// - /// Executes the queued tasks. - /// - private void ExecuteQueuedTasks() + /// + /// Executes the queued tasks. + /// + private void ExecuteQueuedTasks() + { + lock (_taskQueue) { - lock (_taskQueue) - { - var list = new List>(); + var list = new List>(); - while (_taskQueue.TryDequeue(out var item)) + while (_taskQueue.TryDequeue(out var item)) + { + if (list.All(i => i.Item1 != item.Item1)) { - if (list.All(i => i.Item1 != item.Item1)) - { - list.Add(item); - } + list.Add(item); } + } - foreach (var enqueuedType in list) - { - var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == enqueuedType.Item1); + foreach (var enqueuedType in list) + { + var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == enqueuedType.Item1); - if (scheduledTask.State == TaskState.Idle) - { - Execute(scheduledTask, enqueuedType.Item2); - } + if (scheduledTask.State == TaskState.Idle) + { + Execute(scheduledTask, enqueuedType.Item2); } } } diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs index 8d1d509ff7..ef005bfaa5 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs @@ -156,14 +156,11 @@ public partial class AudioNormalizationTask : IScheduledTask /// public IEnumerable GetDefaultTriggers() { - return - [ - new TaskTriggerInfo - { - Type = TaskTriggerInfoType.IntervalTrigger, - IntervalTicks = TimeSpan.FromHours(24).Ticks - } - ]; + yield return new TaskTriggerInfo + { + Type = TaskTriggerInfoType.IntervalTrigger, + IntervalTicks = TimeSpan.FromHours(24).Ticks + }; } private async Task CalculateLUFSAsync(string inputArgs, bool waitForExit, CancellationToken cancellationToken) @@ -194,7 +191,7 @@ public partial class AudioNormalizationTask : IScheduledTask using var reader = process.StandardError; float? lufs = null; - await foreach (var line in reader.ReadAllLinesAsync(cancellationToken)) + await foreach (var line in reader.ReadAllLinesAsync(cancellationToken).ConfigureAwait(false)) { Match match = LUFSRegex().Match(line); if (match.Success) diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs index b76fdeeb04..f81309560e 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs @@ -17,155 +17,151 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.ScheduledTasks.Tasks +namespace Emby.Server.Implementations.ScheduledTasks.Tasks; + +/// +/// Class ChapterImagesTask. +/// +public class ChapterImagesTask : IScheduledTask { + private readonly ILogger _logger; + private readonly ILibraryManager _libraryManager; + private readonly IApplicationPaths _appPaths; + private readonly IChapterManager _chapterManager; + private readonly IFileSystem _fileSystem; + private readonly ILocalizationManager _localization; + /// - /// Class ChapterImagesTask. + /// Initializes a new instance of the class. /// - public class ChapterImagesTask : IScheduledTask + /// 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 ChapterImagesTask( + ILogger logger, + ILibraryManager libraryManager, + IApplicationPaths appPaths, + IChapterManager chapterManager, + IFileSystem fileSystem, + ILocalizationManager localization) { - private readonly ILogger _logger; - private readonly ILibraryManager _libraryManager; - private readonly IApplicationPaths _appPaths; - private readonly IChapterManager _chapterManager; - private readonly IFileSystem _fileSystem; - private readonly ILocalizationManager _localization; - - /// - /// Initializes a new instance of the class. - /// - /// 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 ChapterImagesTask( - ILogger logger, - ILibraryManager libraryManager, - IApplicationPaths appPaths, - IChapterManager chapterManager, - IFileSystem fileSystem, - ILocalizationManager localization) - { - _logger = logger; - _libraryManager = libraryManager; - _appPaths = appPaths; - _chapterManager = chapterManager; - _fileSystem = fileSystem; - _localization = localization; - } + _logger = logger; + _libraryManager = libraryManager; + _appPaths = appPaths; + _chapterManager = chapterManager; + _fileSystem = fileSystem; + _localization = localization; + } - /// - public string Name => _localization.GetLocalizedString("TaskRefreshChapterImages"); + /// + public string Name => _localization.GetLocalizedString("TaskRefreshChapterImages"); - /// - public string Description => _localization.GetLocalizedString("TaskRefreshChapterImagesDescription"); + /// + public string Description => _localization.GetLocalizedString("TaskRefreshChapterImagesDescription"); - /// - public string Category => _localization.GetLocalizedString("TasksLibraryCategory"); + /// + public string Category => _localization.GetLocalizedString("TasksLibraryCategory"); - /// - public string Key => "RefreshChapterImages"; + /// + public string Key => "RefreshChapterImages"; - /// - public IEnumerable GetDefaultTriggers() + /// + public IEnumerable GetDefaultTriggers() + { + yield return new TaskTriggerInfo { - return - [ - new TaskTriggerInfo - { - Type = TaskTriggerInfoType.DailyTrigger, - TimeOfDayTicks = TimeSpan.FromHours(2).Ticks, - MaxRuntimeTicks = TimeSpan.FromHours(4).Ticks - } - ]; - } + Type = TaskTriggerInfoType.DailyTrigger, + TimeOfDayTicks = TimeSpan.FromHours(2).Ticks, + MaxRuntimeTicks = TimeSpan.FromHours(4).Ticks + }; + } - /// - public async Task ExecuteAsync(IProgress progress, CancellationToken cancellationToken) + /// + public async Task ExecuteAsync(IProgress progress, CancellationToken cancellationToken) + { + var videos = _libraryManager.GetItemList(new InternalItemsQuery { - var videos = _libraryManager.GetItemList(new InternalItemsQuery + MediaTypes = [MediaType.Video], + IsFolder = false, + Recursive = true, + DtoOptions = new DtoOptions(false) { - MediaTypes = [MediaType.Video], - IsFolder = false, - Recursive = true, - DtoOptions = new DtoOptions(false) - { - EnableImages = false - }, - SourceTypes = [SourceType.Library], - IsVirtualItem = false - }) - .OfType