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 93ee47fe8..1fc9ccb14 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -18,6 +18,7 @@ using Emby.Server.Implementations.Library.Validators; using Emby.Server.Implementations.Playlists; using Emby.Server.Implementations.ScheduledTasks.Tasks; using Emby.Server.Implementations.Sorting; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index d0f5e60f7..669db65f7 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -13,6 +13,7 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index e9cf47d46..b4e05ebf0 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading; +using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; -- 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 c483f3c61..856810494 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 d8b33a799..ccff31eba 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 d1fec7cb1..7de0e430f 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 e628abde5..c93dabb66 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 856810494..cc2092e21 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 cc2092e21..7b3a54039 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 f8ce473da..10d27498b 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 df46c2dac..cc070244b 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 392b7de74..e20ad79ad 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 47b1cb16e..03a28fd8c 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 afe2d833d..f1ed4fe27 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 8dece28a0..aee720aa7 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 ea223e3ec..6791e3ca9 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 5795c47cc..92a5e9ffd 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 030da6f73..df2acfc46 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 7ea863d76..a83ded439 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 7b3a54039..3432aa322 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 000000000..c910abadb --- /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 e20ad79ad..630a169cb 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 9c0f5b57b..6949ec1a8 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 000000000..036889810 --- /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 45b91971b..98ee1e4b8 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 3432aa322..b810ad4de 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 abf2d0115..6cb63a28a 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 fb48d7bf1..c81a0adb8 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 e3fbe8e4d..9dbac1e92 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 03a28fd8c..e4490bca3 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 3a042df68..4c8ba58d0 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 6e8a9fc20..4d959905d 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -35,11 +35,11 @@ using Emby.Server.Implementations.SyncPlay; using Emby.Server.Implementations.TV; using Emby.Server.Implementations.Updates; using Jellyfin.Api.Helpers; +using Jellyfin.Database.Implementations; using Jellyfin.Drawing; using Jellyfin.MediaEncoding.Hls.Playlist; using Jellyfin.Networking.Manager; using Jellyfin.Networking.Udp; -using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Item; using Jellyfin.Server.Implementations.MediaSegments; using MediaBrowser.Common; diff --git a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs index a83ded439..63481b1f8 100644 --- a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs +++ b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs @@ -4,7 +4,7 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index 82945a4f6..8a79cdebc 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Jellyfin.Data; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Http; diff --git a/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs b/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs index f9c10ba09..0d63b3af7 100644 --- a/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs index 34c722e41..273d356a3 100644 --- a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs +++ b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.IO; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Images/GenreImageProvider.cs b/Emby.Server.Implementations/Images/GenreImageProvider.cs index c9b41f819..706de60a9 100644 --- a/Emby.Server.Implementations/Images/GenreImageProvider.cs +++ b/Emby.Server.Implementations/Images/GenreImageProvider.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs b/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs index 31f053f06..c472623e6 100644 --- a/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs +++ b/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index b0003ed41..846663900 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -21,6 +21,7 @@ using Emby.Server.Implementations.Sorting; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 3e71b2fcd..863195836 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -16,6 +16,7 @@ using AsyncKeyedLock; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using Jellyfin.Extensions.Json; using MediaBrowser.Common.Configuration; diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs index 6791e3ca9..631179ffc 100644 --- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs +++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Model.Entities; diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs index 71c69ec50..ffbf8068f 100644 --- a/Emby.Server.Implementations/Library/MusicManager.cs +++ b/Emby.Server.Implementations/Library/MusicManager.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Linq; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs index 3ac1d0219..9253a9a69 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs b/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs index 76e564d53..0c9edd839 100644 --- a/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs +++ b/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index a41ef888b..2a2813151 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -7,8 +7,8 @@ using System.Globalization; using System.Linq; using System.Threading; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using Jellyfin.Extensions; -using Jellyfin.Server.Implementations; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index 2560466c1..22baafbb0 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -9,6 +9,7 @@ using System.Threading; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index 89f64ee4f..337b1afdd 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs index 05223d28a..4d3a04377 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Tasks; using Microsoft.EntityFrameworkCore; diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index dc37c4f2a..959373fec 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -13,6 +13,7 @@ using Jellyfin.Data.Entities.Security; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs index 270c1b441..74db077d8 100644 --- a/Emby.Server.Implementations/TV/TVSeriesManager.cs +++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs @@ -6,6 +6,7 @@ using System.Linq; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs index 0fd014990..f6f2f59c5 100644 --- a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs +++ b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs @@ -4,7 +4,7 @@ using System.Text.Encodings.Web; using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Data; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Authentication; diff --git a/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs b/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs index 07dedb017..6b80d537f 100644 --- a/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs +++ b/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Data; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; diff --git a/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs b/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs index 5fcf72fb4..7efb5b169 100644 --- a/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs +++ b/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Jellyfin.Api.Extensions; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.SyncPlay; diff --git a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs index a7c3cce97..152c400cd 100644 --- a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs +++ b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs @@ -1,5 +1,5 @@ using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Api.Auth.UserPermissionPolicy { diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs index 10556da65..2da483913 100644 --- a/Jellyfin.Api/Controllers/ArtistsController.cs +++ b/Jellyfin.Api/Controllers/ArtistsController.cs @@ -6,6 +6,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Controllers/ChannelsController.cs b/Jellyfin.Api/Controllers/ChannelsController.cs index 2f55e88ec..880b3a82d 100644 --- a/Jellyfin.Api/Controllers/ChannelsController.cs +++ b/Jellyfin.Api/Controllers/ChannelsController.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs index 6d94d96f3..2196616dd 100644 --- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs +++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs @@ -5,7 +5,7 @@ using System.Globalization; using System.Linq; using Jellyfin.Api.Helpers; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; using MediaBrowser.Model.Dto; diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs index f0d17decb..1fd57eba9 100644 --- a/Jellyfin.Api/Controllers/GenresController.cs +++ b/Jellyfin.Api/Controllers/GenresController.cs @@ -6,6 +6,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index e6fe7df79..803c2f1f7 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -6,6 +6,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index 7c6160fc4..ff4540f58 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -13,6 +13,7 @@ using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.LibraryDtos; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Api; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 1c0a6af79..5461d12fa 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -15,6 +15,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.LiveTvDtos; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Api; using MediaBrowser.Common.Configuration; diff --git a/Jellyfin.Api/Controllers/MediaSegmentsController.cs b/Jellyfin.Api/Controllers/MediaSegmentsController.cs index 2d1d4e2c8..e30e2b54e 100644 --- a/Jellyfin.Api/Controllers/MediaSegmentsController.cs +++ b/Jellyfin.Api/Controllers/MediaSegmentsController.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; using Jellyfin.Api.Extensions; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs index cbbaaddbf..09a7b73b9 100644 --- a/Jellyfin.Api/Controllers/MoviesController.cs +++ b/Jellyfin.Api/Controllers/MoviesController.cs @@ -7,6 +7,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index e8bc8f265..0cb20e433 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -6,6 +6,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index 9b56d0849..5075d91be 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -5,6 +5,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs index 7ee4396bb..3e4bac89a 100644 --- a/Jellyfin.Api/Controllers/TrailersController.cs +++ b/Jellyfin.Api/Controllers/TrailersController.cs @@ -1,6 +1,7 @@ using System; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index cc070244b..0f08854d2 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -7,6 +7,7 @@ using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 838578fab..d0ced277a 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -8,7 +8,7 @@ using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.UserDtos; using Jellyfin.Data; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Api; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index 2b32ae728..bbfa270db 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -8,6 +8,7 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs index 2c45789d3..1801b6bfd 100644 --- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs +++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs @@ -10,6 +10,7 @@ using Jellyfin.Api.Extensions; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs index eb83a37ba..3c2691cb5 100644 --- a/Jellyfin.Api/Helpers/RequestHelpers.cs +++ b/Jellyfin.Api/Helpers/RequestHelpers.cs @@ -7,6 +7,7 @@ using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs b/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs index dece66426..2616694d8 100644 --- a/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs +++ b/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Text.Json.Serialization; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions.Json.Converters; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; diff --git a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs index e2e7b0cb5..60379f415 100644 --- a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs @@ -1,8 +1,8 @@ using System; using System.Threading.Tasks; using Jellyfin.Data; -using Jellyfin.Data.Enums; using Jellyfin.Data.Events; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Activity; diff --git a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs index cc0792477..9d149cc85 100644 --- a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Jellyfin.Data; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; diff --git a/Jellyfin.Data/DayOfWeekHelper.cs b/Jellyfin.Data/DayOfWeekHelper.cs index 82abfb831..836860e0e 100644 --- a/Jellyfin.Data/DayOfWeekHelper.cs +++ b/Jellyfin.Data/DayOfWeekHelper.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 using System; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Data { diff --git a/Jellyfin.Data/UserEntityExtensions.cs b/Jellyfin.Data/UserEntityExtensions.cs index 8d84a6b6e..8bf82265c 100644 --- a/Jellyfin.Data/UserEntityExtensions.cs +++ b/Jellyfin.Data/UserEntityExtensions.cs @@ -2,8 +2,8 @@ using System; using System.ComponentModel; using System.Linq; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data; diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs index 54272aeaf..007a468bf 100644 --- a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs +++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Querying; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationStore.cs b/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationStore.cs index 180561fc8..537630561 100644 --- a/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationStore.cs +++ b/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationStore.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Jellyfin.Database.Implementations.DbConfiguration; using MediaBrowser.Common.Configuration; namespace Jellyfin.Server.Implementations.DatabaseConfiguration; diff --git a/Jellyfin.Server.Implementations/Devices/DeviceManager.cs b/Jellyfin.Server.Implementations/Devices/DeviceManager.cs index 1b4048b8e..e414a8232 100644 --- a/Jellyfin.Server.Implementations/Devices/DeviceManager.cs +++ b/Jellyfin.Server.Implementations/Devices/DeviceManager.cs @@ -7,9 +7,10 @@ using Jellyfin.Data; using Jellyfin.Data.Dtos; using Jellyfin.Data.Entities; using Jellyfin.Data.Entities.Security; -using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Devices; diff --git a/Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs b/Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs index b0e4567a7..fbbb5bca7 100644 --- a/Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs +++ b/Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs @@ -1,14 +1,15 @@ using System; using System.Collections.Generic; using System.Reflection; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.DbConfiguration; using Jellyfin.Database.Providers.Sqlite; -using Jellyfin.Server.Implementations.DatabaseConfiguration; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using JellyfinDbProviderFactory = System.Func; +using JellyfinDbProviderFactory = System.Func; namespace Jellyfin.Server.Implementations.Extensions; diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs index bea69b282..1f04b2829 100644 --- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs +++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs @@ -18,6 +18,8 @@ using System.Text.Json; using System.Threading; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using Jellyfin.Extensions.Json; using MediaBrowser.Common; diff --git a/Jellyfin.Server.Implementations/Item/ChapterRepository.cs b/Jellyfin.Server.Implementations/Item/ChapterRepository.cs index fc6f04d56..48b94a5f3 100644 --- a/Jellyfin.Server.Implementations/Item/ChapterRepository.cs +++ b/Jellyfin.Server.Implementations/Item/ChapterRepository.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller.Chapters; using MediaBrowser.Controller.Drawing; using MediaBrowser.Model.Dto; diff --git a/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs b/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs index 155798209..18167cc53 100644 --- a/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs +++ b/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Linq; using System.Threading; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs b/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs index f47e3fdfd..f70071884 100644 --- a/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs +++ b/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Linq; using System.Threading; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; diff --git a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs index a8dfd4cd3..01a0ade63 100644 --- a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs +++ b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Linq; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations; using Jellyfin.Extensions; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Persistence; diff --git a/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs b/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs index 59ec418ce..fa507ad04 100644 --- a/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs +++ b/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs @@ -6,7 +6,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; diff --git a/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs b/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs index 1c9f54ab0..534e80f4e 100644 --- a/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs +++ b/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Jellyfin.Data.Entities.Security; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller.Security; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs b/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs index 9e225393c..e3fe517c4 100644 --- a/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs +++ b/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Net; using System.Threading.Tasks; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations; using Jellyfin.Extensions; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; diff --git a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs index 6949ec1a8..b55d2271a 100644 --- a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs +++ b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; diff --git a/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs b/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs index 27222a183..02a52e5f2 100644 --- a/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs +++ b/Jellyfin.Server.Implementations/Users/DeviceAccessHost.cs @@ -2,9 +2,9 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Session; diff --git a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs index e204a16a6..3f9491038 100644 --- a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs +++ b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 79fa70c0b..0105f8162 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -12,6 +12,8 @@ using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using Jellyfin.Data.Events.Users; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common; using MediaBrowser.Common.Extensions; diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index 9788119a5..f3bf6b805 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -4,10 +4,10 @@ using System.Reflection; using Emby.Server.Implementations; using Emby.Server.Implementations.Session; using Jellyfin.Api.WebSocketListeners; +using Jellyfin.Database.Implementations; using Jellyfin.Drawing; using Jellyfin.Drawing.Skia; using Jellyfin.LiveTv; -using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Activity; using Jellyfin.Server.Implementations.Devices; using Jellyfin.Server.Implementations.Events; diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index 597643ed1..c3b02ad4e 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -19,6 +19,7 @@ using Jellyfin.Api.Controllers; using Jellyfin.Api.Formatters; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions.Json; using Jellyfin.Server.Configuration; using Jellyfin.Server.Filters; diff --git a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs index 2f23cb1f8..933d85de0 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs index c845beef2..a50990ac5 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities.Security; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; using Microsoft.Data.Sqlite; diff --git a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs index 502a37cde..4f6c5100d 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs @@ -6,8 +6,8 @@ using System.Text.Json; using System.Text.Json.Serialization; using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; diff --git a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs index f183bce10..490daae42 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs @@ -12,8 +12,8 @@ using System.Text; using System.Threading; using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities; +using Jellyfin.Database.Implementations; using Jellyfin.Extensions; -using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Item; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index f126230fb..bd5bf98e0 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -3,9 +3,9 @@ using System.IO; using Emby.Server.Implementations.Data; using Jellyfin.Data; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions.Json; -using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Users; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index d8684f6da..32814393c 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -8,9 +8,9 @@ using System.Threading; using System.Threading.Tasks; using CommandLine; using Emby.Server.Implementations; +using Jellyfin.Database.Implementations; using Jellyfin.Server.Extensions; using Jellyfin.Server.Helpers; -using Jellyfin.Server.Implementations; using Jellyfin.Server.ServerSetupApp; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs index fa21d2566..688b16935 100644 --- a/Jellyfin.Server/Startup.cs +++ b/Jellyfin.Server/Startup.cs @@ -6,6 +6,7 @@ using System.Net.Mime; using System.Text; using Emby.Server.Implementations.EntryPoints; using Jellyfin.Api.Middleware; +using Jellyfin.Database.Implementations; using Jellyfin.LiveTv.Extensions; using Jellyfin.LiveTv.Recordings; using Jellyfin.MediaEncoding.Hls.Extensions; @@ -13,7 +14,6 @@ using Jellyfin.Networking; using Jellyfin.Networking.HappyEyeballs; using Jellyfin.Server.Extensions; using Jellyfin.Server.HealthChecks; -using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Extensions; using Jellyfin.Server.Infrastructure; using MediaBrowser.Common.Net; diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index 49f8df508..f6cbf5a00 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -9,7 +9,7 @@ using System.Text.Json.Serialization; using System.Threading; using Jellyfin.Data; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Querying; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 3b0938ea7..d6e659242 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index e99479ee1..39dc90963 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index e20679084..29481481c 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -15,6 +15,7 @@ using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Channels; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index b2f23cc11..d3e9da622 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -16,6 +16,7 @@ using J2N.Collections.Generic.Extensions; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Collections; diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 0bd28154d..57a8a0113 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -6,6 +6,7 @@ using System.Linq; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 07def2e0f..a252b7a25 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -10,6 +10,7 @@ using System.Text.Json.Serialization; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Querying; diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index f3c252dec..470702f3e 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 367080867..18845ab9f 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -9,6 +9,7 @@ using System.Linq; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.TV; diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index e4490bca3..13915dc5c 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 1c5d2f4e5..cf76f336c 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -15,6 +15,7 @@ using System.Text.RegularExpressions; using System.Threading; using Jellyfin.Data; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Extensions; diff --git a/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs b/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs index 570d2bace..1e75446e1 100644 --- a/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs +++ b/MediaBrowser.Controller/MediaSegments/IMediaSegmentManager.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.MediaSegments; diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 491acdc9c..53e04066f 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; diff --git a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs index d35ed57b8..85bb862c7 100644 --- a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs +++ b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs @@ -11,7 +11,7 @@ using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; using Jellyfin.Data; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index b477f2593..fe4b2de65 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 using System; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace MediaBrowser.Model.Configuration { diff --git a/MediaBrowser.Model/Dto/DisplayPreferencesDto.cs b/MediaBrowser.Model/Dto/DisplayPreferencesDto.cs index 90163ae91..54cbe65f6 100644 --- a/MediaBrowser.Model/Dto/DisplayPreferencesDto.cs +++ b/MediaBrowser.Model/Dto/DisplayPreferencesDto.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace MediaBrowser.Model.Dto { diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs index d872572b7..38e273176 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs @@ -3,6 +3,7 @@ using System; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace MediaBrowser.Model.LiveTv { diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs b/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs index dae885775..e93ad81d3 100644 --- a/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs +++ b/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs @@ -1,6 +1,6 @@ #pragma warning disable CS1591 -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace MediaBrowser.Model.LiveTv { diff --git a/MediaBrowser.Model/MediaSegments/MediaSegmentDto.cs b/MediaBrowser.Model/MediaSegments/MediaSegmentDto.cs index a0433fee1..6e5c7885c 100644 --- a/MediaBrowser.Model/MediaSegments/MediaSegmentDto.cs +++ b/MediaBrowser.Model/MediaSegments/MediaSegmentDto.cs @@ -1,5 +1,5 @@ using System; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace MediaBrowser.Model.MediaSegments; diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index 951e05763..ba0eaf21c 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -6,6 +6,7 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Xml.Serialization; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using AccessSchedule = Jellyfin.Data.Entities.AccessSchedule; namespace MediaBrowser.Model.Users diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs index af2ede701..b481a106f 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs @@ -1,6 +1,4 @@ -using System; - -namespace Jellyfin.Server.Implementations.DatabaseConfiguration; +namespace Jellyfin.Database.Implementations.DbConfiguration; /// /// Options to configure jellyfins managed database. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs index f534e49f3..909e8750f 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AccessSchedule.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations.Schema; using System.Xml.Serialization; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs index 51dd0ffb8..3a7678405 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ActivityLog.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; using Microsoft.Extensions.Logging; namespace Jellyfin.Data.Entities diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs index e3e0e0861..42be5b3b9 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemEntity.cs @@ -3,8 +3,6 @@ using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs index 37723df11..ac6b72ace 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemImageInfo.cs @@ -1,7 +1,6 @@ #pragma warning disable CA2227 using System; -using System.Collections.Generic; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs index 9a1565728..c0c5e3147 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/BaseItemProvider.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs index f0be65769..82bf007a8 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/DisplayPreferences.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs index 09f237289..4b343c164 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Group.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Linq; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs index 8dd6e647e..edffec4ab 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/HomeSection.cs @@ -1,5 +1,5 @@ using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs index 93e6664ea..7e75a200b 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemDisplayPreferences.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs index 94db6a011..e80a9aec3 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/ItemValueMap.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs index fc3c1036f..b529da8fa 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Artwork.cs @@ -1,8 +1,8 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs index a838686d0..54c30d92c 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Book.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs index 4a350d200..7b1a68bb5 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/BookMetadata.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs index f068338f9..cbcb9a5f5 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Chapter.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs index 7de601969..8da9793f9 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Collection.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs index 15b356a74..4bd99d83a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CollectionItem.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs index 1abbee445..5dc1039a1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Company.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs index e27d01d86..92307afec 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/CustomItem.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs index ce2f0c617..637975526 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Episode.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs index 3b822ee82..329b8973f 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Genre.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs index fa9276c66..401d58ff2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/ItemMetadata.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs index 0db42a1c7..17673cb1d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Library.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs index d889b871e..975614be1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/LibraryItem.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs index 7b5a3af64..0913f95be 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFile.cs @@ -2,8 +2,8 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs index e24e73ecb..3170653fe 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MediaFileStream.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs index b38d6a4f1..afaebb8e8 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProvider.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs index a198f53ba..fa36e58db 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MetadataProviderId.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs index 499fafd0e..beae325ec 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Movie.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs index 44b5f34d7..df48ebf27 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/MovieMetadata.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs index 90dc55b70..d9609f1cc 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Person.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs index 7d40bdf44..627f74140 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/PersonRole.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs index 4b459432b..094d57139 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Photo.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs index 58c8fa49e..6b792ffb4 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Rating.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs index 0f3a07324..91ee8caa1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/RatingSource.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs index e68ab9105..40466def1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Release.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs index 42115802c..28da91e47 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/SeriesMetadata.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs index d35400033..6d6a92022 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Libraries/Track.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities.Libraries { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs index 90120d772..8c1c071e6 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaSegment.cs @@ -1,6 +1,6 @@ using System; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs index 77816565a..b16b62b10 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/MediaStreamInfo.cs @@ -1,7 +1,6 @@ #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using System; -using System.Diagnostics.CodeAnalysis; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs index 6d2e68077..c488b90e1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Permission.cs @@ -3,8 +3,8 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs index a6ab275d3..f4f9dd17a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Preference.cs @@ -1,8 +1,8 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs index f3398eeea..aafa92b4a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/User.cs @@ -1,12 +1,10 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; using System.Text.Json.Serialization; -using Jellyfin.Data.Enums; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Enums; +using Jellyfin.Database.Implementations.Interfaces; namespace Jellyfin.Data.Entities { diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs index 05ab6dd2d..ced12b9e6 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/UserData.cs @@ -1,5 +1,4 @@ using System; -using System.ComponentModel.DataAnnotations.Schema; namespace Jellyfin.Data.Entities; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ArtKind.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ArtKind.cs index f7a73848c..218e97bcc 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ArtKind.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ArtKind.cs @@ -1,33 +1,32 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing types of art. +/// +public enum ArtKind { /// - /// An enum representing types of art. + /// Another type of art, not covered by the other members. /// - public enum ArtKind - { - /// - /// Another type of art, not covered by the other members. - /// - Other = 0, + Other = 0, - /// - /// A poster. - /// - Poster = 1, + /// + /// A poster. + /// + Poster = 1, - /// - /// A banner. - /// - Banner = 2, + /// + /// A banner. + /// + Banner = 2, - /// - /// A thumbnail. - /// - Thumbnail = 3, + /// + /// A thumbnail. + /// + Thumbnail = 3, - /// - /// A logo. - /// - Logo = 4 - } + /// + /// A logo. + /// + Logo = 4 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ChromecastVersion.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ChromecastVersion.cs index c9c8a4a62..123f2fe43 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ChromecastVersion.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ChromecastVersion.cs @@ -1,18 +1,17 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing the version of Chromecast to be used by clients. +/// +public enum ChromecastVersion { /// - /// An enum representing the version of Chromecast to be used by clients. + /// Stable Chromecast version. /// - public enum ChromecastVersion - { - /// - /// Stable Chromecast version. - /// - Stable = 0, + Stable = 0, - /// - /// Unstable Chromecast version. - /// - Unstable = 1 - } + /// + /// Unstable Chromecast version. + /// + Unstable = 1 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/DynamicDayOfWeek.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/DynamicDayOfWeek.cs index d3d8dd822..69a9b5816 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/DynamicDayOfWeek.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/DynamicDayOfWeek.cs @@ -1,58 +1,57 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum that represents a day of the week, weekdays, weekends, or all days. +/// +public enum DynamicDayOfWeek { /// - /// An enum that represents a day of the week, weekdays, weekends, or all days. - /// - public enum DynamicDayOfWeek - { - /// - /// Sunday. - /// - Sunday = 0, - - /// - /// Monday. - /// - Monday = 1, - - /// - /// Tuesday. - /// - Tuesday = 2, - - /// - /// Wednesday. - /// - Wednesday = 3, - - /// - /// Thursday. - /// - Thursday = 4, - - /// - /// Friday. - /// - Friday = 5, - - /// - /// Saturday. - /// - Saturday = 6, - - /// - /// All days of the week. - /// - Everyday = 7, - - /// - /// A week day, or Monday-Friday. - /// - Weekday = 8, - - /// - /// Saturday and Sunday. - /// - Weekend = 9 - } + /// Sunday. + /// + Sunday = 0, + + /// + /// Monday. + /// + Monday = 1, + + /// + /// Tuesday. + /// + Tuesday = 2, + + /// + /// Wednesday. + /// + Wednesday = 3, + + /// + /// Thursday. + /// + Thursday = 4, + + /// + /// Friday. + /// + Friday = 5, + + /// + /// Saturday. + /// + Saturday = 6, + + /// + /// All days of the week. + /// + Everyday = 7, + + /// + /// A week day, or Monday-Friday. + /// + Weekday = 8, + + /// + /// Saturday and Sunday. + /// + Weekend = 9 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/HomeSectionType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/HomeSectionType.cs index 62da8c3ff..6ba57e74d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/HomeSectionType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/HomeSectionType.cs @@ -1,58 +1,57 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing the different options for the home screen sections. +/// +public enum HomeSectionType { /// - /// An enum representing the different options for the home screen sections. - /// - public enum HomeSectionType - { - /// - /// None. - /// - None = 0, - - /// - /// My Media. - /// - SmallLibraryTiles = 1, - - /// - /// My Media Small. - /// - LibraryButtons = 2, - - /// - /// Active Recordings. - /// - ActiveRecordings = 3, - - /// - /// Continue Watching. - /// - Resume = 4, - - /// - /// Continue Listening. - /// - ResumeAudio = 5, - - /// - /// Latest Media. - /// - LatestMedia = 6, - - /// - /// Next Up. - /// - NextUp = 7, - - /// - /// Live TV. - /// - LiveTv = 8, - - /// - /// Continue Reading. - /// - ResumeBook = 9 - } + /// None. + /// + None = 0, + + /// + /// My Media. + /// + SmallLibraryTiles = 1, + + /// + /// My Media Small. + /// + LibraryButtons = 2, + + /// + /// Active Recordings. + /// + ActiveRecordings = 3, + + /// + /// Continue Watching. + /// + Resume = 4, + + /// + /// Continue Listening. + /// + ResumeAudio = 5, + + /// + /// Latest Media. + /// + LatestMedia = 6, + + /// + /// Next Up. + /// + NextUp = 7, + + /// + /// Live TV. + /// + LiveTv = 8, + + /// + /// Continue Reading. + /// + ResumeBook = 9 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/IndexingKind.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/IndexingKind.cs index 3967712b0..72ac1140c 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/IndexingKind.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/IndexingKind.cs @@ -1,23 +1,22 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing a type of indexing in a user's display preferences. +/// +public enum IndexingKind { /// - /// An enum representing a type of indexing in a user's display preferences. + /// Index by the premiere date. /// - public enum IndexingKind - { - /// - /// Index by the premiere date. - /// - PremiereDate = 0, + PremiereDate = 0, - /// - /// Index by the production year. - /// - ProductionYear = 1, + /// + /// Index by the production year. + /// + ProductionYear = 1, - /// - /// Index by the community rating. - /// - CommunityRating = 2 - } + /// + /// Index by the community rating. + /// + CommunityRating = 2 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaFileKind.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaFileKind.cs index 797c26ec2..8e6f677dc 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaFileKind.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaFileKind.cs @@ -1,33 +1,32 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing the type of media file. +/// +public enum MediaFileKind { /// - /// An enum representing the type of media file. + /// The main file. /// - public enum MediaFileKind - { - /// - /// The main file. - /// - Main = 0, + Main = 0, - /// - /// A sidecar file. - /// - Sidecar = 1, + /// + /// A sidecar file. + /// + Sidecar = 1, - /// - /// An additional part to the main file. - /// - AdditionalPart = 2, + /// + /// An additional part to the main file. + /// + AdditionalPart = 2, - /// - /// An alternative format to the main file. - /// - AlternativeFormat = 3, + /// + /// An alternative format to the main file. + /// + AlternativeFormat = 3, - /// - /// An additional stream for the main file. - /// - AdditionalStream = 4 - } + /// + /// An additional stream for the main file. + /// + AdditionalStream = 4 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs index 458635450..fed092b97 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/MediaSegmentType.cs @@ -1,6 +1,6 @@ using Jellyfin.Data.Entities; -namespace Jellyfin.Data.Enums; +namespace Jellyfin.Database.Implementations.Enums; /// /// Defines the types of content an individual represents. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PermissionKind.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PermissionKind.cs index c3d6705c2..081863963 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PermissionKind.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PermissionKind.cs @@ -1,128 +1,127 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// The types of user permissions. +/// +public enum PermissionKind { /// - /// The types of user permissions. - /// - public enum PermissionKind - { - /// - /// Whether the user is an administrator. - /// - IsAdministrator = 0, - - /// - /// Whether the user is hidden. - /// - IsHidden = 1, - - /// - /// Whether the user is disabled. - /// - IsDisabled = 2, - - /// - /// Whether the user can control shared devices. - /// - EnableSharedDeviceControl = 3, - - /// - /// Whether the user can access the server remotely. - /// - EnableRemoteAccess = 4, - - /// - /// Whether the user can manage live tv. - /// - EnableLiveTvManagement = 5, - - /// - /// Whether the user can access live tv. - /// - EnableLiveTvAccess = 6, - - /// - /// Whether the user can play media. - /// - EnableMediaPlayback = 7, - - /// - /// Whether the server should transcode audio for the user if requested. - /// - EnableAudioPlaybackTranscoding = 8, - - /// - /// Whether the server should transcode video for the user if requested. - /// - EnableVideoPlaybackTranscoding = 9, - - /// - /// Whether the user can delete content. - /// - EnableContentDeletion = 10, - - /// - /// Whether the user can download content. - /// - EnableContentDownloading = 11, - - /// - /// Whether to enable sync transcoding for the user. - /// - EnableSyncTranscoding = 12, - - /// - /// Whether the user can do media conversion. - /// - EnableMediaConversion = 13, - - /// - /// Whether the user has access to all devices. - /// - EnableAllDevices = 14, - - /// - /// Whether the user has access to all channels. - /// - EnableAllChannels = 15, - - /// - /// Whether the user has access to all folders. - /// - EnableAllFolders = 16, - - /// - /// Whether to enable public sharing for the user. - /// - EnablePublicSharing = 17, - - /// - /// Whether the user can remotely control other users. - /// - EnableRemoteControlOfOtherUsers = 18, - - /// - /// Whether the user is permitted to do playback remuxing. - /// - EnablePlaybackRemuxing = 19, - - /// - /// Whether the server should force transcoding on remote connections for the user. - /// - ForceRemoteSourceTranscoding = 20, - - /// - /// Whether the user can create, modify and delete collections. - /// - EnableCollectionManagement = 21, - - /// - /// Whether the user can edit subtitles. - /// - EnableSubtitleManagement = 22, - - /// - /// Whether the user can edit lyrics. - /// - EnableLyricManagement = 23, - } + /// Whether the user is an administrator. + /// + IsAdministrator = 0, + + /// + /// Whether the user is hidden. + /// + IsHidden = 1, + + /// + /// Whether the user is disabled. + /// + IsDisabled = 2, + + /// + /// Whether the user can control shared devices. + /// + EnableSharedDeviceControl = 3, + + /// + /// Whether the user can access the server remotely. + /// + EnableRemoteAccess = 4, + + /// + /// Whether the user can manage live tv. + /// + EnableLiveTvManagement = 5, + + /// + /// Whether the user can access live tv. + /// + EnableLiveTvAccess = 6, + + /// + /// Whether the user can play media. + /// + EnableMediaPlayback = 7, + + /// + /// Whether the server should transcode audio for the user if requested. + /// + EnableAudioPlaybackTranscoding = 8, + + /// + /// Whether the server should transcode video for the user if requested. + /// + EnableVideoPlaybackTranscoding = 9, + + /// + /// Whether the user can delete content. + /// + EnableContentDeletion = 10, + + /// + /// Whether the user can download content. + /// + EnableContentDownloading = 11, + + /// + /// Whether to enable sync transcoding for the user. + /// + EnableSyncTranscoding = 12, + + /// + /// Whether the user can do media conversion. + /// + EnableMediaConversion = 13, + + /// + /// Whether the user has access to all devices. + /// + EnableAllDevices = 14, + + /// + /// Whether the user has access to all channels. + /// + EnableAllChannels = 15, + + /// + /// Whether the user has access to all folders. + /// + EnableAllFolders = 16, + + /// + /// Whether to enable public sharing for the user. + /// + EnablePublicSharing = 17, + + /// + /// Whether the user can remotely control other users. + /// + EnableRemoteControlOfOtherUsers = 18, + + /// + /// Whether the user is permitted to do playback remuxing. + /// + EnablePlaybackRemuxing = 19, + + /// + /// Whether the server should force transcoding on remote connections for the user. + /// + ForceRemoteSourceTranscoding = 20, + + /// + /// Whether the user can create, modify and delete collections. + /// + EnableCollectionManagement = 21, + + /// + /// Whether the user can edit subtitles. + /// + EnableSubtitleManagement = 22, + + /// + /// Whether the user can edit lyrics. + /// + EnableLyricManagement = 23, } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PersonRoleType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PersonRoleType.cs index 1e619f5ee..5b913385e 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PersonRoleType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PersonRoleType.cs @@ -1,68 +1,67 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing a person's role in a specific media item. +/// +public enum PersonRoleType { /// - /// An enum representing a person's role in a specific media item. + /// Another role, not covered by the other types. /// - public enum PersonRoleType - { - /// - /// Another role, not covered by the other types. - /// - Other = 0, + Other = 0, - /// - /// The director of the media. - /// - Director = 1, + /// + /// The director of the media. + /// + Director = 1, - /// - /// An artist. - /// - Artist = 2, + /// + /// An artist. + /// + Artist = 2, - /// - /// The original artist. - /// - OriginalArtist = 3, + /// + /// The original artist. + /// + OriginalArtist = 3, - /// - /// An actor. - /// - Actor = 4, + /// + /// An actor. + /// + Actor = 4, - /// - /// A voice actor. - /// - VoiceActor = 5, + /// + /// A voice actor. + /// + VoiceActor = 5, - /// - /// A producer. - /// - Producer = 6, + /// + /// A producer. + /// + Producer = 6, - /// - /// A remixer. - /// - Remixer = 7, + /// + /// A remixer. + /// + Remixer = 7, - /// - /// A conductor. - /// - Conductor = 8, + /// + /// A conductor. + /// + Conductor = 8, - /// - /// A composer. - /// - Composer = 9, + /// + /// A composer. + /// + Composer = 9, - /// - /// An author. - /// - Author = 10, + /// + /// An author. + /// + Author = 10, - /// - /// An editor. - /// - Editor = 11 - } + /// + /// An editor. + /// + Editor = 11 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PreferenceKind.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PreferenceKind.cs index d2b412e45..f70e3e2c2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PreferenceKind.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/PreferenceKind.cs @@ -1,73 +1,72 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// The types of user preferences. +/// +public enum PreferenceKind { /// - /// The types of user preferences. + /// A list of blocked tags. /// - public enum PreferenceKind - { - /// - /// A list of blocked tags. - /// - BlockedTags = 0, + BlockedTags = 0, - /// - /// A list of blocked channels. - /// - BlockedChannels = 1, + /// + /// A list of blocked channels. + /// + BlockedChannels = 1, - /// - /// A list of blocked media folders. - /// - BlockedMediaFolders = 2, + /// + /// A list of blocked media folders. + /// + BlockedMediaFolders = 2, - /// - /// A list of enabled devices. - /// - EnabledDevices = 3, + /// + /// A list of enabled devices. + /// + EnabledDevices = 3, - /// - /// A list of enabled channels. - /// - EnabledChannels = 4, + /// + /// A list of enabled channels. + /// + EnabledChannels = 4, - /// - /// A list of enabled folders. - /// - EnabledFolders = 5, + /// + /// A list of enabled folders. + /// + EnabledFolders = 5, - /// - /// A list of folders to allow content deletion from. - /// - EnableContentDeletionFromFolders = 6, + /// + /// A list of folders to allow content deletion from. + /// + EnableContentDeletionFromFolders = 6, - /// - /// A list of latest items to exclude. - /// - LatestItemExcludes = 7, + /// + /// A list of latest items to exclude. + /// + LatestItemExcludes = 7, - /// - /// A list of media to exclude. - /// - MyMediaExcludes = 8, + /// + /// A list of media to exclude. + /// + MyMediaExcludes = 8, - /// - /// A list of grouped folders. - /// - GroupedFolders = 9, + /// + /// A list of grouped folders. + /// + GroupedFolders = 9, - /// - /// A list of unrated items to block. - /// - BlockUnratedItems = 10, + /// + /// A list of unrated items to block. + /// + BlockUnratedItems = 10, - /// - /// A list of ordered views. - /// - OrderedViews = 11, + /// + /// A list of ordered views. + /// + OrderedViews = 11, - /// - /// A list of allowed tags. - /// - AllowedTags = 12 - } + /// + /// A list of allowed tags. + /// + AllowedTags = 12 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ScrollDirection.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ScrollDirection.cs index 29c50e2c4..3ff3c45fa 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ScrollDirection.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ScrollDirection.cs @@ -1,18 +1,17 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing the axis that should be scrolled. +/// +public enum ScrollDirection { /// - /// An enum representing the axis that should be scrolled. + /// Horizontal scrolling direction. /// - public enum ScrollDirection - { - /// - /// Horizontal scrolling direction. - /// - Horizontal = 0, + Horizontal = 0, - /// - /// Vertical scrolling direction. - /// - Vertical = 1 - } + /// + /// Vertical scrolling direction. + /// + Vertical = 1 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SortOrder.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SortOrder.cs index 4151448e4..c865b75f1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SortOrder.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SortOrder.cs @@ -1,18 +1,17 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing the sorting order. +/// +public enum SortOrder { /// - /// An enum representing the sorting order. + /// Sort in increasing order. /// - public enum SortOrder - { - /// - /// Sort in increasing order. - /// - Ascending = 0, + Ascending = 0, - /// - /// Sort in decreasing order. - /// - Descending = 1 - } + /// + /// Sort in decreasing order. + /// + Descending = 1 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SubtitlePlaybackMode.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SubtitlePlaybackMode.cs index 79693d321..c394c209b 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SubtitlePlaybackMode.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SubtitlePlaybackMode.cs @@ -1,33 +1,32 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing a subtitle playback mode. +/// +public enum SubtitlePlaybackMode { /// - /// An enum representing a subtitle playback mode. + /// The default subtitle playback mode. /// - public enum SubtitlePlaybackMode - { - /// - /// The default subtitle playback mode. - /// - Default = 0, + Default = 0, - /// - /// Always show subtitles. - /// - Always = 1, + /// + /// Always show subtitles. + /// + Always = 1, - /// - /// Only show forced subtitles. - /// - OnlyForced = 2, + /// + /// Only show forced subtitles. + /// + OnlyForced = 2, - /// - /// Don't show subtitles. - /// - None = 3, + /// + /// Don't show subtitles. + /// + None = 3, - /// - /// Only show subtitles when the current audio stream is in a different language. - /// - Smart = 4 - } + /// + /// Only show subtitles when the current audio stream is in a different language. + /// + Smart = 4 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SyncPlayUserAccessType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SyncPlayUserAccessType.cs index 030d16fb9..311642e0d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SyncPlayUserAccessType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/SyncPlayUserAccessType.cs @@ -1,23 +1,22 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// Enum SyncPlayUserAccessType. +/// +public enum SyncPlayUserAccessType { /// - /// Enum SyncPlayUserAccessType. + /// User can create groups and join them. /// - public enum SyncPlayUserAccessType - { - /// - /// User can create groups and join them. - /// - CreateAndJoinGroups = 0, + CreateAndJoinGroups = 0, - /// - /// User can only join already existing groups. - /// - JoinGroups = 1, + /// + /// User can only join already existing groups. + /// + JoinGroups = 1, - /// - /// SyncPlay is disabled for the user. - /// - None = 2 - } + /// + /// SyncPlay is disabled for the user. + /// + None = 2 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ViewType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ViewType.cs index c0fd7d448..b2bcbf2bb 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ViewType.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/ViewType.cs @@ -1,113 +1,112 @@ -namespace Jellyfin.Data.Enums +namespace Jellyfin.Database.Implementations.Enums; + +/// +/// An enum representing the type of view for a library or collection. +/// +public enum ViewType { /// - /// An enum representing the type of view for a library or collection. - /// - public enum ViewType - { - /// - /// Shows albums. - /// - Albums = 0, - - /// - /// Shows album artists. - /// - AlbumArtists = 1, - - /// - /// Shows artists. - /// - Artists = 2, - - /// - /// Shows channels. - /// - Channels = 3, - - /// - /// Shows collections. - /// - Collections = 4, - - /// - /// Shows episodes. - /// - Episodes = 5, - - /// - /// Shows favorites. - /// - Favorites = 6, - - /// - /// Shows genres. - /// - Genres = 7, - - /// - /// Shows guide. - /// - Guide = 8, - - /// - /// Shows movies. - /// - Movies = 9, - - /// - /// Shows networks. - /// - Networks = 10, - - /// - /// Shows playlists. - /// - Playlists = 11, - - /// - /// Shows programs. - /// - Programs = 12, - - /// - /// Shows recordings. - /// - Recordings = 13, - - /// - /// Shows schedule. - /// - Schedule = 14, - - /// - /// Shows series. - /// - Series = 15, - - /// - /// Shows shows. - /// - Shows = 16, - - /// - /// Shows songs. - /// - Songs = 17, - - /// - /// Shows songs. - /// - Suggestions = 18, - - /// - /// Shows trailers. - /// - Trailers = 19, - - /// - /// Shows upcoming. - /// - Upcoming = 20 - } + /// Shows albums. + /// + Albums = 0, + + /// + /// Shows album artists. + /// + AlbumArtists = 1, + + /// + /// Shows artists. + /// + Artists = 2, + + /// + /// Shows channels. + /// + Channels = 3, + + /// + /// Shows collections. + /// + Collections = 4, + + /// + /// Shows episodes. + /// + Episodes = 5, + + /// + /// Shows favorites. + /// + Favorites = 6, + + /// + /// Shows genres. + /// + Genres = 7, + + /// + /// Shows guide. + /// + Guide = 8, + + /// + /// Shows movies. + /// + Movies = 9, + + /// + /// Shows networks. + /// + Networks = 10, + + /// + /// Shows playlists. + /// + Playlists = 11, + + /// + /// Shows programs. + /// + Programs = 12, + + /// + /// Shows recordings. + /// + Recordings = 13, + + /// + /// Shows schedule. + /// + Schedule = 14, + + /// + /// Shows series. + /// + Series = 15, + + /// + /// Shows shows. + /// + Shows = 16, + + /// + /// Shows songs. + /// + Songs = 17, + + /// + /// Shows songs. + /// + Suggestions = 18, + + /// + /// Shows trailers. + /// + Trailers = 19, + + /// + /// Shows upcoming. + /// + Upcoming = 20 } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs index cc96792e6..074016553 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs @@ -1,9 +1,8 @@ -using System; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; -namespace Jellyfin.Server.Implementations; +namespace Jellyfin.Database.Implementations; /// /// Defines the type and extension points for multi database support. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs index a4d9c54af..03c2ca4a4 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasArtwork.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Jellyfin.Data.Entities.Libraries; -namespace Jellyfin.Data.Interfaces +namespace Jellyfin.Database.Implementations.Interfaces { /// /// An interface abstracting an entity that has artwork. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs index 8f19ce04f..ed449a8f1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasCompanies.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Jellyfin.Data.Entities.Libraries; -namespace Jellyfin.Data.Interfaces +namespace Jellyfin.Database.Implementations.Interfaces { /// /// An abstraction representing an entity that has companies. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasConcurrencyToken.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasConcurrencyToken.cs index 2c4091493..196d2680d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasConcurrencyToken.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasConcurrencyToken.cs @@ -1,18 +1,17 @@ -namespace Jellyfin.Data.Interfaces +namespace Jellyfin.Database.Implementations.Interfaces; + +/// +/// An interface abstracting an entity that has a concurrency token. +/// +public interface IHasConcurrencyToken { /// - /// An interface abstracting an entity that has a concurrency token. + /// Gets the version of this row. Acts as a concurrency token. /// - public interface IHasConcurrencyToken - { - /// - /// Gets the version of this row. Acts as a concurrency token. - /// - uint RowVersion { get; } + uint RowVersion { get; } - /// - /// Called when saving changes to this entity. - /// - void OnSavingChanges(); - } + /// + /// Called when saving changes to this entity. + /// + void OnSavingChanges(); } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs index 6d1eb59f6..606b1169b 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasPermissions.cs @@ -1,17 +1,15 @@ using System.Collections.Generic; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; -namespace Jellyfin.Data.Interfaces +namespace Jellyfin.Database.Implementations.Interfaces; + +/// +/// An abstraction representing an entity that has permissions. +/// +public interface IHasPermissions { /// - /// An abstraction representing an entity that has permissions. + /// Gets a collection containing this entity's permissions. /// - public interface IHasPermissions - { - /// - /// Gets a collection containing this entity's permissions. - /// - ICollection Permissions { get; } - } + ICollection Permissions { get; } } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs index 3b615893e..653572b6e 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Interfaces/IHasReleases.cs @@ -1,16 +1,15 @@ using System.Collections.Generic; using Jellyfin.Data.Entities.Libraries; -namespace Jellyfin.Data.Interfaces +namespace Jellyfin.Database.Implementations.Interfaces; + +/// +/// An abstraction representing an entity that has releases. +/// +public interface IHasReleases { /// - /// An abstraction representing an entity that has releases. + /// Gets a collection containing this entity's releases. /// - public interface IHasReleases - { - /// - /// Gets a collection containing this entity's releases. - /// - ICollection Releases { get; } - } + ICollection Releases { get; } } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDatabaseProviderKeyAttribute.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDatabaseProviderKeyAttribute.cs index b3ab3d094..778aca373 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDatabaseProviderKeyAttribute.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDatabaseProviderKeyAttribute.cs @@ -1,4 +1,4 @@ -namespace Jellyfin.Server.Implementations; +namespace Jellyfin.Database.Implementations; /// /// Defines the key of the database provider. @@ -16,7 +16,7 @@ public sealed class JellyfinDatabaseProviderKeyAttribute : System.Attribute /// The key on which to identify the annotated provider. public JellyfinDatabaseProviderKeyAttribute(string databaseProviderKey) { - this._databaseProviderKey = databaseProviderKey; + _databaseProviderKey = databaseProviderKey; } /// diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs index 024d595d5..5cdc85331 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs @@ -2,13 +2,11 @@ using System; using System.Linq; using Jellyfin.Data.Entities; using Jellyfin.Data.Entities.Security; -using Jellyfin.Data.Interfaces; +using Jellyfin.Database.Implementations.Interfaces; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Microsoft.EntityFrameworkCore.Metadata.Conventions; using Microsoft.Extensions.Logging; -namespace Jellyfin.Server.Implementations; +namespace Jellyfin.Database.Implementations; /// /// diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs index 9a63ed9f2..be99b46d5 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ActivityLogConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// FluentAPI configuration for the ActivityLog entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs index 8cc817fb8..146df5546 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AncestorIdConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// AncestorId configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs index 3f19b6986..7c15f064d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ApiKeyConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities.Security; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the ApiKey entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs index 057b6689a..b5fae4053 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/AttachmentStreamInfoConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// FluentAPI configuration for the AttachmentStreamInfo entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs index 08f2a3356..67a071039 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// Configuration for BaseItem. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs index b4c6511bf..c101e0085 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemMetadataFieldConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// Provides configuration for the BaseItemMetadataField entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs index d15049a1f..175a82e09 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemProviderConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// BaseItemProvider configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs index e9564b854..c7efef239 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/BaseItemTrailerTypeConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// Provides configuration for the BaseItemMetadataField entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs index 5a84f7750..5935b632a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ChapterConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// Chapter configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs index 779aec986..550fa5073 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the CustomItemDisplayPreferences entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs index a750b65c0..5f87c8d40 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities.Security; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the Device entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs index 038afd752..923a53aca 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities.Security; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the DeviceOptions entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs index 9b437861b..92068c8f2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the DisplayPreferencesConfiguration entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs index abeeb09c9..0e63c130e 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// itemvalues Configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs index 9c22b114c..3860b0e16 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/ItemValuesMapConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// itemvalues Configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs index 7e572f9a3..37e15f5e7 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/MediaStreamInfoConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// People configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs index cdaee9161..125b9e92c 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleBaseItemMapConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// People configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs index f3cccb13f..fe25d3064 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PeopleConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// People configuration. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs index 240e284c0..90a3ec5d0 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PermissionConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the Permission entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs index 49c869c6a..d6d3fadfc 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/PreferenceConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the Permission entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs index dc1c17e5e..a198c80f7 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/TrickplayInfoConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the TrickplayInfo entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs index bcaa3634e..4e830801e 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserConfiguration.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration +namespace Jellyfin.Database.Implementations.ModelConfiguration { /// /// FluentAPI configuration for the User entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs index 7bbb28d43..a7e223c43 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/ModelConfiguration/UserDataConfiguration.cs @@ -1,9 +1,8 @@ -using System; using Jellyfin.Data.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Jellyfin.Server.Implementations.ModelConfiguration; +namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// FluentAPI configuration for the UserData entity. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200514181226_AddActivityLog.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200514181226_AddActivityLog.Designer.cs index 80fe784dd..789100643 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200514181226_AddActivityLog.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200514181226_AddActivityLog.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200613202153_AddUsers.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200613202153_AddUsers.Designer.cs index 7aa4479b3..eab3cd3e7 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200613202153_AddUsers.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200613202153_AddUsers.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200728005145_AddDisplayPreferences.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200728005145_AddDisplayPreferences.Designer.cs index 3860c851d..91dd0ff7a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200728005145_AddDisplayPreferences.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200728005145_AddDisplayPreferences.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs index 1134f7aa4..8ec923103 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs index 607310caa..499faa9c4 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs index 02c3fc753..7ab851689 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs index 1cfd7112c..e14ed9380 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs index ecf7af495..05f2c80a2 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210814002109_AddDevices.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210814002109_AddDevices.Designer.cs index dccba6f77..c9f3cf696 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210814002109_AddDevices.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20210814002109_AddDevices.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs index e821c106e..ab7781d15 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs @@ -2,7 +2,7 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230526173516_RemoveEasyPassword.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230526173516_RemoveEasyPassword.Designer.cs index 360fa0376..8a2806113 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230526173516_RemoveEasyPassword.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230526173516_RemoveEasyPassword.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230626233818_AddTrickplayInfos.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230626233818_AddTrickplayInfos.Designer.cs index 17d33845f..a11507bd5 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230626233818_AddTrickplayInfos.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230626233818_AddTrickplayInfos.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230923170422_UserCastReceiver.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230923170422_UserCastReceiver.Designer.cs index 4c0917669..ddea37f6d 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230923170422_UserCastReceiver.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20230923170422_UserCastReceiver.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240729140605_AddMediaSegments.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240729140605_AddMediaSegments.Designer.cs index 35a3cdad2..ab7065ee6 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240729140605_AddMediaSegments.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240729140605_AddMediaSegments.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs index 8dba31a67..aa60bff32 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20240928082930_MarkSegmentProviderIdNonNullable.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241020103111_LibraryDbMigration.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241020103111_LibraryDbMigration.Designer.cs index 27745f601..2ea6dafe1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241020103111_LibraryDbMigration.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241020103111_LibraryDbMigration.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111131257_AddedCustomDataKey.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111131257_AddedCustomDataKey.Designer.cs index 1fbf21492..d589a4afd 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111131257_AddedCustomDataKey.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111131257_AddedCustomDataKey.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs index bac6fd5b5..3d70bb029 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241111135439_AddedCustomDataKeyKey.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs index ad622d44c..1e0d3b129 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112152323_FixAncestorIdConfig.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112232041_fixMediaStreams.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112232041_fixMediaStreams.Designer.cs index dc4c8212b..ccf67d899 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112232041_fixMediaStreams.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112232041_fixMediaStreams.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112234144_FixMediaStreams2.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112234144_FixMediaStreams2.Designer.cs index 5714120b5..d3ba8c96a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112234144_FixMediaStreams2.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241112234144_FixMediaStreams2.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs index 855f02fd3..2c0058c72 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20241113133548_EnforceUniqueItemValue.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250202021306_FixedCollation.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250202021306_FixedCollation.Designer.cs index d7b806d7a..da4bab3fd 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250202021306_FixedCollation.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250202021306_FixedCollation.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250204092455_MakeStartEndDateNullable.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250204092455_MakeStartEndDateNullable.Designer.cs index a329f1ef1..9b72d9688 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250204092455_MakeStartEndDateNullable.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250204092455_MakeStartEndDateNullable.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250214031148_ChannelIdGuid.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250214031148_ChannelIdGuid.Designer.cs index 48919c9b5..f5cfe86c4 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250214031148_ChannelIdGuid.Designer.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250214031148_ChannelIdGuid.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs index 79587a9c3..5d8ddde08 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs @@ -1,6 +1,6 @@ // using System; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/SqliteDesignTimeJellyfinDbFactory.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/SqliteDesignTimeJellyfinDbFactory.cs index 448bd2fc8..1629c732c 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/SqliteDesignTimeJellyfinDbFactory.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/SqliteDesignTimeJellyfinDbFactory.cs @@ -1,3 +1,4 @@ +using Jellyfin.Database.Implementations; using Jellyfin.Database.Providers.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ModelBuilderExtensions.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ModelBuilderExtensions.cs index 79ae1661a..0d7568619 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ModelBuilderExtensions.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/ModelBuilderExtensions.cs @@ -3,46 +3,45 @@ using Jellyfin.Server.Implementations.ValueConverters; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -namespace Jellyfin.Server.Implementations +namespace Jellyfin.Database.Providers.Sqlite; + +/// +/// Model builder extensions. +/// +public static class ModelBuilderExtensions { /// - /// Model builder extensions. + /// Specify value converter for the object type. /// - public static class ModelBuilderExtensions + /// The model builder. + /// The . + /// The type to convert. + /// The modified . + public static ModelBuilder UseValueConverterForType(this ModelBuilder modelBuilder, ValueConverter converter) { - /// - /// Specify value converter for the object type. - /// - /// The model builder. - /// The . - /// The type to convert. - /// The modified . - public static ModelBuilder UseValueConverterForType(this ModelBuilder modelBuilder, ValueConverter converter) + var type = typeof(T); + foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { - var type = typeof(T); - foreach (var entityType in modelBuilder.Model.GetEntityTypes()) + foreach (var property in entityType.GetProperties()) { - foreach (var property in entityType.GetProperties()) + if (property.ClrType == type) { - if (property.ClrType == type) - { - property.SetValueConverter(converter); - } + property.SetValueConverter(converter); } } - - return modelBuilder; } - /// - /// Specify the default . - /// - /// The model builder to extend. - /// The to specify. - public static void SetDefaultDateTimeKind(this ModelBuilder modelBuilder, DateTimeKind kind) - { - modelBuilder.UseValueConverterForType(new DateTimeKindValueConverter(kind)); - modelBuilder.UseValueConverterForType(new DateTimeKindValueConverter(kind)); - } + return modelBuilder; + } + + /// + /// Specify the default . + /// + /// The model builder to extend. + /// The to specify. + public static void SetDefaultDateTimeKind(this ModelBuilder modelBuilder, DateTimeKind kind) + { + modelBuilder.UseValueConverterForType(new DateTimeKindValueConverter(kind)); + modelBuilder.UseValueConverterForType(new DateTimeKindValueConverter(kind)); } } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs index 2aa3522d8..d9eb0ae7a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs @@ -2,7 +2,7 @@ using System; using System.IO; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Server.Implementations; +using Jellyfin.Database.Implementations; using MediaBrowser.Common.Configuration; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; diff --git a/src/Jellyfin.LiveTv/Channels/ChannelManager.cs b/src/Jellyfin.LiveTv/Channels/ChannelManager.cs index 83f68ab50..402a3f3b0 100644 --- a/src/Jellyfin.LiveTv/Channels/ChannelManager.cs +++ b/src/Jellyfin.LiveTv/Channels/ChannelManager.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using AsyncKeyedLock; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using Jellyfin.Extensions.Json; using MediaBrowser.Common.Extensions; diff --git a/src/Jellyfin.LiveTv/DefaultLiveTvService.cs b/src/Jellyfin.LiveTv/DefaultLiveTvService.cs index 318cc7acd..d8f873abe 100644 --- a/src/Jellyfin.LiveTv/DefaultLiveTvService.cs +++ b/src/Jellyfin.LiveTv/DefaultLiveTvService.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using Jellyfin.LiveTv.Configuration; using Jellyfin.LiveTv.Timers; diff --git a/src/Jellyfin.LiveTv/LiveTvManager.cs b/src/Jellyfin.LiveTv/LiveTvManager.cs index da98606a4..7ebcc4883 100644 --- a/src/Jellyfin.LiveTv/LiveTvManager.cs +++ b/src/Jellyfin.LiveTv/LiveTvManager.cs @@ -12,6 +12,7 @@ using Jellyfin.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.LiveTv.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Channels; diff --git a/src/Jellyfin.LiveTv/Recordings/RecordingNotifier.cs b/src/Jellyfin.LiveTv/Recordings/RecordingNotifier.cs index 1d571805b..a5d186ce1 100644 --- a/src/Jellyfin.LiveTv/Recordings/RecordingNotifier.cs +++ b/src/Jellyfin.LiveTv/Recordings/RecordingNotifier.cs @@ -3,8 +3,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data; -using Jellyfin.Data.Enums; using Jellyfin.Data.Events; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Session; diff --git a/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs b/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs index 2f4caa386..9ca5d7420 100644 --- a/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs +++ b/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.LiveTv.Configuration; using Jellyfin.LiveTv.IO; using Jellyfin.LiveTv.Timers; diff --git a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs index 6b3afc935..0a6489d0a 100644 --- a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs @@ -8,7 +8,7 @@ using Jellyfin.Api.Auth; using Jellyfin.Api.Constants; using Jellyfin.Data; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Authentication; diff --git a/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs index 31d2b486b..1fe9fc97e 100644 --- a/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs @@ -8,7 +8,7 @@ using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; using Jellyfin.Api.Auth.FirstTimeSetupPolicy; using Jellyfin.Api.Constants; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Library; using Microsoft.AspNetCore.Authorization; diff --git a/tests/Jellyfin.Api.Tests/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandlerTests.cs index 534d1863c..ed5235252 100644 --- a/tests/Jellyfin.Api.Tests/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandlerTests.cs @@ -6,7 +6,7 @@ using AutoFixture.AutoMoq; using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; using Jellyfin.Api.Constants; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Library; using Microsoft.AspNetCore.Authorization; diff --git a/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs index a2d1b3607..2851b08e6 100644 --- a/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs +++ b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs @@ -5,6 +5,7 @@ using System.Security.Claims; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Net; using Xunit; diff --git a/tests/Jellyfin.Api.Tests/TestHelpers.cs b/tests/Jellyfin.Api.Tests/TestHelpers.cs index d84da89e2..03884d775 100644 --- a/tests/Jellyfin.Api.Tests/TestHelpers.cs +++ b/tests/Jellyfin.Api.Tests/TestHelpers.cs @@ -6,7 +6,7 @@ using System.Security.Claims; using Jellyfin.Api.Constants; using Jellyfin.Data; using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Server.Implementations.Users; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Library; -- cgit v1.2.3 From 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 4a0662e16..60f515f24 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 356d1e437..0ce967e6a 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 fb0a55135..933cfc8cb 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 846663900..27f682668 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 863195836..afe5b14e9 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 ffbf8068f..28cf69500 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 9253a9a69..9d81b835c 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 2a2813151..8b88b904b 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 22baafbb0..5a9315a92 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 9e780a49e..7b0a16441 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 db3aeaaf3..a5be2b616 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 959373fec..42f7deca1 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 e1c26d012..9afc51108 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 d668c17bf..4c013a8bd 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 622a341b6..cf7786167 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 2a3e456c2..e42c8a33a 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 afd8ccf9f..f54188030 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 12f88bf4d..dd2149b57 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 a7821c0e0..d47e47793 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 74db077d8..ee2e18f73 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 2da483913..7ba75dc24 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 2196616dd..13064882c 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 1fd57eba9..dd60d01e0 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 b71199026..e7b7405ca 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 e326b925b..c4b976756 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 ff4540f58..bde1758e9 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 09a7b73b9..363acf815 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 0cb20e433..1e45e53ca 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 b0c493fbe..4d12dc18f 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 794c6500c..1577b4594 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 43c5384dc..52cb87e72 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 5075d91be..52982c362 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 6cc2b4244..0e04beb14 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 bbfa270db..ebf98da45 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 648716030..ebd0288ca 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 1801b6bfd..7b493d3fa 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 3c2691cb5..e10e940f2 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 b3b8d2831..8de34fec2 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 d57c917c9..c85de34de 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 447594821..46b399d26 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 a235ccada..ee41147d5 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 780ace6ab..0f2763f36 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 8bf82265c..149fc9042 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 007a468bf..8d492f7cd 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 e414a8232..51a118645 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 0d52bb985..5f4864e95 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 0a8c064a9..8fe380e4f 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 a4424c739..1a8931a6d 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 e0ecef2a5..584d559e4 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 0ef929a99..73323acb3 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 7d452ea2f..b75567539 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 77e7859c6..b90708a2f 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 141dc20ea..139c2e2ac 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 b0a9393eb..da82a3b30 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 0ae9b7f66..632f30c7a 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 287ba578b..4b49b714c 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 2de207b15..2d24de7fc 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 08d6bf9c2..e892d3dd9 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 a09c344f6..4f063f6a1 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 46da8044a..ba4a072e8 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 1d0d016a7..bbc00567d 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 2b8f966a8..7219704ec 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 1f04b2829..4f6902244 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 48b94a5f3..93e15735c 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 18167cc53..3ae6dbd70 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 f70071884..36c3b9e56 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 01a0ade63..51040cee7 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 fa507ad04..d6eeafacc 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 534e80f4e..cf0293463 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 b55d2271a..bf39f13a7 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 acada7aa4..35c43b176 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 cefbd0624..6296881a9 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 02a52e5f2..92e2bb4fa 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 3f9491038..0f21e11a3 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 c4e4c460a..caf9d5bd9 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 0105f8162..3c39e5503 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 933d85de0..e9fe9abce 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 a50990ac5..feaf46c84 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 4f6c5100d..a8fa2e52a 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 490daae42..08eea0308 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 bd5bf98e0..c40560660 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 81b532fda..976a667ac 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 8c9d1baf8..592ce9955 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 f6cbf5a00..199e22b3f 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 38a78a67b..206b5ac42 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 fe7dc1cf9..ea38950d3 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 702ce39a2..4eeec99b0 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 22453f0f7..f1d507fcb 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 d6e659242..d016d8f62 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 39dc90963..58841e5b7 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 29481481c..1dd289631 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 b7b5dac03..ca79e6245 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 d3e9da622..dd85a6ec0 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 57a8a0113..5ce5fd4fa 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 3e1d89274..203a16a66 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 a252b7a25..d656fccb4 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 9dbac1e92..1293528fb 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 470702f3e..5dad15851 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 7ae4a4a2c..bc7e22d9a 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 f5ca3737c..dfa31315c 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 18845ab9f..c2b4da32a 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 10c0f56e0..a97096eae 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 4a9721acb..860e948af 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 13915dc5c..a3e3e4991 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 eb697268c..2b6781a19 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 7ba8fc20c..20764ec60 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 5a2deda66..eb46611dd 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 1c115be85..0109cf4b7 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 76e9eb1f5..b0a6782c7 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 c0e46ba24..8d59eef9f 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 caa312987..7586ac902 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 1e75446e1..456977b88 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 e452f2649..dd5eb9a01 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 53e04066f..1062399e3 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 5dd0413b4..21131e6b5 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 66a0c5254..97f653edf 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 800317800..9ac8ead11 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 28073fb8d..95aa567ad 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 7e8949e1f..7bfd8ca29 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 643a1f9b1..01d5e3b6c 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 251ff5d68..40dc81397 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 aee720aa7..a2a3a9d1b 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 ba0eaf21c..3d430e101 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 909e8750f..e23ac86aa 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 3a7678405..bf623be7e 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 954416dfe..3d25ae4f4 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 19265a011..aab3082b3 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 42be5b3b9..fc9695a09 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 54aef50e4..46a59f790 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 ac6b72ace..71d60fc25 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 27bbfc473..e7dbc8e9f 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 c0c5e3147..73bb583e3 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 2bb648138..db329ad2a 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 579442cdb..f9b981328 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 a60659512..b3d4b16bc 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 82bf007a8..ae6966e59 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 4b343c164..9dd248646 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 edffec4ab..584550ac5 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 935a53a26..9c0b36852 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 f78178dd2..6052a95bb 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 7e75a200b..677053114 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 11d8e383e..b5a31921d 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 e80a9aec3..23f6e0f7b 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 3bae3becc..9e2e11c00 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 b529da8fa..f3083a96b 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 54c30d92c..b56c1f940 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 7b1a68bb5..a284d563a 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 cbcb9a5f5..eac973060 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 8da9793f9..03b68317a 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 4bd99d83a..3777c705b 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 5dc1039a1..c686751ab 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 a29f08c7f..fdf1f274f 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 92307afec..70e47d6bc 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 af2393870..660e535e3 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 637975526..7cb71f06d 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 b0ef11e0f..b5c2c3c2a 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 329b8973f..442dced2f 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 401d58ff2..e5cbab7e4 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 17673cb1d..d1877ef43 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 975614be1..4fccf6d73 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 0913f95be..6e435579c 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 3170653fe..4552386fe 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 afaebb8e8..dc8f15350 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 fa36e58db..b7c9313a2 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 beae325ec..afc0e0f43 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 df48ebf27..3d797d97e 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 d6231bbf0..51f77ce0b 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 691f3504f..bfb94c44d 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 d9609f1cc..25cdfdc2e 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 627f74140..e1c211390 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 094d57139..b113170e1 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 6c284307d..6fae4a024 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 6b792ffb4..627575024 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 91ee8caa1..832285599 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 40466def1..db148338e 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 fc110b49d..dc9f695d9 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 da40a075f..af1e9fa2b 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 ab484c96d..1e1633248 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 28da91e47..b1b2b10be 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 6d6a92022..f0bd88963 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 042d2b90d..d9b4736a7 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 8c1c071e6..c34369d88 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 b16b62b10..207317376 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 f57672a2c..33dd81bdd 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 18c778b17..20cf3e2d9 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 bfaaf8215..c719a185c 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 c488b90e1..84b86574c 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 f4f9dd17a..c02ea7375 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 9d79e5ddb..cb7255c19 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 1fcbe0f5e..25a1d5ce9 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 67d7f78ed..b0f9b2d56 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 531f66c62..8ac3e364c 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 ff9a68bef..06b290e4f 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 aafa92b4a..31538b5bf 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 ced12b9e6..cd8068661 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 fed092b97..a6e8732ff 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 03c2ca4a4..46007472a 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 ed449a8f1..5cfefa456 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 606b1169b..99b29e6d3 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 653572b6e..742a6a386 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 5cdc85331..9db70263d 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 be99b46d5..a209c5b90 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 146df5546..1cb4a1eb1 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 7c15f064d..ea382c718 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 b5fae4053..66cafc83c 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 67a071039..37816faec 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 c101e0085..a602ea65f 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 175a82e09..dd28000ba 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 c7efef239..2a888b7de 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 5935b632a..d97a39f4d 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 550fa5073..e8a510ab9 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 5f87c8d40..3551f7686 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 923a53aca..9055e8025 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 92068c8f2..45e0c6482 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 0e63c130e..c8e003eaa 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 3860b0e16..42ef23532 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 37e15f5e7..075af2c05 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 125b9e92c..5e3ab4443 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 fe25d3064..e8f77a806 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 90a3ec5d0..d2aed54eb 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 d6d3fadfc..207051bcd 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 a198c80f7..1b364a05e 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 4e830801e..61b5e06e8 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 a7e223c43..47604d321 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 4e5f63f6f..ac62ea59a 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 1629c732c..78815c311 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 0d7568619..41375874d 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 2e585c92d..d4a9407b0 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 fcb315b3a..7718f6c6a 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 402a3f3b0..0ca294a28 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 7ebcc4883..40adb51a5 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 0a6489d0a..7e44b062c 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 162a022f5..bfc7016d2 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 1fe9fc97e..fc243a873 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 ed5235252..6e63c0450 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 c7331c718..a74dab5f2 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 03884d775..eff14e5f1 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 3fe2caca7..ba3abd5a2 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 9418edc5d..a5a67046d 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 a71a08d8c..e422eb9b8 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 27f682668..eb8e31072 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 5a9315a92..87214c273 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 4f6902244..7b5b6b94d 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 a3e3e4991..df90f546c 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 f1ed4fe27..e185898bf 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 eb8e31072..6a19a41cd 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 6a19a41cd..c6b8501cb 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 89311142c..f9e111b38 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 8f89f35ac..6722c20da 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 eb8e31072..62f1f3d3a 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 8b88b904b..be1d96bf0 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 ba4a2a59c..d8aaf5ba0 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 474f09dc5..4fca94477 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 693bf90e7..f4e6c8e2c 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 07b53bf74..9e7a8c844 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 ae1a2fd71..0dcce1ea1 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 3219472ef..528906589 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 12bc22a6a..a3134f3f6 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 db5bfdbf9..afbf6f8fa 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 62f1f3d3a..c8026960d 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 b4791b945..b9f9f2972 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 4debe722b..f1aeb1340 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 2c33ab492..51eb99f49 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 6722c20da..d99923b4f 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 0c9edd839..71ce3b601 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 754a01329..9598f9e6c 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 36886ba76..000000000 --- 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 000000000..b39015161 --- /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 6e12759a4..000000000 --- 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 000000000..a563df899 --- /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 d171a7132..000000000 --- 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 000000000..18ea2c260 --- /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 f6053c88c..000000000 --- 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 000000000..f455b6643 --- /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 41dbda134..000000000 --- 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 000000000..fa43a8f2b --- /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 000000000..086619471 --- /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 e1e96c590..000000000 --- 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 000000000..4eff6dcc5 --- /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 f6181575e..000000000 --- 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 000000000..30c34b230 --- /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 4ef63b2ea..000000000 --- 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 000000000..9fcd6d44f --- /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 ee5866090..000000000 --- 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 000000000..c19629939 --- /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 7ff92f259..000000000 --- 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 000000000..3152317b5 --- /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 139ea376b..000000000 --- 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 000000000..e8bafd6b8 --- /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 858b9a32d..000000000 --- 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 000000000..7fc88272c --- /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 d3c634fc9..000000000 --- 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 000000000..f6cc56ed6 --- /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 bfb5fdaae..000000000 --- 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 000000000..efff9e92c --- /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 e26b32b67..000000000 --- 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 000000000..0f8f0c68e --- /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 305912f23..000000000 --- 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 000000000..9dc3b89bd --- /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 44f372b2d..000000000 --- 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 000000000..2e43eb83a --- /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 6856a2dbb..000000000 --- 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 000000000..a5e952316 --- /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 633da78fe..000000000 --- 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 000000000..3c1332271 --- /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 44c23e248..000000000 --- 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 000000000..9cf735a54 --- /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 8b264070b..000000000 --- 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 000000000..d1b8b13aa --- /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 e129c3561..000000000 --- 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 000000000..70084995d --- /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 dbafd8efa..000000000 --- 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 000000000..5ec6111ec --- /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 75b1c2058..000000000 --- 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 000000000..7fc88272c --- /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 9aa5c00eb..000000000 --- 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 000000000..08a637312 --- /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 b4ee2c723..789af01cc 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 803c2f1f7..a49128336 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 f65d95c41..bbce5a9e1 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 000000000..d70ac672f --- /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 b0a36b3ae..08c024f43 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 3c39e5503..3dfb14d71 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 49568b087..68a3491b5 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 9c2184029..c38beb723 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 c40560660..1b5fab7a8 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 53c832ff3..d48426672 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 5ce5fd4fa..9a83dba45 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 a3035bf61..2f3a5d117 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 c92640818..4f1198902 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 000000000..69be74ac0 --- /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 000000000..b9bb99685 --- /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 000000000..b452f2901 --- /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 20deaa505..d9df95325 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 49d7c0bcb..6605064ad 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 3d430e101..2c393ca86 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 e8994693d..45f66f85f 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 fc9695a09..332dec2e6 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 31538b5bf..4da7074ec 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 000000000..d6befbe5e --- /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 000000000..71f56a149 --- /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 5d8ddde08..8b2b26934 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 5babc9117..026da4992 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 c8026960d..ab8884f17 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 63481b1f8..9a80eafe5 100644 --- a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs +++ b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs @@ -1,14 +1,14 @@ #pragma warning disable CS1591 using System; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Database.Implementations; -using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Trickplay; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -19,15 +19,18 @@ public class CleanDatabaseScheduledTask : ILibraryPostScanTask private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; private readonly IDbContextFactory _dbProvider; + private readonly IPathManager _pathManager; public CleanDatabaseScheduledTask( ILibraryManager libraryManager, ILogger logger, - IDbContextFactory dbProvider) + IDbContextFactory dbProvider, + IPathManager pathManager) { _libraryManager = libraryManager; _logger = logger; _dbProvider = dbProvider; + _pathManager = pathManager; } public async Task Run(IProgress progress, CancellationToken cancellationToken) @@ -56,6 +59,38 @@ public class CleanDatabaseScheduledTask : ILibraryPostScanTask { _logger.LogInformation("Cleaning item {Item} type: {Type} path: {Path}", item.Name, item.GetType().Name, item.Path ?? string.Empty); + foreach (var mediaSource in item.GetMediaSources(false)) + { + // Delete extracted subtitles + try + { + var subtitleFolder = _pathManager.GetSubtitleFolderPath(mediaSource.Id); + if (Directory.Exists(subtitleFolder)) + { + Directory.Delete(subtitleFolder, true); + } + } + catch (Exception e) + { + _logger.LogWarning("Failed to remove subtitle cache folder for {Item}: {Exception}", item.Id, e.Message); + } + + // Delete extracted attachments + try + { + var attachmentFolder = _pathManager.GetAttachmentFolderPath(mediaSource.Id); + if (Directory.Exists(attachmentFolder)) + { + Directory.Delete(attachmentFolder, true); + } + } + catch (Exception e) + { + _logger.LogWarning("Failed to remove attachment cache folder for {Item}: {Exception}", item.Id, e.Message); + } + } + + // Delete item _libraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index ab8884f17..1303bb3cb 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -492,7 +492,24 @@ namespace Emby.Server.Implementations.Library if (item is Video video) { + // Trickplay list.Add(_pathManager.GetTrickplayDirectory(video)); + + // Subtitles and attachments + foreach (var mediaSource in item.GetMediaSources(false)) + { + var subtitleFolder = _pathManager.GetSubtitleFolderPath(mediaSource.Id); + if (subtitleFolder is not null) + { + list.Add(subtitleFolder); + } + + var attachmentFolder = _pathManager.GetAttachmentFolderPath(mediaSource.Id); + if (attachmentFolder is not null) + { + list.Add(attachmentFolder); + } + } } return list; diff --git a/Emby.Server.Implementations/Library/PathManager.cs b/Emby.Server.Implementations/Library/PathManager.cs index c910abadb..ac004b413 100644 --- a/Emby.Server.Implementations/Library/PathManager.cs +++ b/Emby.Server.Implementations/Library/PathManager.cs @@ -1,5 +1,7 @@ +using System; using System.Globalization; using System.IO; +using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; @@ -12,22 +14,56 @@ namespace Emby.Server.Implementations.Library; public class PathManager : IPathManager { private readonly IServerConfigurationManager _config; + private readonly IApplicationPaths _appPaths; /// /// Initializes a new instance of the class. /// /// The server configuration manager. + /// The application paths. public PathManager( - IServerConfigurationManager config) + IServerConfigurationManager config, + IApplicationPaths appPaths) { _config = config; + _appPaths = appPaths; + } + + private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles"); + + private string AttachmentCachePath => Path.Combine(_appPaths.DataPath, "attachments"); + + /// + public string GetAttachmentPath(string mediaSourceId, string fileName) + { + return Path.Join(GetAttachmentFolderPath(mediaSourceId), fileName); + } + + /// + public string GetAttachmentFolderPath(string mediaSourceId) + { + var id = Guid.Parse(mediaSourceId); + return Path.Join(AttachmentCachePath, id.ToString("D", CultureInfo.InvariantCulture)); + } + + /// + public string GetSubtitleFolderPath(string mediaSourceId) + { + var id = Guid.Parse(mediaSourceId); + return Path.Join(SubtitleCachePath, id.ToString("D", CultureInfo.InvariantCulture)); + } + + /// + public string GetSubtitlePath(string mediaSourceId, int streamIndex, string extension) + { + return Path.Join(GetSubtitleFolderPath(mediaSourceId), streamIndex.ToString(CultureInfo.InvariantCulture) + extension); } /// public string GetTrickplayDirectory(BaseItem item, bool saveWithMedia = false) { var basePath = _config.ApplicationPaths.TrickplayPath; - var idString = item.Id.ToString("N", CultureInfo.InvariantCulture); + var idString = item.Id.ToString("D", CultureInfo.InvariantCulture); return saveWithMedia ? Path.Combine(item.ContainingFolderPath, Path.ChangeExtension(item.Path, ".trickplay")) diff --git a/Jellyfin.Server/Migrations/MigrationRunner.cs b/Jellyfin.Server/Migrations/MigrationRunner.cs index baeea2c14..c3a2e1bc4 100644 --- a/Jellyfin.Server/Migrations/MigrationRunner.cs +++ b/Jellyfin.Server/Migrations/MigrationRunner.cs @@ -54,6 +54,7 @@ namespace Jellyfin.Server.Migrations typeof(Routines.FixAudioData), typeof(Routines.RemoveDuplicatePlaylistChildren), typeof(Routines.MigrateLibraryDb), + typeof(Routines.MoveExtractedFiles), typeof(Routines.MigrateRatingLevels), typeof(Routines.MoveTrickplayFiles), typeof(Routines.MigrateKeyframeData), diff --git a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs index f414b6e39..3fc9bea84 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs @@ -80,6 +80,7 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine using (var operation = GetPreparedDbContext("Cleanup database")) { + operation.JellyfinDbContext.AttachmentStreamInfos.ExecuteDelete(); operation.JellyfinDbContext.BaseItems.ExecuteDelete(); operation.JellyfinDbContext.ItemValues.ExecuteDelete(); operation.JellyfinDbContext.UserData.ExecuteDelete(); @@ -251,6 +252,29 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine } } + using (var operation = GetPreparedDbContext("moving AttachmentStreamInfos")) + { + const string mediaAttachmentQuery = + """ + SELECT ItemId, AttachmentIndex, Codec, CodecTag, Comment, filename, MIMEType + FROM mediaattachments + WHERE EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = mediaattachments.ItemId) + """; + + using (new TrackedMigrationStep("loading AttachmentStreamInfos", _logger)) + { + foreach (SqliteDataReader dto in connection.Query(mediaAttachmentQuery)) + { + operation.JellyfinDbContext.AttachmentStreamInfos.Add(GetMediaAttachment(dto)); + } + } + + using (new TrackedMigrationStep($"saving {operation.JellyfinDbContext.AttachmentStreamInfos.Local.Count} AttachmentStreamInfos entries", _logger)) + { + operation.JellyfinDbContext.SaveChanges(); + } + } + using (var operation = GetPreparedDbContext("moving People")) { const string personsQuery = @@ -709,6 +733,48 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine return item; } + /// + /// Gets the attachment. + /// + /// The reader. + /// MediaAttachment. + private AttachmentStreamInfo GetMediaAttachment(SqliteDataReader reader) + { + var item = new AttachmentStreamInfo + { + Index = reader.GetInt32(1), + Item = null!, + ItemId = reader.GetGuid(0), + }; + + if (reader.TryGetString(2, out var codec)) + { + item.Codec = codec; + } + + if (reader.TryGetString(3, out var codecTag)) + { + item.CodecTag = codecTag; + } + + if (reader.TryGetString(4, out var comment)) + { + item.Comment = comment; + } + + if (reader.TryGetString(5, out var fileName)) + { + item.Filename = fileName; + } + + if (reader.TryGetString(6, out var mimeType)) + { + item.MimeType = mimeType; + } + + return item; + } + private (BaseItemEntity BaseItem, string[] LegacyUserDataKey) GetItem(SqliteDataReader reader) { var entity = new BaseItemEntity() diff --git a/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs b/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs new file mode 100644 index 000000000..f63c5fd40 --- /dev/null +++ b/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs @@ -0,0 +1,299 @@ +#pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms + +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using Jellyfin.Data.Enums; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.MediaInfo; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Migrations.Routines; + +/// +/// Migration to move extracted files to the new directories. +/// +public class MoveExtractedFiles : IDatabaseMigrationRoutine +{ + private readonly IApplicationPaths _appPaths; + private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; + private readonly IMediaSourceManager _mediaSourceManager; + private readonly IPathManager _pathManager; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// The logger. + /// Instance of the interface. + /// Instance of the interface. + public MoveExtractedFiles( + IApplicationPaths appPaths, + ILibraryManager libraryManager, + ILogger logger, + IMediaSourceManager mediaSourceManager, + IPathManager pathManager) + { + _appPaths = appPaths; + _libraryManager = libraryManager; + _logger = logger; + _mediaSourceManager = mediaSourceManager; + _pathManager = pathManager; + } + + private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles"); + + private string AttachmentCachePath => Path.Combine(_appPaths.DataPath, "attachments"); + + /// + public Guid Id => new("9063b0Ef-CFF1-4EDC-9A13-74093681A89B"); + + /// + public string Name => "MoveExtractedFiles"; + + /// + public bool PerformOnNewInstall => false; + + /// + public void Perform() + { + const int Limit = 500; + int itemCount = 0, offset = 0; + + var sw = Stopwatch.StartNew(); + var itemsQuery = new InternalItemsQuery + { + MediaTypes = [MediaType.Video], + SourceTypes = [SourceType.Library], + IsVirtualItem = false, + IsFolder = false, + Limit = Limit, + StartIndex = offset, + EnableTotalRecordCount = true, + }; + + var records = _libraryManager.GetItemsResult(itemsQuery).TotalRecordCount; + _logger.LogInformation("Checking {Count} items for movable extracted files.", records); + + // Make sure directories exist + Directory.CreateDirectory(SubtitleCachePath); + Directory.CreateDirectory(AttachmentCachePath); + + itemsQuery.EnableTotalRecordCount = false; + do + { + itemsQuery.StartIndex = offset; + var result = _libraryManager.GetItemsResult(itemsQuery); + + var items = result.Items; + foreach (var item in items) + { + if (MoveSubtitleAndAttachmentFiles(item)) + { + itemCount++; + } + } + + offset += Limit; + if (offset % 5_000 == 0) + { + _logger.LogInformation("Checked extracted files for {Count} items in {Time}.", offset, sw.Elapsed); + } + } while (offset < records); + + _logger.LogInformation("Checked {Checked} items - Moved files for {Items} items in {Time}.", records, itemCount, sw.Elapsed); + + // Get all subdirectories with 1 character names (those are the legacy directories) + var subdirectories = Directory.GetDirectories(SubtitleCachePath, "*", SearchOption.AllDirectories).Where(s => s.Length == SubtitleCachePath.Length + 2).ToList(); + subdirectories.AddRange(Directory.GetDirectories(AttachmentCachePath, "*", SearchOption.AllDirectories).Where(s => s.Length == AttachmentCachePath.Length + 2)); + + // Remove all legacy subdirectories + foreach (var subdir in subdirectories) + { + Directory.Delete(subdir, true); + } + + // Remove old cache path + var attachmentCachePath = Path.Join(_appPaths.CachePath, "attachments"); + if (Directory.Exists(attachmentCachePath)) + { + Directory.Delete(attachmentCachePath, true); + } + + _logger.LogInformation("Cleaned up left over subtitles and attachments."); + } + + private bool MoveSubtitleAndAttachmentFiles(BaseItem item) + { + var mediaStreams = item.GetMediaStreams().Where(s => s.Type == MediaStreamType.Subtitle && !s.IsExternal); + var itemIdString = item.Id.ToString("N", CultureInfo.InvariantCulture); + var modified = false; + foreach (var mediaStream in mediaStreams) + { + if (mediaStream.Codec is null) + { + continue; + } + + var mediaStreamIndex = mediaStream.Index; + var extension = GetSubtitleExtension(mediaStream.Codec); + var oldSubtitleCachePath = GetOldSubtitleCachePath(item.Path, mediaStream.Index, extension); + if (string.IsNullOrEmpty(oldSubtitleCachePath) || !File.Exists(oldSubtitleCachePath)) + { + continue; + } + + var newSubtitleCachePath = _pathManager.GetSubtitlePath(itemIdString, mediaStreamIndex, extension); + if (File.Exists(newSubtitleCachePath)) + { + File.Delete(oldSubtitleCachePath); + } + else + { + var newDirectory = Path.GetDirectoryName(newSubtitleCachePath); + if (newDirectory is not null) + { + Directory.CreateDirectory(newDirectory); + File.Move(oldSubtitleCachePath, newSubtitleCachePath, false); + _logger.LogDebug("Moved subtitle {Index} for {Item} from {Source} to {Destination}", mediaStreamIndex, item.Id, oldSubtitleCachePath, newSubtitleCachePath); + + modified = true; + } + } + } + + var attachments = _mediaSourceManager.GetMediaAttachments(item.Id).Where(a => !string.Equals(a.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)).ToList(); + var shouldExtractOneByOne = attachments.Any(a => !string.IsNullOrEmpty(a.FileName) + && (a.FileName.Contains('/', StringComparison.OrdinalIgnoreCase) || a.FileName.Contains('\\', StringComparison.OrdinalIgnoreCase))); + foreach (var attachment in attachments) + { + var attachmentIndex = attachment.Index; + var oldAttachmentPath = GetOldAttachmentDataPath(item.Path, attachmentIndex); + if (string.IsNullOrEmpty(oldAttachmentPath) || !File.Exists(oldAttachmentPath)) + { + oldAttachmentPath = GetOldAttachmentCachePath(itemIdString, attachment, shouldExtractOneByOne); + if (string.IsNullOrEmpty(oldAttachmentPath) || !File.Exists(oldAttachmentPath)) + { + continue; + } + } + + var newAttachmentPath = _pathManager.GetAttachmentPath(itemIdString, attachment.FileName ?? attachmentIndex.ToString(CultureInfo.InvariantCulture)); + if (File.Exists(newAttachmentPath)) + { + File.Delete(oldAttachmentPath); + } + else + { + var newDirectory = Path.GetDirectoryName(newAttachmentPath); + if (newDirectory is not null) + { + Directory.CreateDirectory(newDirectory); + File.Move(oldAttachmentPath, newAttachmentPath, false); + _logger.LogDebug("Moved attachment {Index} for {Item} from {Source} to {Destination}", attachmentIndex, item.Id, oldAttachmentPath, newAttachmentPath); + + modified = true; + } + } + } + + return modified; + } + + private string? GetOldAttachmentDataPath(string? mediaPath, int attachmentStreamIndex) + { + if (mediaPath is null) + { + return null; + } + + string filename; + var protocol = _mediaSourceManager.GetPathProtocol(mediaPath); + if (protocol == MediaProtocol.File) + { + DateTime? date; + try + { + date = File.GetLastWriteTimeUtc(mediaPath); + } + catch (IOException e) + { + _logger.LogDebug("Skipping attachment at index {Index} for {Path}: {Exception}", attachmentStreamIndex, mediaPath, e.Message); + + return null; + } + + filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Value.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture); + } + else + { + filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture); + } + + return Path.Join(_appPaths.DataPath, "attachments", filename[..1], filename); + } + + private string? GetOldAttachmentCachePath(string mediaSourceId, MediaAttachment attachment, bool shouldExtractOneByOne) + { + var attachmentFolderPath = Path.Join(_appPaths.CachePath, "attachments", mediaSourceId); + if (shouldExtractOneByOne) + { + return Path.Join(attachmentFolderPath, attachment.Index.ToString(CultureInfo.InvariantCulture)); + } + + if (string.IsNullOrEmpty(attachment.FileName)) + { + return null; + } + + return Path.Join(attachmentFolderPath, attachment.FileName); + } + + private string? GetOldSubtitleCachePath(string path, int streamIndex, string outputSubtitleExtension) + { + DateTime? date; + try + { + date = File.GetLastWriteTimeUtc(path); + } + catch (IOException e) + { + _logger.LogDebug("Skipping subtitle at index {Index} for {Path}: {Exception}", streamIndex, path, e.Message); + + return null; + } + + var ticksParam = string.Empty; + ReadOnlySpan filename = new Guid(MD5.HashData(Encoding.Unicode.GetBytes(path + "_" + streamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Value.Ticks.ToString(CultureInfo.InvariantCulture) + ticksParam))) + outputSubtitleExtension; + + return Path.Join(SubtitleCachePath, filename[..1], filename); + } + + private static string GetSubtitleExtension(string codec) + { + if (codec.ToLower(CultureInfo.InvariantCulture).Equals("ass", StringComparison.OrdinalIgnoreCase) + || codec.ToLower(CultureInfo.InvariantCulture).Equals("ssa", StringComparison.OrdinalIgnoreCase)) + { + return "." + codec; + } + else if (codec.Contains("pgs", StringComparison.OrdinalIgnoreCase)) + { + return ".sup"; + } + else + { + return ".srt"; + } + } +} diff --git a/MediaBrowser.Controller/IO/IPathManager.cs b/MediaBrowser.Controller/IO/IPathManager.cs index 036889810..7c20164a6 100644 --- a/MediaBrowser.Controller/IO/IPathManager.cs +++ b/MediaBrowser.Controller/IO/IPathManager.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Dto; namespace MediaBrowser.Controller.IO; @@ -14,4 +15,35 @@ public interface IPathManager /// Whether or not the tile should be saved next to the media file. /// The absolute path. public string GetTrickplayDirectory(BaseItem item, bool saveWithMedia = false); + + /// + /// Gets the path to the subtitle file. + /// + /// The media source id. + /// The stream index. + /// The subtitle file extension. + /// The absolute path. + public string GetSubtitlePath(string mediaSourceId, int streamIndex, string extension); + + /// + /// Gets the path to the subtitle file. + /// + /// The media source id. + /// The absolute path. + public string GetSubtitleFolderPath(string mediaSourceId); + + /// + /// Gets the path to the attachment file. + /// + /// The media source id. + /// The attachmentFileName index. + /// The absolute path. + public string GetAttachmentPath(string mediaSourceId, string fileName); + + /// + /// Gets the path to the attachment folder. + /// + /// The media source id. + /// The absolute path. + public string GetAttachmentFolderPath(string mediaSourceId); } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index afa962a41..75b3f151d 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -19,6 +19,7 @@ using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Extensions; +using MediaBrowser.Controller.IO; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; @@ -55,6 +56,7 @@ namespace MediaBrowser.Controller.MediaEncoding private readonly ISubtitleEncoder _subtitleEncoder; private readonly IConfiguration _config; private readonly IConfigurationManager _configurationManager; + private readonly IPathManager _pathManager; // i915 hang was fixed by linux 6.2 (3f882f2) private readonly Version _minKerneli915Hang = new Version(5, 18); @@ -153,13 +155,15 @@ namespace MediaBrowser.Controller.MediaEncoding IMediaEncoder mediaEncoder, ISubtitleEncoder subtitleEncoder, IConfiguration config, - IConfigurationManager configurationManager) + IConfigurationManager configurationManager, + IPathManager pathManager) { _appPaths = appPaths; _mediaEncoder = mediaEncoder; _subtitleEncoder = subtitleEncoder; _config = config; _configurationManager = configurationManager; + _pathManager = pathManager; } private enum DynamicHdrMetadataRemovalPlan @@ -1785,7 +1789,7 @@ namespace MediaBrowser.Controller.MediaEncoding var alphaParam = enableAlpha ? ":alpha=1" : string.Empty; var sub2videoParam = enableSub2video ? ":sub2video=1" : string.Empty; - var fontPath = Path.Combine(_appPaths.CachePath, "attachments", state.MediaSource.Id); + var fontPath = _pathManager.GetAttachmentFolderPath(state.MediaSource.Id); var fontParam = string.Format( CultureInfo.InvariantCulture, ":fontsdir='{0}'", diff --git a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs index 09840d2ee..d8d136472 100644 --- a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs +++ b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs @@ -9,26 +9,33 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -namespace MediaBrowser.Controller.MediaEncoding -{ - public interface IAttachmentExtractor - { - Task<(MediaAttachment Attachment, Stream Stream)> GetAttachment( - BaseItem item, - string mediaSourceId, - int attachmentStreamIndex, - CancellationToken cancellationToken); +namespace MediaBrowser.Controller.MediaEncoding; - Task ExtractAllAttachments( - string inputFile, - MediaSourceInfo mediaSource, - string outputPath, - CancellationToken cancellationToken); +public interface IAttachmentExtractor +{ + /// + /// Gets the path to the attachment file. + /// + /// The . + /// The media source id. + /// The attachment index. + /// The cancellation token. + /// The async task. + Task<(MediaAttachment Attachment, Stream Stream)> GetAttachment( + BaseItem item, + string mediaSourceId, + int attachmentStreamIndex, + CancellationToken cancellationToken); - Task ExtractAllAttachmentsExternal( - string inputArgument, - string id, - string outputPath, - CancellationToken cancellationToken); - } + /// + /// Gets the path to the attachment file. + /// + /// The input file path. + /// The source id. + /// The cancellation token. + /// The async task. + Task ExtractAllAttachments( + string inputFile, + MediaSourceInfo mediaSource, + CancellationToken cancellationToken); } diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 431fc0b17..89291c73b 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -1,7 +1,4 @@ -#pragma warning disable CS1591 - using System; -using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; @@ -9,28 +6,27 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; -using MediaBrowser.Common; -using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.MediaEncoding.Encoder; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; -using MediaBrowser.Model.MediaInfo; using Microsoft.Extensions.Logging; namespace MediaBrowser.MediaEncoding.Attachments { + /// public sealed class AttachmentExtractor : IAttachmentExtractor, IDisposable { private readonly ILogger _logger; - private readonly IApplicationPaths _appPaths; private readonly IFileSystem _fileSystem; private readonly IMediaEncoder _mediaEncoder; private readonly IMediaSourceManager _mediaSourceManager; + private readonly IPathManager _pathManager; private readonly AsyncKeyedLocker _semaphoreLocks = new(o => { @@ -38,18 +34,26 @@ namespace MediaBrowser.MediaEncoding.Attachments o.PoolInitialFill = 1; }); + /// + /// Initializes a new instance of the class. + /// + /// The . + /// The . + /// The . + /// The . + /// The . public AttachmentExtractor( ILogger logger, - IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, - IMediaSourceManager mediaSourceManager) + IMediaSourceManager mediaSourceManager, + IPathManager pathManager) { _logger = logger; - _appPaths = appPaths; _fileSystem = fileSystem; _mediaEncoder = mediaEncoder; _mediaSourceManager = mediaSourceManager; + _pathManager = pathManager; } /// @@ -77,350 +81,183 @@ namespace MediaBrowser.MediaEncoding.Attachments throw new ResourceNotFoundException($"MediaSource {mediaSourceId} has no attachment with stream index {attachmentStreamIndex}"); } + if (string.Equals(mediaAttachment.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)) + { + throw new ResourceNotFoundException($"Attachment with stream index {attachmentStreamIndex} can't be extracted for MediaSource {mediaSourceId}"); + } + var attachmentStream = await GetAttachmentStream(mediaSource, mediaAttachment, cancellationToken) .ConfigureAwait(false); return (mediaAttachment, attachmentStream); } + /// public async Task ExtractAllAttachments( string inputFile, MediaSourceInfo mediaSource, - string outputPath, CancellationToken cancellationToken) { var shouldExtractOneByOne = mediaSource.MediaAttachments.Any(a => !string.IsNullOrEmpty(a.FileName) && (a.FileName.Contains('/', StringComparison.OrdinalIgnoreCase) || a.FileName.Contains('\\', StringComparison.OrdinalIgnoreCase))); - if (shouldExtractOneByOne) - { - var attachmentIndexes = mediaSource.MediaAttachments.Select(a => a.Index); - foreach (var i in attachmentIndexes) - { - var newName = Path.Join(outputPath, i.ToString(CultureInfo.InvariantCulture)); - await ExtractAttachment(inputFile, mediaSource, i, newName, cancellationToken).ConfigureAwait(false); - } - } - else + if (shouldExtractOneByOne && !inputFile.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) { - using (await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false)) + foreach (var attachment in mediaSource.MediaAttachments) { - if (!Directory.Exists(outputPath)) + if (!string.Equals(attachment.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)) { - await ExtractAllAttachmentsInternal( - _mediaEncoder.GetInputArgument(inputFile, mediaSource), - outputPath, - false, - cancellationToken).ConfigureAwait(false); + await ExtractAttachment(inputFile, mediaSource, attachment, cancellationToken).ConfigureAwait(false); } } } - } - - public async Task ExtractAllAttachmentsExternal( - string inputArgument, - string id, - string outputPath, - CancellationToken cancellationToken) - { - using (await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false)) + else { - if (!File.Exists(Path.Join(outputPath, id))) - { - await ExtractAllAttachmentsInternal( - inputArgument, - outputPath, - true, - cancellationToken).ConfigureAwait(false); - - if (Directory.Exists(outputPath)) - { - File.Create(Path.Join(outputPath, id)); - } - } + await ExtractAllAttachmentsInternal( + inputFile, + mediaSource, + false, + cancellationToken).ConfigureAwait(false); } } private async Task ExtractAllAttachmentsInternal( - string inputPath, - string outputPath, + string inputFile, + MediaSourceInfo mediaSource, bool isExternal, CancellationToken cancellationToken) { - ArgumentException.ThrowIfNullOrEmpty(inputPath); - ArgumentException.ThrowIfNullOrEmpty(outputPath); - - Directory.CreateDirectory(outputPath); - - var processArgs = string.Format( - CultureInfo.InvariantCulture, - "-dump_attachment:t \"\" -y {0} -i {1} -t 0 -f null null", - inputPath.EndsWith(".concat\"", StringComparison.OrdinalIgnoreCase) ? "-f concat -safe 0" : string.Empty, - inputPath); - - int exitCode; - - using (var process = new Process - { - StartInfo = new ProcessStartInfo - { - Arguments = processArgs, - FileName = _mediaEncoder.EncoderPath, - UseShellExecute = false, - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - WorkingDirectory = outputPath, - ErrorDialog = false - }, - EnableRaisingEvents = true - }) - { - _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments); - - process.Start(); + var inputPath = _mediaEncoder.GetInputArgument(inputFile, mediaSource); - try - { - await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false); - exitCode = process.ExitCode; - } - catch (OperationCanceledException) - { - process.Kill(true); - exitCode = -1; - } - } - - var failed = false; + ArgumentException.ThrowIfNullOrEmpty(inputPath); - if (exitCode != 0) + var outputFolder = _pathManager.GetAttachmentFolderPath(mediaSource.Id); + using (await _semaphoreLocks.LockAsync(outputFolder, cancellationToken).ConfigureAwait(false)) { - if (isExternal && exitCode == 1) + if (!Directory.Exists(outputFolder)) { - // ffmpeg returns exitCode 1 because there is no video or audio stream - // this can be ignored + Directory.CreateDirectory(outputFolder); } else { - failed = true; - - _logger.LogWarning("Deleting extracted attachments {Path} due to failure: {ExitCode}", outputPath, exitCode); - try + var fileNames = Directory.GetFiles(outputFolder, "*", SearchOption.TopDirectoryOnly).Select(f => Path.GetFileName(f)); + var missingFiles = mediaSource.MediaAttachments.Where(a => !fileNames.Contains(a.FileName) && !string.Equals(a.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)); + if (!missingFiles.Any()) { - Directory.Delete(outputPath); - } - catch (IOException ex) - { - _logger.LogError(ex, "Error deleting extracted attachments {Path}", outputPath); + // Skip extraction if all files already exist + return; } } - } - else if (!Directory.Exists(outputPath)) - { - failed = true; - } - - if (failed) - { - _logger.LogError("ffmpeg attachment extraction failed for {InputPath} to {OutputPath}", inputPath, outputPath); - - throw new InvalidOperationException( - string.Format(CultureInfo.InvariantCulture, "ffmpeg attachment extraction failed for {0} to {1}", inputPath, outputPath)); - } - - _logger.LogInformation("ffmpeg attachment extraction completed for {InputPath} to {OutputPath}", inputPath, outputPath); - } - private async Task GetAttachmentStream( - MediaSourceInfo mediaSource, - MediaAttachment mediaAttachment, - CancellationToken cancellationToken) - { - var attachmentPath = await GetReadableFile(mediaSource.Path, mediaSource.Path, mediaSource, mediaAttachment, cancellationToken).ConfigureAwait(false); - return AsyncFile.OpenRead(attachmentPath); - } - - private async Task GetReadableFile( - string mediaPath, - string inputFile, - MediaSourceInfo mediaSource, - MediaAttachment mediaAttachment, - CancellationToken cancellationToken) - { - await CacheAllAttachments(mediaPath, inputFile, mediaSource, cancellationToken).ConfigureAwait(false); - - var outputPath = GetAttachmentCachePath(mediaPath, mediaSource, mediaAttachment.Index); - await ExtractAttachment(inputFile, mediaSource, mediaAttachment.Index, outputPath, cancellationToken) - .ConfigureAwait(false); - - return outputPath; - } + var processArgs = string.Format( + CultureInfo.InvariantCulture, + "-dump_attachment:t \"\" -y {0} -i {1} -t 0 -f null null", + inputPath.EndsWith(".concat\"", StringComparison.OrdinalIgnoreCase) ? "-f concat -safe 0" : string.Empty, + inputPath); - private async Task CacheAllAttachments( - string mediaPath, - string inputFile, - MediaSourceInfo mediaSource, - CancellationToken cancellationToken) - { - var outputFileLocks = new List(); - var extractableAttachmentIds = new List(); + int exitCode; - try - { - foreach (var attachment in mediaSource.MediaAttachments) + using (var process = new Process + { + StartInfo = new ProcessStartInfo + { + Arguments = processArgs, + FileName = _mediaEncoder.EncoderPath, + UseShellExecute = false, + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, + WorkingDirectory = outputFolder, + ErrorDialog = false + }, + EnableRaisingEvents = true + }) { - var outputPath = GetAttachmentCachePath(mediaPath, mediaSource, attachment.Index); + _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments); - var releaser = await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false); + process.Start(); - if (File.Exists(outputPath)) + try { - releaser.Dispose(); - continue; + await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false); + exitCode = process.ExitCode; } - - outputFileLocks.Add(releaser); - extractableAttachmentIds.Add(attachment.Index); - } - - if (extractableAttachmentIds.Count > 0) - { - await CacheAllAttachmentsInternal(mediaPath, _mediaEncoder.GetInputArgument(inputFile, mediaSource), mediaSource, extractableAttachmentIds, cancellationToken).ConfigureAwait(false); - } - } - catch (Exception ex) - { - _logger.LogWarning(ex, "Unable to cache media attachments for File:{File}", mediaPath); - } - finally - { - outputFileLocks.ForEach(x => x.Dispose()); - } - } - - private async Task CacheAllAttachmentsInternal( - string mediaPath, - string inputFile, - MediaSourceInfo mediaSource, - List extractableAttachmentIds, - CancellationToken cancellationToken) - { - var outputPaths = new List(); - var processArgs = string.Empty; - - foreach (var attachmentId in extractableAttachmentIds) - { - var outputPath = GetAttachmentCachePath(mediaPath, mediaSource, attachmentId); - - Directory.CreateDirectory(Path.GetDirectoryName(outputPath) ?? throw new FileNotFoundException($"Calculated path ({outputPath}) is not valid.")); - - outputPaths.Add(outputPath); - processArgs += string.Format( - CultureInfo.InvariantCulture, - " -dump_attachment:{0} \"{1}\"", - attachmentId, - EncodingUtils.NormalizePath(outputPath)); - } - - processArgs += string.Format( - CultureInfo.InvariantCulture, - " -i {0} -t 0 -f null null", - inputFile); - - int exitCode; - - using (var process = new Process - { - StartInfo = new ProcessStartInfo + catch (OperationCanceledException) { - Arguments = processArgs, - FileName = _mediaEncoder.EncoderPath, - UseShellExecute = false, - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - }, - EnableRaisingEvents = true - }) - { - _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments); - - process.Start(); - - try - { - await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false); - exitCode = process.ExitCode; - } - catch (OperationCanceledException) - { - process.Kill(true); - exitCode = -1; + process.Kill(true); + exitCode = -1; + } } - } - var failed = false; + var failed = false; - if (exitCode == -1) - { - failed = true; - - foreach (var outputPath in outputPaths) + if (exitCode != 0) { - try + if (isExternal && exitCode == 1) { - _logger.LogWarning("Deleting extracted media attachment due to failure: {Path}", outputPath); - _fileSystem.DeleteFile(outputPath); - } - catch (FileNotFoundException) - { - // ffmpeg failed, so it is normal that one or more expected output files do not exist. - // There is no need to log anything for the user here. + // ffmpeg returns exitCode 1 because there is no video or audio stream + // this can be ignored } - catch (IOException ex) + else { - _logger.LogError(ex, "Error deleting extracted media attachment {Path}", outputPath); + failed = true; + + _logger.LogWarning("Deleting extracted attachments {Path} due to failure: {ExitCode}", outputFolder, exitCode); + try + { + Directory.Delete(outputFolder); + } + catch (IOException ex) + { + _logger.LogError(ex, "Error deleting extracted attachments {Path}", outputFolder); + } } } - } - else - { - foreach (var outputPath in outputPaths) + else if (!Directory.Exists(outputFolder)) { - if (!File.Exists(outputPath)) - { - _logger.LogError("ffmpeg media attachment extraction failed for {InputPath} to {OutputPath}", inputFile, outputPath); - failed = true; - continue; - } + failed = true; + } - _logger.LogInformation("ffmpeg media attachment extraction completed for {InputPath} to {OutputPath}", inputFile, outputPath); + if (failed) + { + _logger.LogError("ffmpeg attachment extraction failed for {InputPath} to {OutputPath}", inputPath, outputFolder); + + throw new InvalidOperationException( + string.Format(CultureInfo.InvariantCulture, "ffmpeg attachment extraction failed for {0} to {1}", inputPath, outputFolder)); } - } - if (failed) - { - throw new FfmpegException( - string.Format(CultureInfo.InvariantCulture, "ffmpeg media attachment extraction failed for {0}", inputFile)); + _logger.LogInformation("ffmpeg attachment extraction completed for {InputPath} to {OutputPath}", inputPath, outputFolder); } } - private async Task ExtractAttachment( + private async Task GetAttachmentStream( + MediaSourceInfo mediaSource, + MediaAttachment mediaAttachment, + CancellationToken cancellationToken) + { + var attachmentPath = await ExtractAttachment(mediaSource.Path, mediaSource, mediaAttachment, cancellationToken) + .ConfigureAwait(false); + return AsyncFile.OpenRead(attachmentPath); + } + + private async Task ExtractAttachment( string inputFile, MediaSourceInfo mediaSource, - int attachmentStreamIndex, - string outputPath, + MediaAttachment mediaAttachment, CancellationToken cancellationToken) { - using (await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false)) + var attachmentFolderPath = _pathManager.GetAttachmentFolderPath(mediaSource.Id); + using (await _semaphoreLocks.LockAsync(attachmentFolderPath, cancellationToken).ConfigureAwait(false)) { - if (!File.Exists(outputPath)) + var attachmentPath = _pathManager.GetAttachmentPath(mediaSource.Id, mediaAttachment.FileName ?? mediaAttachment.Index.ToString(CultureInfo.InvariantCulture)); + if (!File.Exists(attachmentPath)) { await ExtractAttachmentInternal( _mediaEncoder.GetInputArgument(inputFile, mediaSource), - attachmentStreamIndex, - outputPath, + mediaAttachment.Index, + attachmentPath, cancellationToken).ConfigureAwait(false); } + + return attachmentPath; } } @@ -510,23 +347,6 @@ namespace MediaBrowser.MediaEncoding.Attachments _logger.LogInformation("ffmpeg attachment extraction completed for {InputPath} to {OutputPath}", inputPath, outputPath); } - private string GetAttachmentCachePath(string mediaPath, MediaSourceInfo mediaSource, int attachmentStreamIndex) - { - string filename; - if (mediaSource.Protocol == MediaProtocol.File) - { - var date = _fileSystem.GetLastWriteTimeUtc(mediaPath); - filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture); - } - else - { - filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture); - } - - var prefix = filename.AsSpan(0, 1); - return Path.Join(_appPaths.DataPath, "attachments", prefix, filename); - } - /// public void Dispose() { diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index a731d4785..777e33587 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -13,10 +13,10 @@ using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; using MediaBrowser.Common; -using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dto; @@ -31,12 +31,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles public sealed class SubtitleEncoder : ISubtitleEncoder, IDisposable { private readonly ILogger _logger; - private readonly IApplicationPaths _appPaths; private readonly IFileSystem _fileSystem; private readonly IMediaEncoder _mediaEncoder; private readonly IHttpClientFactory _httpClientFactory; private readonly IMediaSourceManager _mediaSourceManager; private readonly ISubtitleParser _subtitleParser; + private readonly IPathManager _pathManager; /// /// The _semaphoreLocks. @@ -49,24 +49,22 @@ namespace MediaBrowser.MediaEncoding.Subtitles public SubtitleEncoder( ILogger logger, - IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IHttpClientFactory httpClientFactory, IMediaSourceManager mediaSourceManager, - ISubtitleParser subtitleParser) + ISubtitleParser subtitleParser, + IPathManager pathManager) { _logger = logger; - _appPaths = appPaths; _fileSystem = fileSystem; _mediaEncoder = mediaEncoder; _httpClientFactory = httpClientFactory; _mediaSourceManager = mediaSourceManager; _subtitleParser = subtitleParser; + _pathManager = pathManager; } - private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles"); - private MemoryStream ConvertSubtitles( Stream stream, string inputFormat, @@ -830,26 +828,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles private string GetSubtitleCachePath(MediaSourceInfo mediaSource, int subtitleStreamIndex, string outputSubtitleExtension) { - if (mediaSource.Protocol == MediaProtocol.File) - { - var ticksParam = string.Empty; - - var date = _fileSystem.GetLastWriteTimeUtc(mediaSource.Path); - - ReadOnlySpan filename = (mediaSource.Path + "_" + subtitleStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture) + ticksParam).GetMD5() + outputSubtitleExtension; - - var prefix = filename.Slice(0, 1); - - return Path.Join(SubtitleCachePath, prefix, filename); - } - else - { - ReadOnlySpan filename = (mediaSource.Path + "_" + subtitleStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5() + outputSubtitleExtension; - - var prefix = filename.Slice(0, 1); - - return Path.Join(SubtitleCachePath, prefix, filename); - } + return _pathManager.GetSubtitlePath(mediaSource.Id, subtitleStreamIndex, outputSubtitleExtension); } /// diff --git a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs index c7f9cf2cc..0cda803d6 100644 --- a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs +++ b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs @@ -398,24 +398,19 @@ public sealed class TranscodeManager : ITranscodeManager, IDisposable // If subtitles get burned in fonts may need to be extracted from the media file if (state.SubtitleStream is not null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) { - var attachmentPath = Path.Combine(_appPaths.CachePath, "attachments", state.MediaSource.Id); if (state.MediaSource.VideoType == VideoType.Dvd || state.MediaSource.VideoType == VideoType.BluRay) { var concatPath = Path.Join(_appPaths.CachePath, "concat", state.MediaSource.Id + ".concat"); - await _attachmentExtractor.ExtractAllAttachments(concatPath, state.MediaSource, attachmentPath, cancellationTokenSource.Token).ConfigureAwait(false); + await _attachmentExtractor.ExtractAllAttachments(concatPath, state.MediaSource, cancellationTokenSource.Token).ConfigureAwait(false); } else { - await _attachmentExtractor.ExtractAllAttachments(state.MediaPath, state.MediaSource, attachmentPath, cancellationTokenSource.Token).ConfigureAwait(false); + await _attachmentExtractor.ExtractAllAttachments(state.MediaPath, state.MediaSource, cancellationTokenSource.Token).ConfigureAwait(false); } if (state.SubtitleStream.IsExternal && Path.GetExtension(state.SubtitleStream.Path.AsSpan()).Equals(".mks", StringComparison.OrdinalIgnoreCase)) { - string subtitlePath = state.SubtitleStream.Path; - string subtitlePathArgument = string.Format(CultureInfo.InvariantCulture, "file:\"{0}\"", subtitlePath.Replace("\"", "\\\"", StringComparison.Ordinal)); - string subtitleId = subtitlePath.GetMD5().ToString("N", CultureInfo.InvariantCulture); - - await _attachmentExtractor.ExtractAllAttachmentsExternal(subtitlePathArgument, subtitleId, attachmentPath, cancellationTokenSource.Token).ConfigureAwait(false); + await _attachmentExtractor.ExtractAllAttachments(state.SubtitleStream.Path, state.MediaSource, cancellationTokenSource.Token).ConfigureAwait(false); } } diff --git a/MediaBrowser.Model/Entities/MediaAttachment.cs b/MediaBrowser.Model/Entities/MediaAttachment.cs index 34e3eabc9..f8f7ad0f9 100644 --- a/MediaBrowser.Model/Entities/MediaAttachment.cs +++ b/MediaBrowser.Model/Entities/MediaAttachment.cs @@ -1,51 +1,49 @@ -#nullable disable -namespace MediaBrowser.Model.Entities +namespace MediaBrowser.Model.Entities; + +/// +/// Class MediaAttachment. +/// +public class MediaAttachment { /// - /// Class MediaAttachment. + /// Gets or sets the codec. /// - public class MediaAttachment - { - /// - /// Gets or sets the codec. - /// - /// The codec. - public string Codec { get; set; } + /// The codec. + public string? Codec { get; set; } - /// - /// Gets or sets the codec tag. - /// - /// The codec tag. - public string CodecTag { get; set; } + /// + /// Gets or sets the codec tag. + /// + /// The codec tag. + public string? CodecTag { get; set; } - /// - /// Gets or sets the comment. - /// - /// The comment. - public string Comment { get; set; } + /// + /// Gets or sets the comment. + /// + /// The comment. + public string? Comment { get; set; } - /// - /// Gets or sets the index. - /// - /// The index. - public int Index { get; set; } + /// + /// Gets or sets the index. + /// + /// The index. + public int Index { get; set; } - /// - /// Gets or sets the filename. - /// - /// The filename. - public string FileName { get; set; } + /// + /// Gets or sets the filename. + /// + /// The filename. + public string? FileName { get; set; } - /// - /// Gets or sets the MIME type. - /// - /// The MIME type. - public string MimeType { get; set; } + /// + /// Gets or sets the MIME type. + /// + /// The MIME type. + public string? MimeType { get; set; } - /// - /// Gets or sets the delivery URL. - /// - /// The delivery URL. - public string DeliveryUrl { get; set; } - } + /// + /// Gets or sets the delivery URL. + /// + /// The delivery URL. + public string? DeliveryUrl { get; set; } } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs index aab3082b3..2f27d9389 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/AttachmentStreamInfo.cs @@ -25,7 +25,7 @@ public class AttachmentStreamInfo /// /// Gets or Sets the codec of the attachment. /// - public required string Codec { get; set; } + public string? Codec { get; set; } /// /// Gets or Sets the codec tag of the attachment. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.Designer.cs new file mode 100644 index 000000000..d668eea92 --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.Designer.cs @@ -0,0 +1,1657 @@ +// +using System; +using Jellyfin.Database.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20250331182844_FixAttachmentMigration")] + partial class FixAttachmentMigration + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "9.0.3"); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AncestorId", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ParentItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AttachmentStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("Filename") + .HasColumnType("TEXT"); + + b.Property("MimeType") + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Album") + .HasColumnType("TEXT"); + + b.Property("AlbumArtists") + .HasColumnType("TEXT"); + + b.Property("Artists") + .HasColumnType("TEXT"); + + b.Property("Audio") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("TEXT"); + + b.Property("CleanName") + .HasColumnType("TEXT"); + + b.Property("CommunityRating") + .HasColumnType("REAL"); + + b.Property("CriticRating") + .HasColumnType("REAL"); + + b.Property("CustomRating") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastMediaAdded") + .HasColumnType("TEXT"); + + b.Property("DateLastRefreshed") + .HasColumnType("TEXT"); + + b.Property("DateLastSaved") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EpisodeTitle") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasColumnType("TEXT"); + + b.Property("ExternalSeriesId") + .HasColumnType("TEXT"); + + b.Property("ExternalServiceId") + .HasColumnType("TEXT"); + + b.Property("ExtraIds") + .HasColumnType("TEXT"); + + b.Property("ExtraType") + .HasColumnType("INTEGER"); + + b.Property("ForcedSortName") + .HasColumnType("TEXT"); + + b.Property("Genres") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IndexNumber") + .HasColumnType("INTEGER"); + + b.Property("InheritedParentalRatingSubValue") + .HasColumnType("INTEGER"); + + b.Property("InheritedParentalRatingValue") + .HasColumnType("INTEGER"); + + b.Property("IsFolder") + .HasColumnType("INTEGER"); + + b.Property("IsInMixedFolder") + .HasColumnType("INTEGER"); + + b.Property("IsLocked") + .HasColumnType("INTEGER"); + + b.Property("IsMovie") + .HasColumnType("INTEGER"); + + b.Property("IsRepeat") + .HasColumnType("INTEGER"); + + b.Property("IsSeries") + .HasColumnType("INTEGER"); + + b.Property("IsVirtualItem") + .HasColumnType("INTEGER"); + + b.Property("LUFS") + .HasColumnType("REAL"); + + b.Property("MediaType") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizationGain") + .HasColumnType("REAL"); + + b.Property("OfficialRating") + .HasColumnType("TEXT"); + + b.Property("OriginalTitle") + .HasColumnType("TEXT"); + + b.Property("Overview") + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("ParentIndexNumber") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataCountryCode") + .HasColumnType("TEXT"); + + b.Property("PreferredMetadataLanguage") + .HasColumnType("TEXT"); + + b.Property("PremiereDate") + .HasColumnType("TEXT"); + + b.Property("PresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("PrimaryVersionId") + .HasColumnType("TEXT"); + + b.Property("ProductionLocations") + .HasColumnType("TEXT"); + + b.Property("ProductionYear") + .HasColumnType("INTEGER"); + + b.Property("RunTimeTicks") + .HasColumnType("INTEGER"); + + b.Property("SeasonId") + .HasColumnType("TEXT"); + + b.Property("SeasonName") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("TEXT"); + + b.Property("SeriesName") + .HasColumnType("TEXT"); + + b.Property("SeriesPresentationUniqueKey") + .HasColumnType("TEXT"); + + b.Property("ShowId") + .HasColumnType("TEXT"); + + b.Property("Size") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("Studios") + .HasColumnType("TEXT"); + + b.Property("Tagline") + .HasColumnType("TEXT"); + + b.Property("Tags") + .HasColumnType("TEXT"); + + b.Property("TopParentId") + .HasColumnType("TEXT"); + + b.Property("TotalBitrate") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnratedType") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Blurhash") + .HasColumnType("BLOB"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("ImageType") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemMetadataField", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemProvider", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("ProviderValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemTrailerType", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Chapter", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ChapterIndex") + .HasColumnType("INTEGER"); + + b.Property("ImageDateModified") + .HasColumnType("TEXT"); + + b.Property("ImagePath") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("StartPositionTicks") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValue", b => + { + b.Property("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CleanValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue") + .IsUnique(); + + b.ToTable("ItemValues"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValueMap", b => + { + b.Property("ItemValueId") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EndTicks") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartTicks") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("StreamIndex") + .HasColumnType("INTEGER"); + + b.Property("AspectRatio") + .HasColumnType("TEXT"); + + b.Property("AverageFrameRate") + .HasColumnType("REAL"); + + b.Property("BitDepth") + .HasColumnType("INTEGER"); + + b.Property("BitRate") + .HasColumnType("INTEGER"); + + b.Property("BlPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("ChannelLayout") + .HasColumnType("TEXT"); + + b.Property("Channels") + .HasColumnType("INTEGER"); + + b.Property("Codec") + .HasColumnType("TEXT"); + + b.Property("CodecTag") + .HasColumnType("TEXT"); + + b.Property("CodecTimeBase") + .HasColumnType("TEXT"); + + b.Property("ColorPrimaries") + .HasColumnType("TEXT"); + + b.Property("ColorSpace") + .HasColumnType("TEXT"); + + b.Property("ColorTransfer") + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT"); + + b.Property("DvBlSignalCompatibilityId") + .HasColumnType("INTEGER"); + + b.Property("DvLevel") + .HasColumnType("INTEGER"); + + b.Property("DvProfile") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMajor") + .HasColumnType("INTEGER"); + + b.Property("DvVersionMinor") + .HasColumnType("INTEGER"); + + b.Property("ElPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("IsAnamorphic") + .HasColumnType("INTEGER"); + + b.Property("IsAvc") + .HasColumnType("INTEGER"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("IsExternal") + .HasColumnType("INTEGER"); + + b.Property("IsForced") + .HasColumnType("INTEGER"); + + b.Property("IsHearingImpaired") + .HasColumnType("INTEGER"); + + b.Property("IsInterlaced") + .HasColumnType("INTEGER"); + + b.Property("KeyFrames") + .HasColumnType("TEXT"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("REAL"); + + b.Property("NalLengthSize") + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PixelFormat") + .HasColumnType("TEXT"); + + b.Property("Profile") + .HasColumnType("TEXT"); + + b.Property("RealFrameRate") + .HasColumnType("REAL"); + + b.Property("RefFrames") + .HasColumnType("INTEGER"); + + b.Property("Rotation") + .HasColumnType("INTEGER"); + + b.Property("RpuPresentFlag") + .HasColumnType("INTEGER"); + + b.Property("SampleRate") + .HasColumnType("INTEGER"); + + b.Property("StreamType") + .HasColumnType("INTEGER"); + + b.Property("TimeBase") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PersonType") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.PeopleBaseItemMap", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("PeopleId") + .HasColumnType("TEXT"); + + b.Property("ListOrder") + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property("DateModified") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CustomName") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("Width") + .HasColumnType("INTEGER"); + + b.Property("Bandwidth") + .HasColumnType("INTEGER"); + + b.Property("Height") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("ThumbnailCount") + .HasColumnType("INTEGER"); + + b.Property("TileHeight") + .HasColumnType("INTEGER"); + + b.Property("TileWidth") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalRatingScore") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalRatingSubScore") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.UserData", b => + { + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("CustomDataKey") + .HasColumnType("TEXT"); + + b.Property("AudioStreamIndex") + .HasColumnType("INTEGER"); + + b.Property("IsFavorite") + .HasColumnType("INTEGER"); + + b.Property("LastPlayedDate") + .HasColumnType("TEXT"); + + b.Property("Likes") + .HasColumnType("INTEGER"); + + b.Property("PlayCount") + .HasColumnType("INTEGER"); + + b.Property("PlaybackPositionTicks") + .HasColumnType("INTEGER"); + + b.Property("Played") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("REAL"); + + b.Property("SubtitleStreamIndex") + .HasColumnType("INTEGER"); + + b.HasKey("ItemId", "UserId", "CustomDataKey"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + + b.HasAnnotation("Sqlite:UseSqlReturningClause", false); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Children") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "ParentItem") + .WithMany("ParentAncestors") + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Database.Implementations.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Permission", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Preference", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.UserData", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => + { + b.Navigation("Chapters"); + + b.Navigation("Children"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("ParentAncestors"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.cs new file mode 100644 index 000000000..f921856a2 --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/20250331182844_FixAttachmentMigration.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// + public partial class FixAttachmentMigration : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Codec", + table: "AttachmentStreamInfos", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Codec", + table: "AttachmentStreamInfos", + type: "TEXT", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + } + } +} diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs index 0bb4b31b0..08c73217f 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs @@ -120,7 +120,6 @@ namespace Jellyfin.Server.Implementations.Migrations .HasColumnType("INTEGER"); b.Property("Codec") - .IsRequired() .HasColumnType("TEXT"); b.Property("CodecTag") -- cgit v1.2.3 From 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 ac004b413..83a6df964 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 afe5b14e9..c6cfd5391 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 63c9c173b..454d3f08e 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 806900e9a..61e04a813 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 66de18cfe..75ccdcf27 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 000000000..810087b92 --- /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 e59c62e23..d71e91174 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 75334f427..a569aa09f 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 9a83dba45..d50f3d075 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 d71e91174..364770fcd 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 d48426672..d1a6b3584 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 5bb75e2b9..7b07243da 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 000000000..b4daa2a14 --- /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 5b0fc9ef3..9e0a6080d 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 83a6df964..dbd2333ff 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 ea7896861..000000000 --- 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 563e90fbe..b76fdeeb0 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 93e15735c..9f2d47346 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 000000000..7532e56c6 --- /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 e22cb0f58..000000000 --- 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 d1a6b3584..a7ff75bb1 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 7c20164a6..4e4eb514e 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 8ce40a58d..000000000 --- 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 000000000..0844ddb36 --- /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 0bb21b287..286ba0de0 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 266e1861f..7947ba921 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 1c2f8b913..ba6034ec1 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 f0cca9efd..d1376f18a 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 9bc3a0204..81ef0e5f9 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 40045782b..a6eddbbc3 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 725df98da..f049e6647 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 8d0bf73f6..511306755 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 70a4fe409..78e96ab47 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 7a8ab3236..fa0d8247b 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 608286cd8..a6e83a02c 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 cdce608d9..a24b081dd 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 d99923b4f..15843730e 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 b01fd93a7..f29a0b3ad 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 000000000..2c186c917 --- /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 bb45dd87e..25ddade82 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 a6eddbbc3..21c953fb2 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 000000000..d677c9f09 --- /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 7378cf885..f63408403 100644 --- a/Emby.Server.Implementations/IO/FileRefresher.cs +++ b/Emby.Server.Implementations/IO/FileRefresher.cs @@ -130,7 +130,7 @@ namespace Emby.Server.Implementations.IO private void ProcessPathChanges(List paths) { IEnumerable itemsToRefresh = paths - .Distinct(StringComparer.OrdinalIgnoreCase) + .Distinct() .Select(GetAffectedBaseItem) .Where(item => item is not null) .DistinctBy(x => x!.Id)!; // Removed null values in the previous .Where() diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs index 6af2a553d..d87ad729e 100644 --- a/Emby.Server.Implementations/IO/LibraryMonitor.cs +++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs @@ -121,7 +121,7 @@ namespace Emby.Server.Implementations.IO .Where(IsLibraryMonitorEnabled) .OfType() .SelectMany(f => f.PhysicalLocations) - .Distinct(StringComparer.OrdinalIgnoreCase) + .Distinct() .Order(); foreach (var path in paths) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 21c953fb2..64a96c4e5 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -668,10 +668,10 @@ namespace Emby.Server.Implementations.Library var list = originalList.Where(i => i.IsDirectory) .Select(i => Path.TrimEndingDirectorySeparator(i.FullName)) - .Distinct(StringComparer.OrdinalIgnoreCase) + .Distinct() .ToList(); - var dupes = list.Where(subPath => !subPath.EndsWith(":\\", StringComparison.OrdinalIgnoreCase) && list.Any(i => _fileSystem.ContainsSubPath(i, subPath))) + var dupes = list.Where(subPath => !subPath.EndsWith(":\\", StringComparison.Ordinal) && list.Any(i => _fileSystem.ContainsSubPath(i, subPath))) .ToList(); foreach (var dupe in dupes) @@ -679,7 +679,7 @@ namespace Emby.Server.Implementations.Library _logger.LogInformation("Found duplicate path: {0}", dupe); } - var newList = list.Except(dupes, StringComparer.OrdinalIgnoreCase).Select(_fileSystem.GetDirectoryInfo).ToList(); + var newList = list.Except(dupes, StringComparer.Ordinal).Select(_fileSystem.GetDirectoryInfo).ToList(); newList.AddRange(originalList.Where(i => !i.IsDirectory)); return newList; } diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index d49e0753e..50eeaeac6 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -299,7 +299,7 @@ public class ItemUpdateController : BaseJellyfinApiController if (!season.LockedFields.Contains(MetadataField.Tags)) { - season.Tags = season.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + season.Tags = season.Tags.Concat(addedTags).Except(removedTags).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } season.OnMetadataChanged(); @@ -316,7 +316,7 @@ public class ItemUpdateController : BaseJellyfinApiController if (!ep.LockedFields.Contains(MetadataField.Tags)) { - ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } ep.OnMetadataChanged(); @@ -337,7 +337,7 @@ public class ItemUpdateController : BaseJellyfinApiController if (!ep.LockedFields.Contains(MetadataField.Tags)) { - ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } ep.OnMetadataChanged(); @@ -357,7 +357,7 @@ public class ItemUpdateController : BaseJellyfinApiController if (!track.LockedFields.Contains(MetadataField.Tags)) { - track.Tags = track.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + track.Tags = track.Tags.Concat(addedTags).Except(removedTags).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } track.OnMetadataChanged(); diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index ebf98da45..b60258586 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -223,6 +223,6 @@ public class YearsController : BaseJellyfinApiController .Select(i => i.ProductionYear ?? 0) .Where(i => i > 0) .Distinct() - .Select(year => _libraryManager.GetYear(year)); + .Select(_libraryManager.GetYear); } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index a7ff75bb1..b90ec8222 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1804,7 +1804,7 @@ namespace MediaBrowser.Controller.Entities public void SetStudios(IEnumerable names) { - Studios = names.Trimmed().Distinct().ToArray(); + Studios = names.Trimmed().Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } /// diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index d656fccb4..dd5852823 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -197,7 +197,7 @@ namespace MediaBrowser.Controller.Entities.Movies var expandedFolders = new List(); return FlattenItems(this, expandedFolders) - .SelectMany(i => LibraryManager.GetCollectionFolders(i)) + .SelectMany(LibraryManager.GetCollectionFolders) .Select(i => i.Id) .Distinct() .ToArray(); diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index d28cd70ef..5683de169 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -14,8 +14,8 @@ namespace MediaBrowser.MediaEncoding.Encoder { public partial class EncoderValidator { - private static readonly string[] _requiredDecoders = new[] - { + private static readonly string[] _requiredDecoders = + [ "h264", "hevc", "vp8", @@ -57,10 +57,10 @@ namespace MediaBrowser.MediaEncoding.Encoder "vp8_rkmpp", "vp9_rkmpp", "av1_rkmpp" - }; + ]; - private static readonly string[] _requiredEncoders = new[] - { + private static readonly string[] _requiredEncoders = + [ "libx264", "libx265", "libsvtav1", @@ -97,10 +97,10 @@ namespace MediaBrowser.MediaEncoding.Encoder "h264_rkmpp", "hevc_rkmpp", "mjpeg_rkmpp" - }; + ]; - private static readonly string[] _requiredFilters = new[] - { + private static readonly string[] _requiredFilters = + [ // sw "alphasrc", "zscale", @@ -148,7 +148,7 @@ namespace MediaBrowser.MediaEncoding.Encoder "scale_rkrga", "vpp_rkrga", "overlay_rkrga" - }; + ]; private static readonly Dictionary _filterOptionsDict = new Dictionary { @@ -471,10 +471,10 @@ namespace MediaBrowser.MediaEncoding.Encoder if (string.IsNullOrWhiteSpace(output)) { - return Enumerable.Empty(); + return []; } - var found = output.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Skip(1).Distinct().ToList(); + var found = output.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries).Skip(1).Distinct().ToList(); _logger.LogInformation("Available hwaccel types: {Types}", found); return found; @@ -580,12 +580,12 @@ namespace MediaBrowser.MediaEncoding.Encoder catch (Exception ex) { _logger.LogError(ex, "Error detecting available {Codec}", codecstr); - return Enumerable.Empty(); + return []; } if (string.IsNullOrWhiteSpace(output)) { - return Enumerable.Empty(); + return []; } var required = codec == Codec.Encoder ? _requiredEncoders : _requiredDecoders; @@ -610,12 +610,12 @@ namespace MediaBrowser.MediaEncoding.Encoder catch (Exception ex) { _logger.LogError(ex, "Error detecting available filters"); - return Enumerable.Empty(); + return []; } if (string.IsNullOrWhiteSpace(output)) { - return Enumerable.Empty(); + return []; } var found = FilterRegex() diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 413bf2d30..50bbf0974 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -1041,7 +1041,7 @@ namespace MediaBrowser.Providers.Manager } else { - target.Studios = target.Studios.Concat(source.Studios).Distinct().ToArray(); + target.Studios = target.Studios.Concat(source.Studios).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } } @@ -1053,7 +1053,7 @@ namespace MediaBrowser.Providers.Manager } else { - target.Tags = target.Tags.Concat(source.Tags).Distinct().ToArray(); + target.Tags = target.Tags.Concat(source.Tags).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } } @@ -1065,7 +1065,7 @@ namespace MediaBrowser.Providers.Manager } else { - target.ProductionLocations = target.ProductionLocations.Concat(source.ProductionLocations).Distinct().ToArray(); + target.ProductionLocations = target.ProductionLocations.Concat(source.ProductionLocations).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } } @@ -1214,7 +1214,7 @@ namespace MediaBrowser.Providers.Manager } else if (sourceHasAlbumArtist.AlbumArtists.Count > 0) { - targetHasAlbumArtist.AlbumArtists = targetHasAlbumArtist.AlbumArtists.Concat(sourceHasAlbumArtist.AlbumArtists).Distinct().ToArray(); + targetHasAlbumArtist.AlbumArtists = targetHasAlbumArtist.AlbumArtists.Concat(sourceHasAlbumArtist.AlbumArtists).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } } } diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs index 0bcc301cb..64b627367 100644 --- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs +++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs @@ -227,7 +227,7 @@ namespace MediaBrowser.Providers.Music } else { - targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct().ToArray(); + targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } if (replaceData || string.IsNullOrEmpty(targetItem.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist))) diff --git a/MediaBrowser.Providers/Music/AudioMetadataService.cs b/MediaBrowser.Providers/Music/AudioMetadataService.cs index 7b25bc0e4..71962d952 100644 --- a/MediaBrowser.Providers/Music/AudioMetadataService.cs +++ b/MediaBrowser.Providers/Music/AudioMetadataService.cs @@ -63,7 +63,7 @@ namespace MediaBrowser.Providers.Music } else { - targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct().ToArray(); + targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } if (replaceData || string.IsNullOrEmpty(targetItem.Album)) diff --git a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs index 24c4b5501..4022bedc1 100644 --- a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs +++ b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System; using System.Linq; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -48,7 +49,7 @@ namespace MediaBrowser.Providers.Music } else { - targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct().ToArray(); + targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); } } } diff --git a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs index 51a3ba0c7..a986b0b69 100644 --- a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs +++ b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs @@ -99,7 +99,7 @@ public class PlaylistItemsProvider : ILocalMetadataProvider, .OfType() .Where(f => f.CollectionType.HasValue && !_ignoredCollections.Contains(f.CollectionType.Value)) .SelectMany(f => f.PhysicalLocations) - .Distinct(StringComparer.OrdinalIgnoreCase) + .Distinct() .ToList(); using (var stream = File.OpenRead(path)) diff --git a/src/Jellyfin.LiveTv/LiveTvManager.cs b/src/Jellyfin.LiveTv/LiveTvManager.cs index 40adb51a5..53bc6751f 100644 --- a/src/Jellyfin.LiveTv/LiveTvManager.cs +++ b/src/Jellyfin.LiveTv/LiveTvManager.cs @@ -125,8 +125,8 @@ namespace Jellyfin.LiveTv IsKids = query.IsKids, IsSports = query.IsSports, IsSeries = query.IsSeries, - IncludeItemTypes = new[] { BaseItemKind.LiveTvChannel }, - TopParentIds = new[] { topFolder.Id }, + IncludeItemTypes = [BaseItemKind.LiveTvChannel], + TopParentIds = [topFolder.Id], IsFavorite = query.IsFavorite, IsLiked = query.IsLiked, StartIndex = query.StartIndex, @@ -199,17 +199,17 @@ namespace Jellyfin.LiveTv if (query.OrderBy.Count == 0) { // Unless something else was specified, order by start date to take advantage of a specialized index - query.OrderBy = new[] - { + query.OrderBy = + [ (ItemSortBy.StartDate, SortOrder.Ascending) - }; + ]; } RemoveFields(options); var internalQuery = new InternalItemsQuery(user) { - IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram }, + IncludeItemTypes = [BaseItemKind.LiveTvProgram], MinEndDate = query.MinEndDate, MinStartDate = query.MinStartDate, MaxEndDate = query.MaxEndDate, @@ -226,7 +226,7 @@ namespace Jellyfin.LiveTv Limit = query.Limit, OrderBy = query.OrderBy, EnableTotalRecordCount = query.EnableTotalRecordCount, - TopParentIds = new[] { topFolder.Id }, + TopParentIds = [topFolder.Id], Name = query.Name, DtoOptions = options, HasAired = query.HasAired, @@ -272,7 +272,7 @@ namespace Jellyfin.LiveTv var internalQuery = new InternalItemsQuery(user) { - IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram }, + IncludeItemTypes = [BaseItemKind.LiveTvProgram], IsAiring = query.IsAiring, HasAired = query.HasAired, IsNews = query.IsNews, @@ -281,8 +281,8 @@ namespace Jellyfin.LiveTv IsSports = query.IsSports, IsKids = query.IsKids, EnableTotalRecordCount = query.EnableTotalRecordCount, - OrderBy = new[] { (ItemSortBy.StartDate, SortOrder.Ascending) }, - TopParentIds = new[] { topFolder.Id }, + OrderBy = [(ItemSortBy.StartDate, SortOrder.Ascending)], + TopParentIds = [topFolder.Id], DtoOptions = options, GenreIds = query.GenreIds }; @@ -497,19 +497,19 @@ namespace Jellyfin.LiveTv // TotalRecordCount = items.Length // }; - dtoOptions.Fields = dtoOptions.Fields.Concat(new[] { ItemFields.Tags }).Distinct().ToArray(); + dtoOptions.Fields = dtoOptions.Fields.Concat([ItemFields.Tags]).Distinct().ToArray(); } var result = _libraryManager.GetItemsResult(new InternalItemsQuery(user) { - MediaTypes = new[] { MediaType.Video }, + MediaTypes = [MediaType.Video], Recursive = true, AncestorIds = folderIds, IsFolder = false, IsVirtualItem = false, Limit = limit, StartIndex = query.StartIndex, - OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending) }, + OrderBy = [(ItemSortBy.DateCreated, SortOrder.Descending)], EnableTotalRecordCount = query.EnableTotalRecordCount, IncludeItemTypes = includeItemTypes.ToArray(), ExcludeItemTypes = excludeItemTypes.ToArray(), @@ -959,13 +959,13 @@ namespace Jellyfin.LiveTv var programs = options.AddCurrentProgram ? _libraryManager.GetItemList(new InternalItemsQuery(user) { - IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram }, + IncludeItemTypes = [BaseItemKind.LiveTvProgram], ChannelIds = channelIds, MaxStartDate = now, MinEndDate = now, Limit = channelIds.Length, - OrderBy = new[] { (ItemSortBy.StartDate, SortOrder.Ascending) }, - TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Id }, + OrderBy = [(ItemSortBy.StartDate, SortOrder.Ascending)], + TopParentIds = [GetInternalLiveTvFolder(CancellationToken.None).Id], DtoOptions = options }) : new List(); @@ -1269,7 +1269,7 @@ namespace Jellyfin.LiveTv { var folders = _recordingsManager.GetRecordingFolders() .SelectMany(i => i.Locations) - .Distinct(StringComparer.OrdinalIgnoreCase) + .Distinct() .Select(i => _libraryManager.FindByPath(i, true)) .Where(i => i is not null && i.IsVisibleStandalone(user)) .SelectMany(i => _libraryManager.GetCollectionFolders(i)) diff --git a/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs b/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs index 9ca5d7420..846f9baf7 100644 --- a/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs +++ b/src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs @@ -230,7 +230,7 @@ public sealed class RecordingsManager : IRecordingsManager, IDisposable if (pathsAdded.Count > 0 || pathsToRemove.Count > 0) { pathsAdded.InsertRange(0, config.MediaLocationsCreated); - config.MediaLocationsCreated = pathsAdded.Except(pathsToRemove).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); + config.MediaLocationsCreated = pathsAdded.Except(pathsToRemove).Distinct().ToArray(); _config.SaveConfiguration("livetv", config); } -- cgit v1.2.3 From 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 d51f9aaa7..a31d5ecca 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 7591e8391..7cc851b73 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 337b1afdd..38631e0de 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 d21d2887b..5097e0073 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 364770fcd..fbfc9f7d5 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 be119866b..76658a81b 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 1ecf4c87c..6203bce2b 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 725b8f76c..b7fd24fa5 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 c682b156b..67c56c104 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 26bc49c1f..5b87e4d9d 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 985f0a8f8..24f554981 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 a5e4104ff..4ec2c9c78 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 8d1d509ff..ef005bfaa 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 b76fdeeb0..f81309560 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