Пример #1
0
        public Task <object> GetImage(ImageRequest request, User user, bool isHeadRequest)
        {
            var imageInfo = GetImageInfo(request, user);

            TimeSpan?cacheDuration = null;

            if (!string.IsNullOrEmpty(request.Tag))
            {
                cacheDuration = TimeSpan.FromDays(365);
            }

            var responseHeaders = new Dictionary <string, string>
            {
                { "transferMode.dlna.org", "Interactive" },
                { "realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*" }
            };

            var outputFormats = GetOutputFormats(request);

            return(GetImageResult(user.Id,
                                  request,
                                  imageInfo,
                                  outputFormats,
                                  cacheDuration,
                                  responseHeaders,
                                  isHeadRequest));
        }
 /// <summary>
 /// Count media items and call <see cref="SyncMovies"/> and <see cref="SyncShows"/>
 /// </summary>
 /// <returns></returns>
 private async Task SyncUserLibrary(
     Jellyfin.Data.Entities.User user,
     TraktUser traktUser,
     ISplittableProgress <double> progress,
     CancellationToken cancellationToken)
 {
     await SyncMovies(user, traktUser, progress.Split(2), cancellationToken).ConfigureAwait(false);
     await SyncShows(user, traktUser, progress.Split(2), cancellationToken).ConfigureAwait(false);
 }
        /// <summary> Gets report result. </summary>
        /// <param name="request"> The request. </param>
        /// <returns> The report result. </returns>
        private ReportResult GetReportResult(GetItemReport request, User user)
        {
            ReportBuilder          reportBuilder = new ReportBuilder(_libraryManager);
            QueryResult <BaseItem> queryResult   = GetQueryResult(request, user);
            ReportResult           reportResult  = reportBuilder.GetResult(queryResult.Items, request);

            reportResult.TotalRecordCount = queryResult.TotalRecordCount;

            return(reportResult);
        }
Пример #4
0
        private async Task PostImage(User user, Stream inputStream, string mimeType)
        {
            var memoryStream = await GetMemoryStream(inputStream);

            // Handle image/png; charset=utf-8
            mimeType = mimeType.Split(';').FirstOrDefault();
            var userDataPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username);

            user.ProfileImage = new Jellyfin.Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType)));

            await _providerManager
            .SaveImage(user, memoryStream, mimeType, user.ProfileImage.Path)
            .ConfigureAwait(false);

            await _userManager.UpdateUserAsync(user);
        }
Пример #5
0
        private static ItemImageInfo GetImageInfo(ImageRequest request, User user)
        {
            var info = new ItemImageInfo
            {
                Path         = user.ProfileImage.Path,
                Type         = ImageType.Primary,
                DateModified = user.ProfileImage.LastModified,
            };

            if (request.Width.HasValue)
            {
                info.Width = request.Width.Value;
            }

            if (request.Height.HasValue)
            {
                info.Height = request.Height.Value;
            }

            return(info);
        }
Пример #6
0
        private long?GetMaxBitrate(long?clientMaxBitrate, Jellyfin.Data.Entities.User user)
        {
            var maxBitrate             = clientMaxBitrate;
            var remoteClientMaxBitrate = user?.RemoteClientBitrateLimit ?? 0;

            if (remoteClientMaxBitrate <= 0)
            {
                remoteClientMaxBitrate = ServerConfigurationManager.Configuration.RemoteClientBitrateLimit;
            }

            if (remoteClientMaxBitrate > 0)
            {
                var isInLocalNetwork = _networkManager.IsInLocalNetwork(Request.RemoteIp);

                Logger.LogInformation("RemoteClientBitrateLimit: {0}, RemoteIp: {1}, IsInLocalNetwork: {2}", remoteClientMaxBitrate, Request.RemoteIp, isInLocalNetwork);
                if (!isInLocalNetwork)
                {
                    maxBitrate = Math.Min(maxBitrate ?? remoteClientMaxBitrate, remoteClientMaxBitrate);
                }
            }

            return(maxBitrate);
        }
        /// <summary>
        /// Sync watched and collected status of <see cref="Movie"/>s with trakt.
        /// </summary>
        private async Task SyncShows(
            Jellyfin.Data.Entities.User user,
            TraktUser traktUser,
            ISplittableProgress <double> progress,
            CancellationToken cancellationToken)
        {
            var traktWatchedShows = await _traktApi.SendGetWatchedShowsRequest(traktUser).ConfigureAwait(false);

            var traktCollectedShows = await _traktApi.SendGetCollectedShowsRequest(traktUser).ConfigureAwait(false);

            var episodeItems =
                _libraryManager.GetItemList(
                    new InternalItemsQuery(user)
            {
                IncludeItemTypes = new[] { typeof(Episode).Name },
                IsVirtualItem    = false,
                OrderBy          = new[]
                {
                    new ValueTuple <string, SortOrder>(ItemSortBy.SeriesSortName, SortOrder.Ascending)
                }
            })
                .Where(x => _traktApi.CanSync(x, traktUser))
                .ToList();

            var collectedEpisodes = new List <Episode>();
            var playedEpisodes    = new List <Episode>();
            var unplayedEpisodes  = new List <Episode>();

            var decisionProgress = progress.Split(4).Split(episodeItems.Count);

            foreach (var child in episodeItems)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var episode          = child as Episode;
                var userData         = _userDataManager.GetUserData(user.Id, episode);
                var isPlayedTraktTv  = false;
                var traktWatchedShow = SyncFromTraktTask.FindMatch(episode.Series, traktWatchedShows);

                if (traktWatchedShow?.seasons != null && traktWatchedShow.seasons.Count > 0)
                {
                    isPlayedTraktTv =
                        traktWatchedShow.seasons.Any(
                            season =>
                            season.number == episode.GetSeasonNumber() && season.episodes != null &&
                            season.episodes.Any(te => te.number == episode.IndexNumber && te.plays > 0));
                }

                // if the show has been played locally and is unplayed on trakt.tv then add it to the list
                if (userData != null && userData.Played && !isPlayedTraktTv)
                {
                    if (traktUser.PostWatchedHistory)
                    {
                        playedEpisodes.Add(episode);
                    }
                    else if (!traktUser.SkipUnwatchedImportFromTrakt)
                    {
                        if (userData.Played)
                        {
                            userData.Played = false;

                            _userDataManager.SaveUserData(
                                user.Id,
                                episode,
                                userData,
                                UserDataSaveReason.Import,
                                cancellationToken);
                        }
                    }
                }
                else if (userData != null && !userData.Played && isPlayedTraktTv && traktUser.PostUnwatchedHistory)
                {
                    // If the show has not been played locally but is played on trakt.tv then add it to the unplayed list
                    unplayedEpisodes.Add(episode);
                }

                if (traktUser.SynchronizeCollections)
                {
                    var traktCollectedShow = SyncFromTraktTask.FindMatch(episode.Series, traktCollectedShows);
                    if (traktCollectedShow?.seasons == null ||
                        traktCollectedShow.seasons.All(x => x.number != episode.ParentIndexNumber) ||
                        traktCollectedShow.seasons.First(x => x.number == episode.ParentIndexNumber)
                        .episodes.All(e => e.number != episode.IndexNumber))
                    {
                        collectedEpisodes.Add(episode);
                    }
                }

                decisionProgress.Report(100);
            }

            if (traktUser.SynchronizeCollections)
            {
                await SendEpisodeCollectionUpdates(true, traktUser, collectedEpisodes, progress.Split(4), cancellationToken).ConfigureAwait(false);
            }

            await SendEpisodePlaystateUpdates(true, traktUser, playedEpisodes, progress.Split(4), cancellationToken).ConfigureAwait(false);

            await SendEpisodePlaystateUpdates(false, traktUser, unplayedEpisodes, progress.Split(4), cancellationToken).ConfigureAwait(false);
        }
        /// <summary>
        /// Sync watched and collected status of <see cref="Movie"/>s with trakt.
        /// </summary>
        private async Task SyncMovies(
            Jellyfin.Data.Entities.User user,
            TraktUser traktUser,
            ISplittableProgress <double> progress,
            CancellationToken cancellationToken)
        {
            /*
             * In order to sync watched status to trakt.tv we need to know what's been watched on Trakt already. This
             * will stop us from endlessly incrementing the watched values on the site.
             */
            var traktWatchedMovies = await _traktApi.SendGetAllWatchedMoviesRequest(traktUser).ConfigureAwait(false);

            var traktCollectedMovies = await _traktApi.SendGetAllCollectedMoviesRequest(traktUser).ConfigureAwait(false);

            var libraryMovies =
                _libraryManager.GetItemList(
                    new InternalItemsQuery(user)
            {
                IncludeItemTypes = new[] { typeof(Movie).Name },
                IsVirtualItem    = false,
                OrderBy          = new []
                {
                    new ValueTuple <string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending)
                }
            })
                .Where(x => _traktApi.CanSync(x, traktUser))
                .ToList();
            var collectedMovies = new List <Movie>();
            var playedMovies    = new List <Movie>();
            var unplayedMovies  = new List <Movie>();

            var decisionProgress = progress.Split(4).Split(libraryMovies.Count);

            foreach (var child in libraryMovies)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var libraryMovie = child as Movie;
                var userData     = _userDataManager.GetUserData(user.Id, child);

                if (traktUser.SynchronizeCollections)
                {
                    // if movie is not collected, or (export media info setting is enabled and every collected matching movie has different metadata), collect it
                    var collectedMathingMovies = SyncFromTraktTask.FindMatches(libraryMovie, traktCollectedMovies).ToList();
                    if (!collectedMathingMovies.Any() ||
                        (traktUser.ExportMediaInfo &&
                         collectedMathingMovies.All(
                             collectedMovie => collectedMovie.MetadataIsDifferent(libraryMovie))))
                    {
                        collectedMovies.Add(libraryMovie);
                    }
                }

                var movieWatched = SyncFromTraktTask.FindMatch(libraryMovie, traktWatchedMovies);

                // if the movie has been played locally and is unplayed on trakt.tv then add it to the list
                if (userData.Played)
                {
                    if (movieWatched == null)
                    {
                        if (traktUser.PostWatchedHistory)
                        {
                            playedMovies.Add(libraryMovie);
                        }
                        else if (!traktUser.SkipUnwatchedImportFromTrakt)
                        {
                            if (userData.Played)
                            {
                                userData.Played = false;

                                _userDataManager.SaveUserData(
                                    user.Id,
                                    libraryMovie,
                                    userData,
                                    UserDataSaveReason.Import,
                                    cancellationToken);
                            }
                        }
                    }
                }
                else
                {
                    // If the show has not been played locally but is played on trakt.tv then add it to the unplayed list
                    if (movieWatched != null && traktUser.PostUnwatchedHistory)
                    {
                        unplayedMovies.Add(libraryMovie);
                    }
                }

                decisionProgress.Report(100);
            }

            // send movies to mark collected
            if (traktUser.SynchronizeCollections)
            {
                await SendMovieCollectionUpdates(true, traktUser, collectedMovies, progress.Split(4), cancellationToken).ConfigureAwait(false);
            }

            // send movies to mark watched
            await SendMoviePlaystateUpdates(true, traktUser, playedMovies, progress.Split(4), cancellationToken).ConfigureAwait(false);

            // send movies to mark unwatched
            await SendMoviePlaystateUpdates(false, traktUser, unplayedMovies, progress.Split(4), cancellationToken).ConfigureAwait(false);
        }
Пример #9
0
        private async Task SyncTraktDataForUser(Jellyfin.Data.Entities.User user, double currentProgress, CancellationToken cancellationToken, IProgress <double> progress, double percentPerUser)
        {
            var traktUser = UserHelper.GetTraktUser(user);

            List <TraktMovieWatched> traktWatchedMovies;
            List <TraktShowWatched>  traktWatchedShows;

            try
            {
                /*
                 * In order to be as accurate as possible. We need to download the users show collection & the users watched shows.
                 * It's unfortunate that trakt.tv doesn't explicitly supply a bulk method to determine shows that have not been watched
                 * like they do for movies.
                 */
                traktWatchedMovies = await _traktApi.SendGetAllWatchedMoviesRequest(traktUser).ConfigureAwait(false);

                traktWatchedShows = await _traktApi.SendGetWatchedShowsRequest(traktUser).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception handled");
                throw;
            }

            _logger.LogInformation("Trakt.tv watched Movies count = " + traktWatchedMovies.Count);
            _logger.LogInformation("Trakt.tv watched Shows count = " + traktWatchedShows.Count);

            var mediaItems =
                _libraryManager.GetItemList(
                    new InternalItemsQuery(user)
            {
                IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Episode).Name },
                IsVirtualItem    = false,
                OrderBy          = new[]
                {
                    new ValueTuple <string, SortOrder>(ItemSortBy.SeriesSortName, SortOrder.Ascending),
                    new ValueTuple <string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending)
                }
            })
                .Where(i => _traktApi.CanSync(i, traktUser)).ToList();

            // purely for progress reporting
            var percentPerItem = percentPerUser / mediaItems.Count;

            foreach (var movie in mediaItems.OfType <Movie>())
            {
                cancellationToken.ThrowIfCancellationRequested();
                var matchedMovie = FindMatch(movie, traktWatchedMovies);

                if (matchedMovie != null)
                {
                    _logger.LogDebug("Movie is in Watched list " + movie.Name);

                    var  userData = _userDataManager.GetUserData(user.Id, movie);
                    bool changed  = false;

                    DateTime?tLastPlayed = null;
                    if (DateTime.TryParse(matchedMovie.last_watched_at, out var value))
                    {
                        tLastPlayed = value;
                    }

                    // set movie as watched
                    if (!userData.Played)
                    {
                        userData.Played         = true;
                        userData.LastPlayedDate = tLastPlayed ?? DateTime.Now;
                        changed = true;
                    }

                    // keep the highest play count
                    if (userData.PlayCount < matchedMovie.plays)
                    {
                        userData.PlayCount = matchedMovie.plays;
                        changed            = true;
                    }

                    // Update last played if remote time is more recent
                    if (tLastPlayed != null && userData.LastPlayedDate < tLastPlayed)
                    {
                        userData.LastPlayedDate = tLastPlayed;
                        changed = true;
                    }

                    // Only process if there's a change
                    if (changed)
                    {
                        _userDataManager.SaveUserData(
                            user.Id,
                            movie,
                            userData,
                            UserDataSaveReason.Import,
                            cancellationToken);
                    }
                }
                else
                {
                    //_logger.LogInformation("Failed to match " + movie.Name);
                }

                // purely for progress reporting
                currentProgress += percentPerItem;
                progress.Report(currentProgress);
            }

            foreach (var episode in mediaItems.OfType <Episode>())
            {
                cancellationToken.ThrowIfCancellationRequested();
                var matchedShow = FindMatch(episode.Series, traktWatchedShows);

                if (matchedShow != null)
                {
                    var matchedSeason =
                        matchedShow.seasons.FirstOrDefault(
                            tSeason =>
                            tSeason.number
                            == (episode.ParentIndexNumber == 0
                                        ? 0
                                        : (episode.ParentIndexNumber ?? 1)));

                    // if it's not a match then it means trakt doesn't know about the season, leave the watched state alone and move on
                    if (matchedSeason != null)
                    {
                        // episode is in users libary. Now we need to determine if it's watched
                        var  userData = _userDataManager.GetUserData(user.Id, episode);
                        bool changed  = false;

                        var matchedEpisode =
                            matchedSeason.episodes.FirstOrDefault(x => x.number == (episode.IndexNumber ?? -1));

                        if (matchedEpisode != null)
                        {
                            _logger.LogDebug("Episode is in Watched list " + GetVerboseEpisodeData(episode));

                            if (!traktUser.SkipWatchedImportFromTrakt)
                            {
                                DateTime?tLastPlayed = null;
                                if (DateTime.TryParse(matchedEpisode.last_watched_at, out var value))
                                {
                                    tLastPlayed = value;
                                }

                                // Set episode as watched
                                if (!userData.Played)
                                {
                                    userData.Played         = true;
                                    userData.LastPlayedDate = tLastPlayed ?? DateTime.Now;
                                    changed = true;
                                }

                                // keep the highest play count
                                if (userData.PlayCount < matchedEpisode.plays)
                                {
                                    userData.PlayCount = matchedEpisode.plays;
                                    changed            = true;
                                }

                                // Update last played if remote time is more recent
                                if (tLastPlayed != null && userData.LastPlayedDate < tLastPlayed)
                                {
                                    userData.LastPlayedDate = tLastPlayed;
                                    changed = true;
                                }
                            }
                        }
                        else if (!traktUser.SkipUnwatchedImportFromTrakt)
                        {
                            userData.Played         = false;
                            userData.PlayCount      = 0;
                            userData.LastPlayedDate = null;
                            changed = true;
                        }

                        // only process if changed
                        if (changed)
                        {
                            _userDataManager.SaveUserData(
                                user.Id,
                                episode,
                                userData,
                                UserDataSaveReason.Import,
                                cancellationToken);
                        }
                    }
                    else
                    {
                        _logger.LogDebug("No Season match in Watched shows list " + GetVerboseEpisodeData(episode));
                    }
                }
                else
                {
                    _logger.LogDebug("No Show match in Watched shows list " + GetVerboseEpisodeData(episode));
                }

                // purely for progress reporting
                currentProgress += percentPerItem;
                progress.Report(currentProgress);
            }

            // _logger.LogInformation(syncItemFailures + " items not parsed");
        }
        private QueryResult <BaseItem> GetQueryResult(BaseReportRequest request, User user)
        {
            // all report queries currently need this because it's not being specified
            request.Recursive = true;

            BaseItem item = null;

            if (!string.IsNullOrEmpty(request.ParentId))
            {
                item = _libraryManager.GetItemById(request.ParentId);
            }

            if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase))
            {
                //item = user == null ? _libraryManager.RootFolder : user.RootFolder;
            }
            else if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase))
            {
                item = _libraryManager.GetUserRootFolder();
            }

            // Default list type = children

            Folder folder = item as Folder;

            if (folder is null)
            {
                folder = _libraryManager.GetUserRootFolder();
            }

            if (!string.IsNullOrEmpty(request.Ids))
            {
                request.Recursive = true;
                var query  = GetItemsQuery(request, user);
                var result = folder.GetItems(query);

                if (string.IsNullOrWhiteSpace(request.SortBy))
                {
                    var ids = query.ItemIds.ToList();

                    // Try to preserve order
                    result.Items = result.Items.OrderBy(i => ids.IndexOf(i.Id)).ToArray();
                }

                return(result);
            }

            if (request.Recursive)
            {
                return(folder.GetItems(GetItemsQuery(request, user)));
            }

            if (user == null)
            {
                return(folder.GetItems(GetItemsQuery(request, null)));
            }

            var userRoot = item as UserRootFolder;

            if (userRoot == null)
            {
                return(folder.GetItems(GetItemsQuery(request, user)));
            }

            IEnumerable <BaseItem> items = folder.GetChildren(user, true);

            var itemsArray = items.ToArray();

            return(new QueryResult <BaseItem>
            {
                Items = itemsArray,
                TotalRecordCount = itemsArray.Length
            });
        }
        private InternalItemsQuery GetItemsQuery(BaseReportRequest request, User user)
        {
            var query = new InternalItemsQuery(user)
            {
                IsPlayed                = request.IsPlayed,
                MediaTypes              = request.GetMediaTypes(),
                IncludeItemTypes        = request.GetIncludeItemTypes(),
                ExcludeItemTypes        = request.GetExcludeItemTypes(),
                Recursive               = request.Recursive,
                OrderBy                 = request.GetOrderBy(),
                IsFavorite              = request.IsFavorite,
                StartIndex              = request.StartIndex,
                IsMissing               = request.IsMissing,
                IsUnaired               = request.IsUnaired,
                CollapseBoxSetItems     = request.CollapseBoxSetItems,
                NameLessThan            = request.NameLessThan,
                NameStartsWith          = request.NameStartsWith,
                NameStartsWithOrGreater = request.NameStartsWithOrGreater,
                HasImdbId               = request.HasImdbId,
                IsPlaceHolder           = request.IsPlaceHolder,
                IsLocked                = request.IsLocked,
                IsHD                   = request.IsHD,
                Is3D                   = request.Is3D,
                HasTvdbId              = request.HasTvdbId,
                HasTmdbId              = request.HasTmdbId,
                HasOverview            = request.HasOverview,
                HasOfficialRating      = request.HasOfficialRating,
                HasParentalRating      = request.HasParentalRating,
                HasSpecialFeature      = request.HasSpecialFeature,
                HasSubtitles           = request.HasSubtitles,
                HasThemeSong           = request.HasThemeSong,
                HasThemeVideo          = request.HasThemeVideo,
                HasTrailer             = request.HasTrailer,
                Tags                   = request.GetTags(),
                OfficialRatings        = request.GetOfficialRatings(),
                Genres                 = request.GetGenres(),
                GenreIds               = request.GetGenreIds(),
                StudioIds              = request.GetStudioIds(),
                Person                 = request.Person,
                PersonIds              = request.GetPersonIds(),
                PersonTypes            = request.GetPersonTypes(),
                Years                  = request.GetYears(),
                ImageTypes             = request.GetImageTypes().ToArray(),
                VideoTypes             = request.GetVideoTypes().ToArray(),
                AdjacentTo             = request.AdjacentTo,
                ItemIds                = request.GetItemIds(),
                MinCommunityRating     = request.MinCommunityRating,
                MinCriticRating        = request.MinCriticRating,
                ParentId               = string.IsNullOrWhiteSpace(request.ParentId) ? Guid.Empty : new Guid(request.ParentId),
                ParentIndexNumber      = request.ParentIndexNumber,
                EnableTotalRecordCount = request.EnableTotalRecordCount
            };

            if (request.Limit == -1)
            {
                query.Limit = null;
            }

            if (!string.IsNullOrWhiteSpace(request.Ids))
            {
                query.CollapseBoxSetItems = false;
            }

            query.IsFavorite = null;
            if (request.IsFavorite == true)
            {
                query.IsFavorite = true;
            }
            else if (request.IsNotFavorite == true)
            {
                query.IsFavorite = false;
            }

            foreach (var filter in request.GetFilters())
            {
                switch (filter)
                {
                case ItemFilter.Dislikes:
                    query.IsLiked = false;
                    break;

                case ItemFilter.IsFavoriteOrLikes:
                    query.IsFavoriteOrLiked = true;
                    break;

                case ItemFilter.IsFolder:
                    query.IsFolder = true;
                    break;

                case ItemFilter.IsNotFolder:
                    query.IsFolder = false;
                    break;

                case ItemFilter.IsPlayed:
                    query.IsPlayed = true;
                    break;

                case ItemFilter.IsResumable:
                    query.IsResumable = true;
                    break;

                case ItemFilter.IsUnplayed:
                    query.IsPlayed = false;
                    break;

                case ItemFilter.Likes:
                    query.IsLiked = true;
                    break;
                }
            }

            if (!string.IsNullOrEmpty(request.MinPremiereDate))
            {
                query.MinPremiereDate = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
            }

            if (!string.IsNullOrEmpty(request.MaxPremiereDate))
            {
                query.MaxPremiereDate = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
            }

            // Filter by Series Status
            if (!string.IsNullOrEmpty(request.SeriesStatus))
            {
                query.SeriesStatuses = request.SeriesStatus.Split(',').Select(d => (SeriesStatus)Enum.Parse(typeof(SeriesStatus), d, true)).ToArray();
            }

            // ExcludeLocationTypes
            if (!string.IsNullOrEmpty(request.ExcludeLocationTypes))
            {
                var excludeLocationTypes = request.ExcludeLocationTypes.Split(',').Select(d => (LocationType)Enum.Parse(typeof(LocationType), d, true)).ToArray();
                if (excludeLocationTypes.Contains(LocationType.Virtual))
                {
                    query.IsVirtualItem = false;
                }
            }

            // Min official rating
            if (!string.IsNullOrWhiteSpace(request.MinOfficialRating))
            {
                query.MinParentalRating = _localization.GetRatingLevel(request.MinOfficialRating);
            }

            // Max official rating
            if (!string.IsNullOrWhiteSpace(request.MaxOfficialRating))
            {
                query.MaxParentalRating = _localization.GetRatingLevel(request.MaxOfficialRating);
            }

            query.CollapseBoxSetItems = false;

            if (request.Limit > -1 && request.Limit < int.MaxValue)
            {
                query.Limit = request.Limit;
            }

            return(query);
        }
        /// <summary> Gets an option. </summary>
        /// <param name="header"> The header. </param>
        /// <param name="sortField"> The sort field. </param>
        /// <returns> The option. </returns>
        private ReportOptions <ActivityLogEntry> GetOption(HeaderMetadata header, string sortField = "")
        {
            HeaderMetadata internalHeader = header;

            ReportOptions <ActivityLogEntry> option = new ReportOptions <ActivityLogEntry>()
            {
                Header = new ReportHeader
                {
                    HeaderFieldType = ReportFieldType.String,
                    SortField       = sortField,
                    Type            = "",
                    ItemViewType    = ItemViewType.None
                }
            };

            switch (header)
            {
            case HeaderMetadata.Name:
                option.Column           = (i, r) => i.Name;
                option.Header.SortField = "";
                break;

            case HeaderMetadata.Overview:
                option.Column           = (i, r) => i.Overview;
                option.Header.SortField = "";
                option.Header.CanGroup  = false;
                break;

            case HeaderMetadata.ShortOverview:
                option.Column           = (i, r) => i.ShortOverview;
                option.Header.SortField = "";
                option.Header.CanGroup  = false;
                break;

            case HeaderMetadata.Type:
                option.Column           = (i, r) => i.Type;
                option.Header.SortField = "";
                break;

            case HeaderMetadata.Date:
                option.Column                 = (i, r) => i.Date;
                option.Header.SortField       = "";
                option.Header.HeaderFieldType = ReportFieldType.DateTime;
                option.Header.Type            = "";
                break;

            case HeaderMetadata.UserPrimaryImage:
                //option.Column = (i, r) => i.UserPrimaryImageTag;
                option.Header.DisplayType     = ReportDisplayType.Screen;
                option.Header.ItemViewType    = ItemViewType.UserPrimaryImage;
                option.Header.ShowHeaderLabel = false;
                internalHeader         = HeaderMetadata.User;
                option.Header.CanGroup = false;
                option.Column          = (i, r) =>
                {
                    if (i.UserId != Guid.Empty)
                    {
                        Jellyfin.Data.Entities.User user = _userManager.GetUserById(i.UserId);
                        if (user != null)
                        {
                            var dto = _userManager.GetUserDto(user);
                            return(dto.PrimaryImageTag);
                        }
                    }
                    return(string.Empty);
                };
                option.Header.SortField = "";
                break;

            case HeaderMetadata.Severity:
                option.Column           = (i, r) => i.Severity;
                option.Header.SortField = "";
                break;

            case HeaderMetadata.Item:
                option.Column           = (i, r) => i.ItemId;
                option.Header.SortField = "";
                break;

            case HeaderMetadata.User:
                option.Column = (i, r) =>
                {
                    if (i.UserId != Guid.Empty)
                    {
                        Jellyfin.Data.Entities.User user = _userManager.GetUserById(i.UserId);
                        if (user != null)
                        {
                            return(user.Username);
                        }
                    }
                    return(string.Empty);
                };
                option.Header.SortField = "";
                break;

            case HeaderMetadata.UserId:
                option.Column           = (i, r) => i.UserId;
                option.Header.SortField = "";
                break;
            }

            option.Header.Name      = GetLocalizedHeader(internalHeader);
            option.Header.FieldName = header;

            return(option);
        }