mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	Merge branch 'master' into hwaccel
This commit is contained in:
		
						commit
						dabb869a6b
					
				@ -33,6 +33,13 @@ jobs:
 | 
			
		||||
          packageType: sdk
 | 
			
		||||
          version: ${{ parameters.DotNetSdkVersion }}
 | 
			
		||||
 | 
			
		||||
      - task: DotNetCoreCLI@2
 | 
			
		||||
        displayName: 'Install ABI CompatibilityChecker tool'
 | 
			
		||||
        inputs:
 | 
			
		||||
          command: custom
 | 
			
		||||
          custom: tool
 | 
			
		||||
          arguments: 'update compatibilitychecker -g'
 | 
			
		||||
 | 
			
		||||
      - task: DownloadPipelineArtifact@2
 | 
			
		||||
        displayName: "Download New Assembly Build Artifact"
 | 
			
		||||
        inputs:
 | 
			
		||||
@ -72,25 +79,11 @@ jobs:
 | 
			
		||||
          overWrite: true
 | 
			
		||||
          flattenFolders: true
 | 
			
		||||
 | 
			
		||||
      - task: DownloadGitHubRelease@0
 | 
			
		||||
        displayName: "Download ABI Compatibility Check Tool"
 | 
			
		||||
        inputs:
 | 
			
		||||
          connection: Jellyfin Release Download
 | 
			
		||||
          userRepository: EraYaN/dotnet-compatibility
 | 
			
		||||
          defaultVersionType: "latest"
 | 
			
		||||
          itemPattern: "**-ci.zip"
 | 
			
		||||
          downloadPath: "$(System.ArtifactsDirectory)"
 | 
			
		||||
 | 
			
		||||
      - task: ExtractFiles@1
 | 
			
		||||
        displayName: "Extract ABI Compatibility Check Tool"
 | 
			
		||||
        inputs:
 | 
			
		||||
          archiveFilePatterns: "$(System.ArtifactsDirectory)/*-ci.zip"
 | 
			
		||||
          destinationFolder: $(System.ArtifactsDirectory)/tools
 | 
			
		||||
          cleanDestinationFolder: true
 | 
			
		||||
 | 
			
		||||
      # The `--warnings-only` switch will swallow the return code and not emit any errors.
 | 
			
		||||
      - task: CmdLine@2
 | 
			
		||||
        displayName: "Execute ABI Compatibility Check Tool"
 | 
			
		||||
      - task: DotNetCoreCLI@2
 | 
			
		||||
        displayName: 'Execute ABI Compatibility Check Tool'
 | 
			
		||||
        inputs:
 | 
			
		||||
          script: "dotnet tools/CompatibilityCheckerCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines --warnings-only"
 | 
			
		||||
          command: custom
 | 
			
		||||
          custom: compat
 | 
			
		||||
          arguments: 'current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines --warnings-only'
 | 
			
		||||
          workingDirectory: $(System.ArtifactsDirectory)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
			
		||||
version: 2
 | 
			
		||||
updates:
 | 
			
		||||
- package-ecosystem: nuget
 | 
			
		||||
  directory: "/"
 | 
			
		||||
  schedule:
 | 
			
		||||
    interval: weekly
 | 
			
		||||
    time: '12:00'
 | 
			
		||||
  open-pull-requests-limit: 10
 | 
			
		||||
  
 | 
			
		||||
@ -7,6 +7,7 @@
 | 
			
		||||
 - [anthonylavado](https://github.com/anthonylavado)
 | 
			
		||||
 - [Artiume](https://github.com/Artiume)
 | 
			
		||||
 - [AThomsen](https://github.com/AThomsen)
 | 
			
		||||
 - [barronpm](https://github.com/barronpm)
 | 
			
		||||
 - [bilde2910](https://github.com/bilde2910)
 | 
			
		||||
 - [bfayers](https://github.com/bfayers)
 | 
			
		||||
 - [BnMcG](https://github.com/BnMcG)
 | 
			
		||||
@ -130,6 +131,7 @@
 | 
			
		||||
 - [XVicarious](https://github.com/XVicarious)
 | 
			
		||||
 - [YouKnowBlom](https://github.com/YouKnowBlom)
 | 
			
		||||
 - [KristupasSavickas](https://github.com/KristupasSavickas)
 | 
			
		||||
 - [Pusta](https://github.com/pusta)
 | 
			
		||||
 | 
			
		||||
# Emby Contributors
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,11 +4,12 @@ using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Emby.Dlna.Service;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using Jellyfin.Data.Enums;
 | 
			
		||||
using MediaBrowser.Common.Net;
 | 
			
		||||
using MediaBrowser.Controller.Configuration;
 | 
			
		||||
using MediaBrowser.Controller.Dlna;
 | 
			
		||||
using MediaBrowser.Controller.Drawing;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.MediaEncoding;
 | 
			
		||||
using MediaBrowser.Controller.TV;
 | 
			
		||||
@ -32,7 +33,8 @@ namespace Emby.Dlna.ContentDirectory
 | 
			
		||||
        private readonly IMediaEncoder _mediaEncoder;
 | 
			
		||||
        private readonly ITVSeriesManager _tvSeriesManager;
 | 
			
		||||
 | 
			
		||||
        public ContentDirectory(IDlnaManager dlna,
 | 
			
		||||
        public ContentDirectory(
 | 
			
		||||
            IDlnaManager dlna,
 | 
			
		||||
            IUserDataManager userDataManager,
 | 
			
		||||
            IImageProcessor imageProcessor,
 | 
			
		||||
            ILibraryManager libraryManager,
 | 
			
		||||
@ -131,7 +133,7 @@ namespace Emby.Dlna.ContentDirectory
 | 
			
		||||
 | 
			
		||||
            foreach (var user in _userManager.Users)
 | 
			
		||||
            {
 | 
			
		||||
                if (user.Policy.IsAdministrator)
 | 
			
		||||
                if (user.HasPermission(PermissionKind.IsAdministrator))
 | 
			
		||||
                {
 | 
			
		||||
                    return user;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,7 @@ using System.Threading;
 | 
			
		||||
using System.Xml;
 | 
			
		||||
using Emby.Dlna.Didl;
 | 
			
		||||
using Emby.Dlna.Service;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Common.Extensions;
 | 
			
		||||
using MediaBrowser.Controller.Configuration;
 | 
			
		||||
using MediaBrowser.Controller.Drawing;
 | 
			
		||||
@ -17,7 +18,6 @@ using MediaBrowser.Controller.Dto;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Audio;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Movies;
 | 
			
		||||
using MediaBrowser.Controller.Entities.TV;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.LiveTv;
 | 
			
		||||
using MediaBrowser.Controller.MediaEncoding;
 | 
			
		||||
@ -28,6 +28,12 @@ using MediaBrowser.Model.Entities;
 | 
			
		||||
using MediaBrowser.Model.Globalization;
 | 
			
		||||
using MediaBrowser.Model.Querying;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Book = MediaBrowser.Controller.Entities.Book;
 | 
			
		||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
 | 
			
		||||
using Genre = MediaBrowser.Controller.Entities.Genre;
 | 
			
		||||
using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
 | 
			
		||||
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
 | 
			
		||||
using Series = MediaBrowser.Controller.Entities.TV.Series;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Dlna.ContentDirectory
 | 
			
		||||
{
 | 
			
		||||
@ -731,7 +737,7 @@ namespace Emby.Dlna.ContentDirectory
 | 
			
		||||
                return GetGenres(item, user, query);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var array = new ServerItem[]
 | 
			
		||||
            var array = new[]
 | 
			
		||||
            {
 | 
			
		||||
                new ServerItem(item)
 | 
			
		||||
                {
 | 
			
		||||
@ -1115,7 +1121,7 @@ namespace Emby.Dlna.ContentDirectory
 | 
			
		||||
        private QueryResult<ServerItem> GetMusicPlaylists(User user, InternalItemsQuery query)
 | 
			
		||||
        {
 | 
			
		||||
            query.Parent = null;
 | 
			
		||||
            query.IncludeItemTypes = new[] { typeof(Playlist).Name };
 | 
			
		||||
            query.IncludeItemTypes = new[] { nameof(Playlist) };
 | 
			
		||||
            query.SetUser(user);
 | 
			
		||||
            query.Recursive = true;
 | 
			
		||||
 | 
			
		||||
@ -1132,10 +1138,9 @@ namespace Emby.Dlna.ContentDirectory
 | 
			
		||||
            {
 | 
			
		||||
                UserId = user.Id,
 | 
			
		||||
                Limit = 50,
 | 
			
		||||
                IncludeItemTypes = new[] { typeof(Audio).Name },
 | 
			
		||||
                ParentId = parent == null ? Guid.Empty : parent.Id,
 | 
			
		||||
                IncludeItemTypes = new[] { nameof(Audio) },
 | 
			
		||||
                ParentId = parent?.Id ?? Guid.Empty,
 | 
			
		||||
                GroupItems = true
 | 
			
		||||
 | 
			
		||||
            }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray();
 | 
			
		||||
 | 
			
		||||
            return ToResult(items);
 | 
			
		||||
@ -1150,7 +1155,6 @@ namespace Emby.Dlna.ContentDirectory
 | 
			
		||||
                Limit = query.Limit,
 | 
			
		||||
                StartIndex = query.StartIndex,
 | 
			
		||||
                UserId = query.User.Id
 | 
			
		||||
 | 
			
		||||
            }, new[] { parent }, query.DtoOptions);
 | 
			
		||||
 | 
			
		||||
            return ToResult(result);
 | 
			
		||||
@ -1167,7 +1171,6 @@ namespace Emby.Dlna.ContentDirectory
 | 
			
		||||
                IncludeItemTypes = new[] { typeof(Episode).Name },
 | 
			
		||||
                ParentId = parent == null ? Guid.Empty : parent.Id,
 | 
			
		||||
                GroupItems = false
 | 
			
		||||
 | 
			
		||||
            }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray();
 | 
			
		||||
 | 
			
		||||
            return ToResult(items);
 | 
			
		||||
@ -1177,14 +1180,14 @@ namespace Emby.Dlna.ContentDirectory
 | 
			
		||||
        {
 | 
			
		||||
            query.OrderBy = Array.Empty<(string, SortOrder)>();
 | 
			
		||||
 | 
			
		||||
            var items = _userViewManager.GetLatestItems(new LatestItemsQuery
 | 
			
		||||
            var items = _userViewManager.GetLatestItems(
 | 
			
		||||
                new LatestItemsQuery
 | 
			
		||||
            {
 | 
			
		||||
                UserId = user.Id,
 | 
			
		||||
                Limit = 50,
 | 
			
		||||
                IncludeItemTypes = new[] { typeof(Movie).Name },
 | 
			
		||||
                ParentId = parent == null ? Guid.Empty : parent.Id,
 | 
			
		||||
                IncludeItemTypes = new[] { nameof(Movie) },
 | 
			
		||||
                ParentId = parent?.Id ?? Guid.Empty,
 | 
			
		||||
                GroupItems = true
 | 
			
		||||
 | 
			
		||||
            }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray();
 | 
			
		||||
 | 
			
		||||
            return ToResult(items);
 | 
			
		||||
@ -1217,7 +1220,11 @@ namespace Emby.Dlna.ContentDirectory
 | 
			
		||||
                Recursive = true,
 | 
			
		||||
                ParentId = parentId,
 | 
			
		||||
                GenreIds = new[] { item.Id },
 | 
			
		||||
                IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Series).Name },
 | 
			
		||||
                IncludeItemTypes = new[]
 | 
			
		||||
                {
 | 
			
		||||
                    nameof(Movie),
 | 
			
		||||
                    nameof(Series)
 | 
			
		||||
                },
 | 
			
		||||
                Limit = limit,
 | 
			
		||||
                StartIndex = startIndex,
 | 
			
		||||
                DtoOptions = GetDtoOptions()
 | 
			
		||||
 | 
			
		||||
@ -6,14 +6,13 @@ using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Xml;
 | 
			
		||||
using Emby.Dlna.Configuration;
 | 
			
		||||
using Emby.Dlna.ContentDirectory;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Channels;
 | 
			
		||||
using MediaBrowser.Controller.Drawing;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Audio;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Movies;
 | 
			
		||||
using MediaBrowser.Controller.Entities.TV;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.MediaEncoding;
 | 
			
		||||
using MediaBrowser.Controller.Playlists;
 | 
			
		||||
@ -23,6 +22,13 @@ using MediaBrowser.Model.Entities;
 | 
			
		||||
using MediaBrowser.Model.Globalization;
 | 
			
		||||
using MediaBrowser.Model.Net;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
 | 
			
		||||
using Genre = MediaBrowser.Controller.Entities.Genre;
 | 
			
		||||
using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
 | 
			
		||||
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
 | 
			
		||||
using Season = MediaBrowser.Controller.Entities.TV.Season;
 | 
			
		||||
using Series = MediaBrowser.Controller.Entities.TV.Series;
 | 
			
		||||
using XmlAttribute = MediaBrowser.Model.Dlna.XmlAttribute;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Dlna.Didl
 | 
			
		||||
{
 | 
			
		||||
@ -421,7 +427,6 @@ namespace Emby.Dlna.Didl
 | 
			
		||||
                    case StubType.FavoriteSeries: return _localization.GetLocalizedString("HeaderFavoriteShows");
 | 
			
		||||
                    case StubType.FavoriteEpisodes: return _localization.GetLocalizedString("HeaderFavoriteEpisodes");
 | 
			
		||||
                    case StubType.Series: return _localization.GetLocalizedString("Shows");
 | 
			
		||||
                    default: break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -670,7 +675,7 @@ namespace Emby.Dlna.Didl
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            MediaBrowser.Model.Dlna.XmlAttribute secAttribute = null;
 | 
			
		||||
            XmlAttribute secAttribute = null;
 | 
			
		||||
            foreach (var attribute in _profile.XmlRootAttributes)
 | 
			
		||||
            {
 | 
			
		||||
                if (string.Equals(attribute.Name, "xmlns:sec", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
@ -995,7 +1000,6 @@ namespace Emby.Dlna.Didl
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            AddImageResElement(item, writer, 160, 160, "jpg", "JPEG_TN");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddImageResElement(
 | 
			
		||||
@ -1135,7 +1139,6 @@ namespace Emby.Dlna.Didl
 | 
			
		||||
                width = null;
 | 
			
		||||
                height = null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            else if (width == -1 || height == -1)
 | 
			
		||||
            {
 | 
			
		||||
                width = null;
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,6 @@ namespace Emby.Dlna.Didl
 | 
			
		||||
        public Filter()
 | 
			
		||||
            : this("*")
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Filter(string filter)
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,7 @@ namespace Emby.Dlna
 | 
			
		||||
        private readonly IApplicationPaths _appPaths;
 | 
			
		||||
        private readonly IXmlSerializer _xmlSerializer;
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<DlnaManager> _logger;
 | 
			
		||||
        private readonly IJsonSerializer _jsonSerializer;
 | 
			
		||||
        private readonly IServerApplicationHost _appHost;
 | 
			
		||||
        private static readonly Assembly _assembly = typeof(DlnaManager).Assembly;
 | 
			
		||||
@ -49,7 +49,7 @@ namespace Emby.Dlna
 | 
			
		||||
            _xmlSerializer = xmlSerializer;
 | 
			
		||||
            _fileSystem = fileSystem;
 | 
			
		||||
            _appPaths = appPaths;
 | 
			
		||||
            _logger = loggerFactory.CreateLogger("Dlna");
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<DlnaManager>();
 | 
			
		||||
            _jsonSerializer = jsonSerializer;
 | 
			
		||||
            _appHost = appHost;
 | 
			
		||||
        }
 | 
			
		||||
@ -88,7 +88,6 @@ namespace Emby.Dlna
 | 
			
		||||
                    .Select(i => i.Item2)
 | 
			
		||||
                    .ToList();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public DeviceProfile GetDefaultProfile()
 | 
			
		||||
 | 
			
		||||
@ -169,7 +169,6 @@ namespace Emby.Dlna.Eventing
 | 
			
		||||
            {
 | 
			
		||||
                using (await _httpClient.SendAsync(options, new HttpMethod("NOTIFY")).ConfigureAwait(false))
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (OperationCanceledException)
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ namespace Emby.Dlna.Main
 | 
			
		||||
    public class DlnaEntryPoint : IServerEntryPoint, IRunBeforeStartup
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IServerConfigurationManager _config;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<DlnaEntryPoint> _logger;
 | 
			
		||||
        private readonly IServerApplicationHost _appHost;
 | 
			
		||||
 | 
			
		||||
        private PlayToManager _manager;
 | 
			
		||||
@ -65,7 +65,8 @@ namespace Emby.Dlna.Main
 | 
			
		||||
 | 
			
		||||
        public static DlnaEntryPoint Current;
 | 
			
		||||
 | 
			
		||||
        public DlnaEntryPoint(IServerConfigurationManager config,
 | 
			
		||||
        public DlnaEntryPoint(
 | 
			
		||||
            IServerConfigurationManager config,
 | 
			
		||||
            ILoggerFactory loggerFactory,
 | 
			
		||||
            IServerApplicationHost appHost,
 | 
			
		||||
            ISessionManager sessionManager,
 | 
			
		||||
@ -99,7 +100,7 @@ namespace Emby.Dlna.Main
 | 
			
		||||
            _mediaEncoder = mediaEncoder;
 | 
			
		||||
            _socketFactory = socketFactory;
 | 
			
		||||
            _networkManager = networkManager;
 | 
			
		||||
            _logger = loggerFactory.CreateLogger("Dlna");
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<DlnaEntryPoint>();
 | 
			
		||||
 | 
			
		||||
            ContentDirectory = new ContentDirectory.ContentDirectory(
 | 
			
		||||
                dlnaManager,
 | 
			
		||||
@ -347,7 +348,8 @@ namespace Emby.Dlna.Main
 | 
			
		||||
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    _manager = new PlayToManager(_logger,
 | 
			
		||||
                    _manager = new PlayToManager(
 | 
			
		||||
                        _logger,
 | 
			
		||||
                        _sessionManager,
 | 
			
		||||
                        _libraryManager,
 | 
			
		||||
                        _userManager,
 | 
			
		||||
 | 
			
		||||
@ -794,7 +794,6 @@ namespace Emby.Dlna.PlayTo
 | 
			
		||||
            }
 | 
			
		||||
            catch (XmlException)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // first try to add a root node with a dlna namesapce
 | 
			
		||||
@ -806,7 +805,6 @@ namespace Emby.Dlna.PlayTo
 | 
			
		||||
            }
 | 
			
		||||
            catch (XmlException)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // some devices send back invalid xml
 | 
			
		||||
@ -816,7 +814,6 @@ namespace Emby.Dlna.PlayTo
 | 
			
		||||
            }
 | 
			
		||||
            catch (XmlException)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Emby.Dlna.Didl;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Common.Configuration;
 | 
			
		||||
using MediaBrowser.Controller.Dlna;
 | 
			
		||||
using MediaBrowser.Controller.Drawing;
 | 
			
		||||
@ -22,6 +23,7 @@ using MediaBrowser.Model.Globalization;
 | 
			
		||||
using MediaBrowser.Model.Session;
 | 
			
		||||
using Microsoft.AspNetCore.WebUtilities;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Photo = MediaBrowser.Controller.Entities.Photo;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Dlna.PlayTo
 | 
			
		||||
{
 | 
			
		||||
@ -446,7 +448,13 @@ namespace Emby.Dlna.PlayTo
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private PlaylistItem CreatePlaylistItem(BaseItem item, User user, long startPostionTicks, string mediaSourceId, int? audioStreamIndex, int? subtitleStreamIndex)
 | 
			
		||||
        private PlaylistItem CreatePlaylistItem(
 | 
			
		||||
            BaseItem item,
 | 
			
		||||
            User user,
 | 
			
		||||
            long startPostionTicks,
 | 
			
		||||
            string mediaSourceId,
 | 
			
		||||
            int? audioStreamIndex,
 | 
			
		||||
            int? subtitleStreamIndex)
 | 
			
		||||
        {
 | 
			
		||||
            var deviceInfo = _device.Properties;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -112,7 +112,6 @@ namespace Emby.Dlna.PlayTo
 | 
			
		||||
            }
 | 
			
		||||
            catch (OperationCanceledException)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
@ -184,7 +183,8 @@ namespace Emby.Dlna.PlayTo
 | 
			
		||||
                    serverAddress = _appHost.GetLocalApiUrl(info.LocalIpAddress);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                controller = new PlayToController(sessionInfo,
 | 
			
		||||
                controller = new PlayToController(
 | 
			
		||||
                    sessionInfo,
 | 
			
		||||
                   _sessionManager,
 | 
			
		||||
                   _libraryManager,
 | 
			
		||||
                   _logger,
 | 
			
		||||
@ -242,7 +242,6 @@ namespace Emby.Dlna.PlayTo
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _sessionLock.Dispose();
 | 
			
		||||
 | 
			
		||||
@ -91,7 +91,6 @@ namespace Emby.Dlna.PlayTo
 | 
			
		||||
 | 
			
		||||
            using (await _httpClient.SendAsync(options, new HttpMethod("SUBSCRIBE")).ConfigureAwait(false))
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ namespace Emby.Dlna.Service
 | 
			
		||||
            Logger = logger;
 | 
			
		||||
            HttpClient = httpClient;
 | 
			
		||||
 | 
			
		||||
            EventManager = new EventManager(Logger, HttpClient);
 | 
			
		||||
            EventManager = new EventManager(logger, HttpClient);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public EventSubscriptionResponse CancelEventSubscription(string subscriptionId)
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ using System.Globalization;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Common.Extensions;
 | 
			
		||||
using MediaBrowser.Controller;
 | 
			
		||||
using MediaBrowser.Controller.Drawing;
 | 
			
		||||
@ -14,6 +15,7 @@ using MediaBrowser.Model.Entities;
 | 
			
		||||
using MediaBrowser.Model.IO;
 | 
			
		||||
using MediaBrowser.Model.Net;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Photo = MediaBrowser.Controller.Entities.Photo;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Drawing
 | 
			
		||||
{
 | 
			
		||||
@ -28,7 +30,7 @@ namespace Emby.Drawing
 | 
			
		||||
        private static readonly HashSet<string> _transparentImageTypes
 | 
			
		||||
            = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".png", ".webp", ".gif" };
 | 
			
		||||
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<ImageProcessor> _logger;
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
        private readonly IServerApplicationPaths _appPaths;
 | 
			
		||||
        private readonly IImageEncoder _imageEncoder;
 | 
			
		||||
@ -300,7 +302,7 @@ namespace Emby.Drawing
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            string path = info.Path;
 | 
			
		||||
            _logger.LogInformation("Getting image size for item {ItemType} {Path}", item.GetType().Name, path);
 | 
			
		||||
            _logger.LogDebug("Getting image size for item {ItemType} {Path}", item.GetType().Name, path);
 | 
			
		||||
 | 
			
		||||
            ImageDimensions size = GetImageDimensions(path);
 | 
			
		||||
            info.Width = size.Width;
 | 
			
		||||
@ -349,6 +351,13 @@ namespace Emby.Drawing
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <inheritdoc />
 | 
			
		||||
        public string GetImageCacheTag(User user)
 | 
			
		||||
        {
 | 
			
		||||
            return (user.ProfileImage.Path + user.ProfileImage.LastModified.Ticks).GetMD5()
 | 
			
		||||
                .ToString("N", CultureInfo.InvariantCulture);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<(string path, DateTime dateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
 | 
			
		||||
        {
 | 
			
		||||
            var inputFormat = Path.GetExtension(originalImagePath)
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Jellyfin.Data.Enums;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.Net;
 | 
			
		||||
using MediaBrowser.Controller.Notifications;
 | 
			
		||||
@ -149,9 +150,7 @@ namespace Emby.Notifications.Api
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
 | 
			
		||||
        public object Get(GetNotificationsSummary request)
 | 
			
		||||
        {
 | 
			
		||||
            return new NotificationsSummary
 | 
			
		||||
            {
 | 
			
		||||
            };
 | 
			
		||||
            return new NotificationsSummary();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Task Post(AddAdminNotification request)
 | 
			
		||||
@ -164,7 +163,10 @@ namespace Emby.Notifications.Api
 | 
			
		||||
                Level = request.Level,
 | 
			
		||||
                Name = request.Name,
 | 
			
		||||
                Url = request.Url,
 | 
			
		||||
                UserIds = _userManager.Users.Where(i => i.Policy.IsAdministrator).Select(i => i.Id).ToArray()
 | 
			
		||||
                UserIds = _userManager.Users
 | 
			
		||||
                    .Where(user => user.HasPermission(PermissionKind.IsAdministrator))
 | 
			
		||||
                    .Select(user => user.Id)
 | 
			
		||||
                    .ToArray()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            return _notificationManager.SendNotification(notification, CancellationToken.None);
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,7 @@ namespace Emby.Notifications
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class NotificationEntryPoint : IServerEntryPoint
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<NotificationEntryPoint> _logger;
 | 
			
		||||
        private readonly IActivityManager _activityManager;
 | 
			
		||||
        private readonly ILocalizationManager _localization;
 | 
			
		||||
        private readonly INotificationManager _notificationManager;
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,8 @@ using System.Globalization;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using Jellyfin.Data.Enums;
 | 
			
		||||
using MediaBrowser.Common.Configuration;
 | 
			
		||||
using MediaBrowser.Common.Extensions;
 | 
			
		||||
using MediaBrowser.Controller.Configuration;
 | 
			
		||||
@ -21,7 +23,7 @@ namespace Emby.Notifications
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class NotificationManager : INotificationManager
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<NotificationManager> _logger;
 | 
			
		||||
        private readonly IUserManager _userManager;
 | 
			
		||||
        private readonly IServerConfigurationManager _config;
 | 
			
		||||
 | 
			
		||||
@ -101,7 +103,7 @@ namespace Emby.Notifications
 | 
			
		||||
                switch (request.SendToUserMode.Value)
 | 
			
		||||
                {
 | 
			
		||||
                    case SendToUserType.Admins:
 | 
			
		||||
                        return _userManager.Users.Where(i => i.Policy.IsAdministrator)
 | 
			
		||||
                        return _userManager.Users.Where(i => i.HasPermission(PermissionKind.IsAdministrator))
 | 
			
		||||
                                .Select(i => i.Id);
 | 
			
		||||
                    case SendToUserType.All:
 | 
			
		||||
                        return _userManager.UsersIds;
 | 
			
		||||
@ -117,7 +119,7 @@ namespace Emby.Notifications
 | 
			
		||||
                var config = GetConfiguration();
 | 
			
		||||
 | 
			
		||||
                return _userManager.Users
 | 
			
		||||
                    .Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N", CultureInfo.InvariantCulture), i.Policy))
 | 
			
		||||
                    .Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N", CultureInfo.InvariantCulture), i))
 | 
			
		||||
                    .Select(i => i.Id);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -142,7 +144,7 @@ namespace Emby.Notifications
 | 
			
		||||
                User = user
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            _logger.LogDebug("Sending notification via {0} to user {1}", service.Name, user.Name);
 | 
			
		||||
            _logger.LogDebug("Sending notification via {0} to user {1}", service.Name, user.Username);
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
@ -22,7 +22,7 @@ namespace Emby.Photos
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class PhotoProvider : ICustomMetadataProvider<Photo>, IForcedProvider, IHasItemChangeMonitor
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<PhotoProvider> _logger;
 | 
			
		||||
        private readonly IImageProcessor _imageProcessor;
 | 
			
		||||
 | 
			
		||||
        // These are causing taglib to hang
 | 
			
		||||
@ -104,7 +104,7 @@ namespace Emby.Photos
 | 
			
		||||
                            item.Overview = image.ImageTag.Comment;
 | 
			
		||||
 | 
			
		||||
                            if (!string.IsNullOrWhiteSpace(image.ImageTag.Title)
 | 
			
		||||
                                && !item.LockedFields.Contains(MetadataFields.Name))
 | 
			
		||||
                                && !item.LockedFields.Contains(MetadataField.Name))
 | 
			
		||||
                            {
 | 
			
		||||
                                item.Name = image.ImageTag.Title;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
@ -88,25 +88,26 @@ namespace Emby.Server.Implementations.Activity
 | 
			
		||||
 | 
			
		||||
            _subManager.SubtitleDownloadFailure += OnSubtitleDownloadFailure;
 | 
			
		||||
 | 
			
		||||
            _userManager.UserCreated += OnUserCreated;
 | 
			
		||||
            _userManager.UserPasswordChanged += OnUserPasswordChanged;
 | 
			
		||||
            _userManager.UserDeleted += OnUserDeleted;
 | 
			
		||||
            _userManager.UserPolicyUpdated += OnUserPolicyUpdated;
 | 
			
		||||
            _userManager.UserLockedOut += OnUserLockedOut;
 | 
			
		||||
            _userManager.OnUserCreated += OnUserCreated;
 | 
			
		||||
            _userManager.OnUserPasswordChanged += OnUserPasswordChanged;
 | 
			
		||||
            _userManager.OnUserDeleted += OnUserDeleted;
 | 
			
		||||
            _userManager.OnUserLockedOut += OnUserLockedOut;
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async void OnUserLockedOut(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
 | 
			
		||||
        private async void OnUserLockedOut(object sender, GenericEventArgs<User> e)
 | 
			
		||||
        {
 | 
			
		||||
            await CreateLogEntry(new ActivityLog(
 | 
			
		||||
                    string.Format(
 | 
			
		||||
                        CultureInfo.InvariantCulture,
 | 
			
		||||
                        _localization.GetLocalizedString("UserLockedOutWithName"),
 | 
			
		||||
                        e.Argument.Name),
 | 
			
		||||
                        e.Argument.Username),
 | 
			
		||||
                    NotificationType.UserLockedOut.ToString(),
 | 
			
		||||
                    e.Argument.Id))
 | 
			
		||||
                .ConfigureAwait(false);
 | 
			
		||||
                    e.Argument.Id)
 | 
			
		||||
            {
 | 
			
		||||
                LogSeverity = LogLevel.Error
 | 
			
		||||
            }).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async void OnSubtitleDownloadFailure(object sender, SubtitleDownloadFailureEventArgs e)
 | 
			
		||||
@ -152,7 +153,7 @@ namespace Emby.Server.Implementations.Activity
 | 
			
		||||
                string.Format(
 | 
			
		||||
                    CultureInfo.InvariantCulture,
 | 
			
		||||
                    _localization.GetLocalizedString("UserStoppedPlayingItemWithValues"),
 | 
			
		||||
                    user.Name,
 | 
			
		||||
                    user.Username,
 | 
			
		||||
                    GetItemName(item),
 | 
			
		||||
                    e.DeviceName),
 | 
			
		||||
                GetPlaybackStoppedNotificationType(item.MediaType),
 | 
			
		||||
@ -187,7 +188,7 @@ namespace Emby.Server.Implementations.Activity
 | 
			
		||||
                string.Format(
 | 
			
		||||
                    CultureInfo.InvariantCulture,
 | 
			
		||||
                    _localization.GetLocalizedString("UserStartedPlayingItemWithValues"),
 | 
			
		||||
                    user.Name,
 | 
			
		||||
                    user.Username,
 | 
			
		||||
                    GetItemName(item),
 | 
			
		||||
                    e.DeviceName),
 | 
			
		||||
                GetPlaybackNotificationType(item.MediaType),
 | 
			
		||||
@ -304,49 +305,37 @@ namespace Emby.Server.Implementations.Activity
 | 
			
		||||
            }).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async void OnUserPolicyUpdated(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
 | 
			
		||||
        {
 | 
			
		||||
            await CreateLogEntry(new ActivityLog(
 | 
			
		||||
                string.Format(
 | 
			
		||||
                    CultureInfo.InvariantCulture,
 | 
			
		||||
                    _localization.GetLocalizedString("UserPolicyUpdatedWithName"),
 | 
			
		||||
                    e.Argument.Name),
 | 
			
		||||
                "UserPolicyUpdated",
 | 
			
		||||
                e.Argument.Id))
 | 
			
		||||
                .ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async void OnUserDeleted(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
 | 
			
		||||
        private async void OnUserDeleted(object sender, GenericEventArgs<User> e)
 | 
			
		||||
        {
 | 
			
		||||
            await CreateLogEntry(new ActivityLog(
 | 
			
		||||
                string.Format(
 | 
			
		||||
                    CultureInfo.InvariantCulture,
 | 
			
		||||
                    _localization.GetLocalizedString("UserDeletedWithName"),
 | 
			
		||||
                    e.Argument.Name),
 | 
			
		||||
                    e.Argument.Username),
 | 
			
		||||
                "UserDeleted",
 | 
			
		||||
                Guid.Empty))
 | 
			
		||||
                .ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async void OnUserPasswordChanged(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
 | 
			
		||||
        private async void OnUserPasswordChanged(object sender, GenericEventArgs<User> e)
 | 
			
		||||
        {
 | 
			
		||||
            await CreateLogEntry(new ActivityLog(
 | 
			
		||||
                string.Format(
 | 
			
		||||
                    CultureInfo.InvariantCulture,
 | 
			
		||||
                    _localization.GetLocalizedString("UserPasswordChangedWithName"),
 | 
			
		||||
                    e.Argument.Name),
 | 
			
		||||
                    e.Argument.Username),
 | 
			
		||||
                "UserPasswordChanged",
 | 
			
		||||
                e.Argument.Id))
 | 
			
		||||
                .ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async void OnUserCreated(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
 | 
			
		||||
        private async void OnUserCreated(object sender, GenericEventArgs<User> e)
 | 
			
		||||
        {
 | 
			
		||||
            await CreateLogEntry(new ActivityLog(
 | 
			
		||||
                string.Format(
 | 
			
		||||
                    CultureInfo.InvariantCulture,
 | 
			
		||||
                    _localization.GetLocalizedString("UserCreatedWithName"),
 | 
			
		||||
                    e.Argument.Name),
 | 
			
		||||
                    e.Argument.Username),
 | 
			
		||||
                "UserCreated",
 | 
			
		||||
                e.Argument.Id))
 | 
			
		||||
                .ConfigureAwait(false);
 | 
			
		||||
@ -510,11 +499,10 @@ namespace Emby.Server.Implementations.Activity
 | 
			
		||||
 | 
			
		||||
            _subManager.SubtitleDownloadFailure -= OnSubtitleDownloadFailure;
 | 
			
		||||
 | 
			
		||||
            _userManager.UserCreated -= OnUserCreated;
 | 
			
		||||
            _userManager.UserPasswordChanged -= OnUserPasswordChanged;
 | 
			
		||||
            _userManager.UserDeleted -= OnUserDeleted;
 | 
			
		||||
            _userManager.UserPolicyUpdated -= OnUserPolicyUpdated;
 | 
			
		||||
            _userManager.UserLockedOut -= OnUserLockedOut;
 | 
			
		||||
            _userManager.OnUserCreated -= OnUserCreated;
 | 
			
		||||
            _userManager.OnUserPasswordChanged -= OnUserPasswordChanged;
 | 
			
		||||
            _userManager.OnUserDeleted -= OnUserDeleted;
 | 
			
		||||
            _userManager.OnUserLockedOut -= OnUserLockedOut;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
 | 
			
		||||
@ -53,7 +53,7 @@ namespace Emby.Server.Implementations.AppBase
 | 
			
		||||
            CommonApplicationPaths = applicationPaths;
 | 
			
		||||
            XmlSerializer = xmlSerializer;
 | 
			
		||||
            _fileSystem = fileSystem;
 | 
			
		||||
            Logger = loggerFactory.CreateLogger(GetType().Name);
 | 
			
		||||
            Logger = loggerFactory.CreateLogger<BaseConfigurationManager>();
 | 
			
		||||
 | 
			
		||||
            UpdateCachePath();
 | 
			
		||||
        }
 | 
			
		||||
@ -83,7 +83,7 @@ namespace Emby.Server.Implementations.AppBase
 | 
			
		||||
        /// Gets the logger.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <value>The logger.</value>
 | 
			
		||||
        protected ILogger Logger { get; private set; }
 | 
			
		||||
        protected ILogger<BaseConfigurationManager> Logger { get; private set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the XML serializer.
 | 
			
		||||
 | 
			
		||||
@ -173,7 +173,7 @@ namespace Emby.Server.Implementations
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the logger.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        protected ILogger Logger { get; }
 | 
			
		||||
        protected ILogger<ApplicationHost> Logger { get; }
 | 
			
		||||
 | 
			
		||||
        private IPlugin[] _plugins;
 | 
			
		||||
 | 
			
		||||
@ -562,11 +562,8 @@ namespace Emby.Server.Implementations
 | 
			
		||||
 | 
			
		||||
            serviceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
 | 
			
		||||
 | 
			
		||||
            serviceCollection.AddSingleton<IUserRepository, SqliteUserRepository>();
 | 
			
		||||
 | 
			
		||||
            // TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
 | 
			
		||||
            serviceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>));
 | 
			
		||||
            serviceCollection.AddSingleton<IUserManager, UserManager>();
 | 
			
		||||
 | 
			
		||||
            // TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
 | 
			
		||||
            // TODO: Add StartupOptions.FFmpegPath to IConfiguration and remove this custom activation
 | 
			
		||||
@ -659,15 +656,11 @@ namespace Emby.Server.Implementations
 | 
			
		||||
 | 
			
		||||
            ((SqliteDisplayPreferencesRepository)Resolve<IDisplayPreferencesRepository>()).Initialize();
 | 
			
		||||
            ((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
 | 
			
		||||
            ((SqliteUserRepository)Resolve<IUserRepository>()).Initialize();
 | 
			
		||||
 | 
			
		||||
            SetStaticProperties();
 | 
			
		||||
 | 
			
		||||
            var userManager = (UserManager)Resolve<IUserManager>();
 | 
			
		||||
            userManager.Initialize();
 | 
			
		||||
 | 
			
		||||
            var userDataRepo = (SqliteUserDataRepository)Resolve<IUserDataRepository>();
 | 
			
		||||
            ((SqliteItemRepository)Resolve<IItemRepository>()).Initialize(userDataRepo, userManager);
 | 
			
		||||
            ((SqliteItemRepository)Resolve<IItemRepository>()).Initialize(userDataRepo, Resolve<IUserManager>());
 | 
			
		||||
 | 
			
		||||
            FindParts();
 | 
			
		||||
        }
 | 
			
		||||
@ -750,7 +743,6 @@ namespace Emby.Server.Implementations
 | 
			
		||||
            BaseItem.ProviderManager = Resolve<IProviderManager>();
 | 
			
		||||
            BaseItem.LocalizationManager = Resolve<ILocalizationManager>();
 | 
			
		||||
            BaseItem.ItemRepository = Resolve<IItemRepository>();
 | 
			
		||||
            User.UserManager = Resolve<IUserManager>();
 | 
			
		||||
            BaseItem.FileSystem = _fileSystemManager;
 | 
			
		||||
            BaseItem.UserDataManager = Resolve<IUserDataManager>();
 | 
			
		||||
            BaseItem.ChannelManager = Resolve<IChannelManager>();
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,7 @@ namespace Emby.Server.Implementations.Browser
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                var logger = appHost.Resolve<ILogger>();
 | 
			
		||||
                var logger = appHost.Resolve<ILogger<IServerApplicationHost>>();
 | 
			
		||||
                logger?.LogError(ex, "Failed to open browser window with URL {URL}", relativeUrl);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Common.Extensions;
 | 
			
		||||
using MediaBrowser.Common.Progress;
 | 
			
		||||
using MediaBrowser.Controller.Channels;
 | 
			
		||||
@ -13,8 +14,6 @@ using MediaBrowser.Controller.Configuration;
 | 
			
		||||
using MediaBrowser.Controller.Dto;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Audio;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Movies;
 | 
			
		||||
using MediaBrowser.Controller.Entities.TV;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.Providers;
 | 
			
		||||
using MediaBrowser.Model.Channels;
 | 
			
		||||
@ -24,6 +23,11 @@ using MediaBrowser.Model.IO;
 | 
			
		||||
using MediaBrowser.Model.Querying;
 | 
			
		||||
using MediaBrowser.Model.Serialization;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
 | 
			
		||||
using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
 | 
			
		||||
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
 | 
			
		||||
using Season = MediaBrowser.Controller.Entities.TV.Season;
 | 
			
		||||
using Series = MediaBrowser.Controller.Entities.TV.Series;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.Channels
 | 
			
		||||
{
 | 
			
		||||
@ -36,7 +40,7 @@ namespace Emby.Server.Implementations.Channels
 | 
			
		||||
        private readonly IUserDataManager _userDataManager;
 | 
			
		||||
        private readonly IDtoService _dtoService;
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<ChannelManager> _logger;
 | 
			
		||||
        private readonly IServerConfigurationManager _config;
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
        private readonly IJsonSerializer _jsonSerializer;
 | 
			
		||||
@ -791,7 +795,8 @@ namespace Emby.Server.Implementations.Channels
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<ChannelItemResult> GetChannelItems(IChannel channel,
 | 
			
		||||
        private async Task<ChannelItemResult> GetChannelItems(
 | 
			
		||||
            IChannel channel,
 | 
			
		||||
            User user,
 | 
			
		||||
            string externalFolderId,
 | 
			
		||||
            ChannelItemSortField? sortField,
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.Channels
 | 
			
		||||
    public class RefreshChannelsScheduledTask : IScheduledTask, IConfigurableScheduledTask
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IChannelManager _channelManager;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<RefreshChannelsScheduledTask> _logger;
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
        private readonly ILocalizationManager _localization;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Common.Configuration;
 | 
			
		||||
using MediaBrowser.Controller.Collections;
 | 
			
		||||
using MediaBrowser.Controller.Configuration;
 | 
			
		||||
@ -29,7 +30,7 @@ namespace Emby.Server.Implementations.Collections
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
        private readonly ILibraryMonitor _iLibraryMonitor;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<CollectionManager> _logger;
 | 
			
		||||
        private readonly IProviderManager _providerManager;
 | 
			
		||||
        private readonly ILocalizationManager _localizationManager;
 | 
			
		||||
        private readonly IApplicationPaths _appPaths;
 | 
			
		||||
@ -56,7 +57,7 @@ namespace Emby.Server.Implementations.Collections
 | 
			
		||||
            _libraryManager = libraryManager;
 | 
			
		||||
            _fileSystem = fileSystem;
 | 
			
		||||
            _iLibraryMonitor = iLibraryMonitor;
 | 
			
		||||
            _logger = loggerFactory.CreateLogger(nameof(CollectionManager));
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<CollectionManager>();
 | 
			
		||||
            _providerManager = providerManager;
 | 
			
		||||
            _localizationManager = localizationManager;
 | 
			
		||||
            _appPaths = appPaths;
 | 
			
		||||
@ -370,7 +371,7 @@ namespace Emby.Server.Implementations.Collections
 | 
			
		||||
    {
 | 
			
		||||
        private readonly CollectionManager _collectionManager;
 | 
			
		||||
        private readonly IServerConfigurationManager _config;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<CollectionManagerEntryPoint> _logger;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Initializes a new instance of the <see cref="CollectionManagerEntryPoint"/> class.
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.Data
 | 
			
		||||
        /// Initializes a new instance of the <see cref="BaseSqliteRepository"/> class.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="logger">The logger.</param>
 | 
			
		||||
        protected BaseSqliteRepository(ILogger logger)
 | 
			
		||||
        protected BaseSqliteRepository(ILogger<BaseSqliteRepository> logger)
 | 
			
		||||
        {
 | 
			
		||||
            Logger = logger;
 | 
			
		||||
        }
 | 
			
		||||
@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.Data
 | 
			
		||||
        /// Gets the logger.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <value>The logger.</value>
 | 
			
		||||
        protected ILogger Logger { get; }
 | 
			
		||||
        protected ILogger<BaseSqliteRepository> Logger { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the default connection flags.
 | 
			
		||||
@ -162,7 +162,6 @@ namespace Emby.Server.Implementations.Data
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            }, ReadTransactionMode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Data
 | 
			
		||||
    public class CleanDatabaseScheduledTask : ILibraryPostScanTask
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<CleanDatabaseScheduledTask> _logger;
 | 
			
		||||
 | 
			
		||||
        public CleanDatabaseScheduledTask(ILibraryManager libraryManager, ILogger<CleanDatabaseScheduledTask> logger)
 | 
			
		||||
        {
 | 
			
		||||
@ -51,7 +51,6 @@ namespace Emby.Server.Implementations.Data
 | 
			
		||||
                    _libraryManager.DeleteItem(item, new DeleteOptions
 | 
			
		||||
                    {
 | 
			
		||||
                        DeleteFileLocation = false
 | 
			
		||||
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
#pragma warning disable CS1591
 | 
			
		||||
#pragma warning disable CS1591
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
@ -321,7 +321,6 @@ namespace Emby.Server.Implementations.Data
 | 
			
		||||
                    AddColumn(db, "MediaStreams", "ColorPrimaries", "TEXT", existingColumnNames);
 | 
			
		||||
                    AddColumn(db, "MediaStreams", "ColorSpace", "TEXT", existingColumnNames);
 | 
			
		||||
                    AddColumn(db, "MediaStreams", "ColorTransfer", "TEXT", existingColumnNames);
 | 
			
		||||
 | 
			
		||||
                }, TransactionMode);
 | 
			
		||||
 | 
			
		||||
                connection.RunQueries(postQueries);
 | 
			
		||||
@ -1626,11 +1625,11 @@ namespace Emby.Server.Implementations.Data
 | 
			
		||||
            {
 | 
			
		||||
                if (!reader.IsDBNull(index))
 | 
			
		||||
                {
 | 
			
		||||
                    IEnumerable<MetadataFields> GetLockedFields(string s)
 | 
			
		||||
                    IEnumerable<MetadataField> GetLockedFields(string s)
 | 
			
		||||
                    {
 | 
			
		||||
                        foreach (var i in s.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries))
 | 
			
		||||
                        {
 | 
			
		||||
                            if (Enum.TryParse(i, true, out MetadataFields parsedValue))
 | 
			
		||||
                            if (Enum.TryParse(i, true, out MetadataField parsedValue))
 | 
			
		||||
                            {
 | 
			
		||||
                                yield return parsedValue;
 | 
			
		||||
                            }
 | 
			
		||||
@ -2044,7 +2043,6 @@ namespace Emby.Server.Implementations.Data
 | 
			
		||||
                    db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", idBlob);
 | 
			
		||||
 | 
			
		||||
                    InsertChapters(idBlob, chapters, db);
 | 
			
		||||
 | 
			
		||||
                }, TransactionMode);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -2734,7 +2732,7 @@ namespace Emby.Server.Implementations.Data
 | 
			
		||||
 | 
			
		||||
                foreach (var providerId in newItem.ProviderIds)
 | 
			
		||||
                {
 | 
			
		||||
                    if (providerId.Key == MetadataProviders.TmdbCollection.ToString())
 | 
			
		||||
                    if (providerId.Key == MetadataProvider.TmdbCollection.ToString())
 | 
			
		||||
                    {
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
@ -4324,7 +4322,7 @@ namespace Emby.Server.Implementations.Data
 | 
			
		||||
                var index = 0;
 | 
			
		||||
                foreach (var pair in query.ExcludeProviderIds)
 | 
			
		||||
                {
 | 
			
		||||
                    if (string.Equals(pair.Key, MetadataProviders.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                    if (string.Equals(pair.Key, MetadataProvider.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                    {
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
@ -4353,7 +4351,7 @@ namespace Emby.Server.Implementations.Data
 | 
			
		||||
                var index = 0;
 | 
			
		||||
                foreach (var pair in query.HasAnyProviderId)
 | 
			
		||||
                {
 | 
			
		||||
                    if (string.Equals(pair.Key, MetadataProviders.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                    if (string.Equals(pair.Key, MetadataProvider.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                    {
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
@ -4789,7 +4787,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
 | 
			
		||||
                connection.RunInTransaction(db =>
 | 
			
		||||
                {
 | 
			
		||||
                    connection.ExecuteAll(sql);
 | 
			
		||||
 | 
			
		||||
                }, TransactionMode);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -5180,7 +5177,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            LogQueryTime("GetItemValueNames", commandText, now);
 | 
			
		||||
@ -5631,7 +5627,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
 | 
			
		||||
                    db.Execute("delete from People where ItemId=@ItemId", itemIdBlob);
 | 
			
		||||
 | 
			
		||||
                    InsertPeople(itemIdBlob, people, db);
 | 
			
		||||
 | 
			
		||||
                }, TransactionMode);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -5788,7 +5783,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
 | 
			
		||||
                    db.Execute("delete from mediastreams where ItemId=@ItemId", itemIdBlob);
 | 
			
		||||
 | 
			
		||||
                    InsertMediaStreams(itemIdBlob, streams, db);
 | 
			
		||||
 | 
			
		||||
                }, TransactionMode);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -6134,7 +6128,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
 | 
			
		||||
                    db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob);
 | 
			
		||||
 | 
			
		||||
                    InsertMediaAttachments(itemIdBlob, attachments, db, cancellationToken);
 | 
			
		||||
 | 
			
		||||
                }, TransactionMode);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Common.Configuration;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
 | 
			
		||||
@ -1,240 +0,0 @@
 | 
			
		||||
#pragma warning disable CS1591
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
using MediaBrowser.Common.Json;
 | 
			
		||||
using MediaBrowser.Controller;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Persistence;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using SQLitePCL.pretty;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.Data
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Class SQLiteUserRepository
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class SqliteUserRepository : BaseSqliteRepository, IUserRepository
 | 
			
		||||
    {
 | 
			
		||||
        private readonly JsonSerializerOptions _jsonOptions;
 | 
			
		||||
 | 
			
		||||
        public SqliteUserRepository(
 | 
			
		||||
            ILogger<SqliteUserRepository> logger,
 | 
			
		||||
            IServerApplicationPaths appPaths)
 | 
			
		||||
            : base(logger)
 | 
			
		||||
        {
 | 
			
		||||
            _jsonOptions = JsonDefaults.GetOptions();
 | 
			
		||||
 | 
			
		||||
            DbFilePath = Path.Combine(appPaths.DataPath, "users.db");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the name of the repository
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <value>The name.</value>
 | 
			
		||||
        public string Name => "SQLite";
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Opens the connection to the database.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public void Initialize()
 | 
			
		||||
        {
 | 
			
		||||
            using (var connection = GetConnection())
 | 
			
		||||
            {
 | 
			
		||||
                var localUsersTableExists = TableExists(connection, "LocalUsersv2");
 | 
			
		||||
 | 
			
		||||
                connection.RunQueries(new[] {
 | 
			
		||||
                    "create table if not exists LocalUsersv2 (Id INTEGER PRIMARY KEY, guid GUID NOT NULL, data BLOB NOT NULL)",
 | 
			
		||||
                    "drop index if exists idx_users"
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                if (!localUsersTableExists && TableExists(connection, "Users"))
 | 
			
		||||
                {
 | 
			
		||||
                    TryMigrateToLocalUsersTable(connection);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                RemoveEmptyPasswordHashes(connection);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void TryMigrateToLocalUsersTable(ManagedConnection connection)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                connection.RunQueries(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "INSERT INTO LocalUsersv2 (guid, data) SELECT guid,data from users"
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Logger.LogError(ex, "Error migrating users database");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void RemoveEmptyPasswordHashes(ManagedConnection connection)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var user in RetrieveAllUsers(connection))
 | 
			
		||||
            {
 | 
			
		||||
                // If the user password is the sha1 hash of the empty string, remove it
 | 
			
		||||
                if (!string.Equals(user.Password, "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709", StringComparison.Ordinal)
 | 
			
		||||
                    && !string.Equals(user.Password, "$SHA1$DA39A3EE5E6B4B0D3255BFEF95601890AFD80709", StringComparison.Ordinal))
 | 
			
		||||
                {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                user.Password = null;
 | 
			
		||||
                var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions);
 | 
			
		||||
 | 
			
		||||
                connection.RunInTransaction(db =>
 | 
			
		||||
                {
 | 
			
		||||
                    using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId"))
 | 
			
		||||
                    {
 | 
			
		||||
                        statement.TryBind("@InternalId", user.InternalId);
 | 
			
		||||
                        statement.TryBind("@data", serialized);
 | 
			
		||||
                        statement.MoveNext();
 | 
			
		||||
                    }
 | 
			
		||||
                }, TransactionMode);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Save a user in the repo
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public void CreateUser(User user)
 | 
			
		||||
        {
 | 
			
		||||
            if (user == null)
 | 
			
		||||
            {
 | 
			
		||||
                throw new ArgumentNullException(nameof(user));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions);
 | 
			
		||||
 | 
			
		||||
            using (var connection = GetConnection())
 | 
			
		||||
            {
 | 
			
		||||
                connection.RunInTransaction(db =>
 | 
			
		||||
                {
 | 
			
		||||
                    using (var statement = db.PrepareStatement("insert into LocalUsersv2 (guid, data) values (@guid, @data)"))
 | 
			
		||||
                    {
 | 
			
		||||
                        statement.TryBind("@guid", user.Id.ToByteArray());
 | 
			
		||||
                        statement.TryBind("@data", serialized);
 | 
			
		||||
 | 
			
		||||
                        statement.MoveNext();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    var createdUser = GetUser(user.Id, connection);
 | 
			
		||||
 | 
			
		||||
                    if (createdUser == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        throw new ApplicationException("created user should never be null");
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    user.InternalId = createdUser.InternalId;
 | 
			
		||||
 | 
			
		||||
                }, TransactionMode);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void UpdateUser(User user)
 | 
			
		||||
        {
 | 
			
		||||
            if (user == null)
 | 
			
		||||
            {
 | 
			
		||||
                throw new ArgumentNullException(nameof(user));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions);
 | 
			
		||||
 | 
			
		||||
            using (var connection = GetConnection())
 | 
			
		||||
            {
 | 
			
		||||
                connection.RunInTransaction(db =>
 | 
			
		||||
                {
 | 
			
		||||
                    using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId"))
 | 
			
		||||
                    {
 | 
			
		||||
                        statement.TryBind("@InternalId", user.InternalId);
 | 
			
		||||
                        statement.TryBind("@data", serialized);
 | 
			
		||||
                        statement.MoveNext();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                }, TransactionMode);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private User GetUser(Guid guid, ManagedConnection connection)
 | 
			
		||||
        {
 | 
			
		||||
            using (var statement = connection.PrepareStatement("select id,guid,data from LocalUsersv2 where guid=@guid"))
 | 
			
		||||
            {
 | 
			
		||||
                statement.TryBind("@guid", guid);
 | 
			
		||||
 | 
			
		||||
                foreach (var row in statement.ExecuteQuery())
 | 
			
		||||
                {
 | 
			
		||||
                    return GetUser(row);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private User GetUser(IReadOnlyList<IResultSetValue> row)
 | 
			
		||||
        {
 | 
			
		||||
            var id = row[0].ToInt64();
 | 
			
		||||
            var guid = row[1].ReadGuidFromBlob();
 | 
			
		||||
 | 
			
		||||
            var user = JsonSerializer.Deserialize<User>(row[2].ToBlob(), _jsonOptions);
 | 
			
		||||
            user.InternalId = id;
 | 
			
		||||
            user.Id = guid;
 | 
			
		||||
            return user;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Retrieve all users from the database
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <returns>IEnumerable{User}.</returns>
 | 
			
		||||
        public List<User> RetrieveAllUsers()
 | 
			
		||||
        {
 | 
			
		||||
            using (var connection = GetConnection(true))
 | 
			
		||||
            {
 | 
			
		||||
                return new List<User>(RetrieveAllUsers(connection));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Retrieve all users from the database
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <returns>IEnumerable{User}.</returns>
 | 
			
		||||
        private IEnumerable<User> RetrieveAllUsers(ManagedConnection connection)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var row in connection.Query("select id,guid,data from LocalUsersv2"))
 | 
			
		||||
            {
 | 
			
		||||
                yield return GetUser(row);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Deletes the user.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="user">The user.</param>
 | 
			
		||||
        /// <returns>Task.</returns>
 | 
			
		||||
        /// <exception cref="ArgumentNullException">user</exception>
 | 
			
		||||
        public void DeleteUser(User user)
 | 
			
		||||
        {
 | 
			
		||||
            if (user == null)
 | 
			
		||||
            {
 | 
			
		||||
                throw new ArgumentNullException(nameof(user));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            using (var connection = GetConnection())
 | 
			
		||||
            {
 | 
			
		||||
                connection.RunInTransaction(db =>
 | 
			
		||||
                {
 | 
			
		||||
                    using (var statement = db.PrepareStatement("delete from LocalUsersv2 where Id=@id"))
 | 
			
		||||
                    {
 | 
			
		||||
                        statement.TryBind("@id", user.InternalId);
 | 
			
		||||
                        statement.MoveNext();
 | 
			
		||||
                    }
 | 
			
		||||
                }, TransactionMode);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Devices
 | 
			
		||||
    public class DeviceId
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IApplicationPaths _appPaths;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<DeviceId> _logger;
 | 
			
		||||
 | 
			
		||||
        private readonly object _syncLock = new object();
 | 
			
		||||
 | 
			
		||||
@ -90,7 +90,7 @@ namespace Emby.Server.Implementations.Devices
 | 
			
		||||
        public DeviceId(IApplicationPaths appPaths, ILoggerFactory loggerFactory)
 | 
			
		||||
        {
 | 
			
		||||
            _appPaths = appPaths;
 | 
			
		||||
            _logger = loggerFactory.CreateLogger("SystemId");
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<DeviceId>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string Value => _id ?? (_id = GetDeviceId());
 | 
			
		||||
 | 
			
		||||
@ -5,10 +5,11 @@ using System.Collections.Generic;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Jellyfin.Data.Enums;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Common.Extensions;
 | 
			
		||||
using MediaBrowser.Controller.Configuration;
 | 
			
		||||
using MediaBrowser.Controller.Devices;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.Security;
 | 
			
		||||
using MediaBrowser.Model.Devices;
 | 
			
		||||
@ -16,7 +17,6 @@ using MediaBrowser.Model.Events;
 | 
			
		||||
using MediaBrowser.Model.Querying;
 | 
			
		||||
using MediaBrowser.Model.Serialization;
 | 
			
		||||
using MediaBrowser.Model.Session;
 | 
			
		||||
using MediaBrowser.Model.Users;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.Devices
 | 
			
		||||
{
 | 
			
		||||
@ -27,11 +27,10 @@ namespace Emby.Server.Implementations.Devices
 | 
			
		||||
        private readonly IServerConfigurationManager _config;
 | 
			
		||||
        private readonly IAuthenticationRepository _authRepo;
 | 
			
		||||
        private readonly Dictionary<string, ClientCapabilities> _capabilitiesCache;
 | 
			
		||||
        private readonly object _capabilitiesSyncLock = new object();
 | 
			
		||||
 | 
			
		||||
        public event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>> DeviceOptionsUpdated;
 | 
			
		||||
 | 
			
		||||
        private readonly object _capabilitiesSyncLock = new object();
 | 
			
		||||
 | 
			
		||||
        public DeviceManager(
 | 
			
		||||
            IAuthenticationRepository authRepo,
 | 
			
		||||
            IJsonSerializer json,
 | 
			
		||||
@ -175,7 +174,12 @@ namespace Emby.Server.Implementations.Devices
 | 
			
		||||
                throw new ArgumentNullException(nameof(deviceId));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!CanAccessDevice(user.Policy, deviceId))
 | 
			
		||||
            if (user.HasPermission(PermissionKind.EnableAllDevices) || user.HasPermission(PermissionKind.IsAdministrator))
 | 
			
		||||
            {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!user.GetPreference(PreferenceKind.EnabledDevices).Contains(deviceId, StringComparer.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                var capabilities = GetCapabilities(deviceId);
 | 
			
		||||
 | 
			
		||||
@ -187,20 +191,5 @@ namespace Emby.Server.Implementations.Devices
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool CanAccessDevice(UserPolicy policy, string id)
 | 
			
		||||
        {
 | 
			
		||||
            if (policy.EnableAllDevices)
 | 
			
		||||
            {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (policy.IsAdministrator)
 | 
			
		||||
            {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return policy.EnabledDevices.Contains(id, StringComparer.OrdinalIgnoreCase);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -6,14 +6,14 @@ using System.Globalization;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using Jellyfin.Data.Enums;
 | 
			
		||||
using MediaBrowser.Common;
 | 
			
		||||
using MediaBrowser.Controller.Channels;
 | 
			
		||||
using MediaBrowser.Controller.Drawing;
 | 
			
		||||
using MediaBrowser.Controller.Dto;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Audio;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Movies;
 | 
			
		||||
using MediaBrowser.Controller.Entities.TV;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.LiveTv;
 | 
			
		||||
using MediaBrowser.Controller.Persistence;
 | 
			
		||||
@ -24,12 +24,20 @@ using MediaBrowser.Model.Dto;
 | 
			
		||||
using MediaBrowser.Model.Entities;
 | 
			
		||||
using MediaBrowser.Model.Querying;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Book = MediaBrowser.Controller.Entities.Book;
 | 
			
		||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
 | 
			
		||||
using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
 | 
			
		||||
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
 | 
			
		||||
using Person = MediaBrowser.Controller.Entities.Person;
 | 
			
		||||
using Photo = MediaBrowser.Controller.Entities.Photo;
 | 
			
		||||
using Season = MediaBrowser.Controller.Entities.TV.Season;
 | 
			
		||||
using Series = MediaBrowser.Controller.Entities.TV.Series;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.Dto
 | 
			
		||||
{
 | 
			
		||||
    public class DtoService : IDtoService
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<DtoService> _logger;
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
        private readonly IUserDataManager _userDataRepository;
 | 
			
		||||
        private readonly IItemRepository _itemRepo;
 | 
			
		||||
@ -384,7 +392,7 @@ namespace Emby.Server.Implementations.Dto
 | 
			
		||||
 | 
			
		||||
                    if (options.ContainsField(ItemFields.ChildCount))
 | 
			
		||||
                    {
 | 
			
		||||
                        dto.ChildCount = dto.ChildCount ?? GetChildCount(folder, user);
 | 
			
		||||
                        dto.ChildCount ??= GetChildCount(folder, user);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@ -398,7 +406,6 @@ namespace Emby.Server.Implementations.Dto
 | 
			
		||||
                    dto.DateLastMediaAdded = folder.DateLastMediaAdded;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if (options.EnableUserData)
 | 
			
		||||
@ -414,7 +421,7 @@ namespace Emby.Server.Implementations.Dto
 | 
			
		||||
 | 
			
		||||
            if (options.ContainsField(ItemFields.BasicSyncInfo))
 | 
			
		||||
            {
 | 
			
		||||
                var userCanSync = user != null && user.Policy.EnableContentDownloading;
 | 
			
		||||
                var userCanSync = user != null && user.HasPermission(PermissionKind.EnableContentDownloading);
 | 
			
		||||
                if (userCanSync && item.SupportsExternalTransfer)
 | 
			
		||||
                {
 | 
			
		||||
                    dto.SupportsSync = true;
 | 
			
		||||
@ -586,7 +593,6 @@ namespace Emby.Server.Implementations.Dto
 | 
			
		||||
                        _logger.LogError(ex, "Error getting person {Name}", c);
 | 
			
		||||
                        return null;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                }).Where(i => i != null)
 | 
			
		||||
                .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
 | 
			
		||||
                .Select(x => x.First())
 | 
			
		||||
@ -993,7 +999,6 @@ namespace Emby.Server.Implementations.Dto
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        return null;
 | 
			
		||||
 | 
			
		||||
                    }).Where(i => i != null).ToArray();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -1044,7 +1049,6 @@ namespace Emby.Server.Implementations.Dto
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        return null;
 | 
			
		||||
 | 
			
		||||
                    }).Where(i => i != null).ToArray();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -34,13 +34,13 @@
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.4" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.4" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.4" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.4" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.5" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.5" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.5" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.5" />
 | 
			
		||||
    <PackageReference Include="Mono.Nat" Version="2.0.1" />
 | 
			
		||||
    <PackageReference Include="prometheus-net.DotNetRuntime" Version="3.3.1" />
 | 
			
		||||
    <PackageReference Include="ServiceStack.Text.Core" Version="5.8.0" />
 | 
			
		||||
    <PackageReference Include="ServiceStack.Text.Core" Version="5.9.0" />
 | 
			
		||||
    <PackageReference Include="sharpcompress" Version="0.25.0" />
 | 
			
		||||
    <PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.1.0" />
 | 
			
		||||
    <PackageReference Include="DotNet.Glob" Version="3.0.9" />
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@ namespace Emby.Server.Implementations.EntryPoints
 | 
			
		||||
    public class ExternalPortForwarding : IServerEntryPoint
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IServerApplicationHost _appHost;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<ExternalPortForwarding> _logger;
 | 
			
		||||
        private readonly IServerConfigurationManager _config;
 | 
			
		||||
        private readonly IDeviceDiscovery _deviceDiscovery;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ using System.Globalization;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Channels;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Audio;
 | 
			
		||||
@ -28,7 +29,7 @@ namespace Emby.Server.Implementations.EntryPoints
 | 
			
		||||
 | 
			
		||||
        private readonly ISessionManager _sessionManager;
 | 
			
		||||
        private readonly IUserManager _userManager;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<LibraryChangedNotifier> _logger;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The library changed sync lock.
 | 
			
		||||
@ -131,7 +132,6 @@ namespace Emby.Server.Implementations.EntryPoints
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Jellyfin.Data.Enums;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.LiveTv;
 | 
			
		||||
using MediaBrowser.Controller.Plugins;
 | 
			
		||||
@ -17,7 +18,7 @@ namespace Emby.Server.Implementations.EntryPoints
 | 
			
		||||
        private readonly ILiveTvManager _liveTvManager;
 | 
			
		||||
        private readonly ISessionManager _sessionManager;
 | 
			
		||||
        private readonly IUserManager _userManager;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<RecordingNotifier> _logger;
 | 
			
		||||
 | 
			
		||||
        public RecordingNotifier(
 | 
			
		||||
            ISessionManager sessionManager,
 | 
			
		||||
@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.EntryPoints
 | 
			
		||||
 | 
			
		||||
        private async Task SendMessage(string name, TimerEventInfo info)
 | 
			
		||||
        {
 | 
			
		||||
            var users = _userManager.Users.Where(i => i.Policy.EnableLiveTvAccess).Select(i => i.Id).ToList();
 | 
			
		||||
            var users = _userManager.Users.Where(i => i.HasPermission(PermissionKind.EnableLiveTvAccess)).Select(i => i.Id).ToList();
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
@ -1,77 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.Providers;
 | 
			
		||||
using MediaBrowser.Model.IO;
 | 
			
		||||
using MediaBrowser.Model.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.EntryPoints
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Class RefreshUsersMetadata.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class RefreshUsersMetadata : IScheduledTask, IConfigurableScheduledTask
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The user manager.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private readonly IUserManager _userManager;
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Initializes a new instance of the <see cref="RefreshUsersMetadata" /> class.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public RefreshUsersMetadata(IUserManager userManager, IFileSystem fileSystem)
 | 
			
		||||
        {
 | 
			
		||||
            _userManager = userManager;
 | 
			
		||||
            _fileSystem = fileSystem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <inheritdoc />
 | 
			
		||||
        public string Name => "Refresh Users";
 | 
			
		||||
 | 
			
		||||
        /// <inheritdoc />
 | 
			
		||||
        public string Key => "RefreshUsers";
 | 
			
		||||
 | 
			
		||||
        /// <inheritdoc />
 | 
			
		||||
        public string Description => "Refresh user infos";
 | 
			
		||||
 | 
			
		||||
        /// <inheritdoc />
 | 
			
		||||
        public string Category => "Library";
 | 
			
		||||
 | 
			
		||||
        /// <inheritdoc />
 | 
			
		||||
        public bool IsHidden => true;
 | 
			
		||||
 | 
			
		||||
        /// <inheritdoc />
 | 
			
		||||
        public bool IsEnabled => true;
 | 
			
		||||
 | 
			
		||||
        /// <inheritdoc />
 | 
			
		||||
        public bool IsLogged => true;
 | 
			
		||||
 | 
			
		||||
        /// <inheritdoc />
 | 
			
		||||
        public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var user in _userManager.Users)
 | 
			
		||||
            {
 | 
			
		||||
                cancellationToken.ThrowIfCancellationRequested();
 | 
			
		||||
 | 
			
		||||
                await user.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem)), cancellationToken).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <inheritdoc />
 | 
			
		||||
        public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
 | 
			
		||||
        {
 | 
			
		||||
            return new[]
 | 
			
		||||
            {
 | 
			
		||||
                new TaskTriggerInfo
 | 
			
		||||
                {
 | 
			
		||||
                    IntervalTicks = TimeSpan.FromDays(1).Ticks,
 | 
			
		||||
                    Type = TaskTriggerInfo.TriggerInterval
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -3,10 +3,10 @@ using System.Collections.Generic;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Common.Plugins;
 | 
			
		||||
using MediaBrowser.Common.Updates;
 | 
			
		||||
using MediaBrowser.Controller;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.Plugins;
 | 
			
		||||
using MediaBrowser.Controller.Session;
 | 
			
		||||
@ -68,10 +68,8 @@ namespace Emby.Server.Implementations.EntryPoints
 | 
			
		||||
        /// <inheritdoc />
 | 
			
		||||
        public Task RunAsync()
 | 
			
		||||
        {
 | 
			
		||||
            _userManager.UserDeleted += OnUserDeleted;
 | 
			
		||||
            _userManager.UserUpdated += OnUserUpdated;
 | 
			
		||||
            _userManager.UserPolicyUpdated += OnUserPolicyUpdated;
 | 
			
		||||
            _userManager.UserConfigurationUpdated += OnUserConfigurationUpdated;
 | 
			
		||||
            _userManager.OnUserDeleted += OnUserDeleted;
 | 
			
		||||
            _userManager.OnUserUpdated += OnUserUpdated;
 | 
			
		||||
 | 
			
		||||
            _appHost.HasPendingRestartChanged += OnHasPendingRestartChanged;
 | 
			
		||||
 | 
			
		||||
@ -153,20 +151,6 @@ namespace Emby.Server.Implementations.EntryPoints
 | 
			
		||||
            await SendMessageToUserSession(e.Argument, "UserDeleted", e.Argument.Id.ToString("N", CultureInfo.InvariantCulture)).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async void OnUserPolicyUpdated(object sender, GenericEventArgs<User> e)
 | 
			
		||||
        {
 | 
			
		||||
            var dto = _userManager.GetUserDto(e.Argument);
 | 
			
		||||
 | 
			
		||||
            await SendMessageToUserSession(e.Argument, "UserPolicyUpdated", dto).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async void OnUserConfigurationUpdated(object sender, GenericEventArgs<User> e)
 | 
			
		||||
        {
 | 
			
		||||
            var dto = _userManager.GetUserDto(e.Argument);
 | 
			
		||||
 | 
			
		||||
            await SendMessageToUserSession(e.Argument, "UserConfigurationUpdated", dto).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task SendMessageToAdminSessions<T>(string name, T data)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
@ -175,7 +159,6 @@ namespace Emby.Server.Implementations.EntryPoints
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -191,7 +174,6 @@ namespace Emby.Server.Implementations.EntryPoints
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -210,10 +192,8 @@ namespace Emby.Server.Implementations.EntryPoints
 | 
			
		||||
        {
 | 
			
		||||
            if (dispose)
 | 
			
		||||
            {
 | 
			
		||||
                _userManager.UserDeleted -= OnUserDeleted;
 | 
			
		||||
                _userManager.UserUpdated -= OnUserUpdated;
 | 
			
		||||
                _userManager.UserPolicyUpdated -= OnUserPolicyUpdated;
 | 
			
		||||
                _userManager.UserConfigurationUpdated -= OnUserConfigurationUpdated;
 | 
			
		||||
                _userManager.OnUserDeleted -= OnUserDeleted;
 | 
			
		||||
                _userManager.OnUserUpdated -= OnUserUpdated;
 | 
			
		||||
 | 
			
		||||
                _installationManager.PluginUninstalled -= OnPluginUninstalled;
 | 
			
		||||
                _installationManager.PackageInstalling -= OnPackageInstalling;
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.EntryPoints
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The logger.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<UdpServerEntryPoint> _logger;
 | 
			
		||||
        private readonly IServerApplicationHost _appHost;
 | 
			
		||||
        private readonly IConfiguration _config;
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,6 @@ namespace Emby.Server.Implementations.EntryPoints
 | 
			
		||||
            _logger = logger;
 | 
			
		||||
            _appHost = appHost;
 | 
			
		||||
            _config = configuration;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <inheritdoc />
 | 
			
		||||
 | 
			
		||||
@ -22,7 +22,7 @@ namespace Emby.Server.Implementations.HttpClientManager
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class HttpClientManager : IHttpClient
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<HttpClientManager> _logger;
 | 
			
		||||
        private readonly IApplicationPaths _appPaths;
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
        private readonly IApplicationHost _appHost;
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,7 @@ namespace Emby.Server.Implementations.HttpServer
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public const string DefaultRedirectKey = "HttpListenerHost:DefaultRedirectPath";
 | 
			
		||||
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<HttpListenerHost> _logger;
 | 
			
		||||
        private readonly ILoggerFactory _loggerFactory;
 | 
			
		||||
        private readonly IServerConfigurationManager _config;
 | 
			
		||||
        private readonly INetworkManager _networkManager;
 | 
			
		||||
@ -230,7 +230,9 @@ namespace Emby.Server.Implementations.HttpServer
 | 
			
		||||
 | 
			
		||||
            httpRes.StatusCode = statusCode;
 | 
			
		||||
 | 
			
		||||
            var errContent = NormalizeExceptionMessage(ex) ?? string.Empty;
 | 
			
		||||
            var errContent = _hostEnvironment.IsDevelopment()
 | 
			
		||||
                    ? (NormalizeExceptionMessage(ex) ?? string.Empty)
 | 
			
		||||
                    : "Error processing request.";
 | 
			
		||||
            httpRes.ContentType = "text/plain";
 | 
			
		||||
            httpRes.ContentLength = errContent.Length;
 | 
			
		||||
            await httpRes.WriteAsync(errContent).ConfigureAwait(false);
 | 
			
		||||
@ -397,7 +399,7 @@ namespace Emby.Server.Implementations.HttpServer
 | 
			
		||||
            var response = context.Response;
 | 
			
		||||
            var localPath = context.Request.Path.ToString();
 | 
			
		||||
 | 
			
		||||
            var req = new WebSocketSharpRequest(request, response, request.Path, _logger);
 | 
			
		||||
            var req = new WebSocketSharpRequest(request, response, request.Path);
 | 
			
		||||
            return RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, context.RequestAborted);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ namespace Emby.Server.Implementations.HttpServer
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The logger.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<HttpResultFactory> _logger;
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
        private readonly IJsonSerializer _jsonSerializer;
 | 
			
		||||
        private readonly IStreamHelper _streamHelper;
 | 
			
		||||
@ -50,7 +50,7 @@ namespace Emby.Server.Implementations.HttpServer
 | 
			
		||||
            _fileSystem = fileSystem;
 | 
			
		||||
            _jsonSerializer = jsonSerializer;
 | 
			
		||||
            _streamHelper = streamHelper;
 | 
			
		||||
            _logger = loggerfactory.CreateLogger("HttpResultFactory");
 | 
			
		||||
            _logger = loggerfactory.CreateLogger<HttpResultFactory>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@ -580,7 +580,6 @@ namespace Emby.Server.Implementations.HttpServer
 | 
			
		||||
                }
 | 
			
		||||
                catch (NotSupportedException)
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using MediaBrowser.Controller.Net;
 | 
			
		||||
 | 
			
		||||
@ -2,11 +2,12 @@
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Security.Authentication;
 | 
			
		||||
using Emby.Server.Implementations.SocketSharp;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using Jellyfin.Data.Enums;
 | 
			
		||||
using MediaBrowser.Common.Net;
 | 
			
		||||
using MediaBrowser.Controller.Authentication;
 | 
			
		||||
using MediaBrowser.Controller.Configuration;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Net;
 | 
			
		||||
using MediaBrowser.Controller.Security;
 | 
			
		||||
using MediaBrowser.Controller.Session;
 | 
			
		||||
@ -45,7 +46,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
 | 
			
		||||
 | 
			
		||||
        public User Authenticate(HttpRequest request, IAuthenticationAttributes authAttributes)
 | 
			
		||||
        {
 | 
			
		||||
            var req = new WebSocketSharpRequest(request, null, request.Path, _logger);
 | 
			
		||||
            var req = new WebSocketSharpRequest(request, null, request.Path);
 | 
			
		||||
            var user = ValidateUser(req, authAttributes);
 | 
			
		||||
            return user;
 | 
			
		||||
        }
 | 
			
		||||
@ -90,7 +91,8 @@ namespace Emby.Server.Implementations.HttpServer.Security
 | 
			
		||||
                !string.IsNullOrEmpty(auth.Client) &&
 | 
			
		||||
                !string.IsNullOrEmpty(auth.Device))
 | 
			
		||||
            {
 | 
			
		||||
                _sessionManager.LogSessionActivity(auth.Client,
 | 
			
		||||
                _sessionManager.LogSessionActivity(
 | 
			
		||||
                    auth.Client,
 | 
			
		||||
                    auth.Version,
 | 
			
		||||
                    auth.DeviceId,
 | 
			
		||||
                    auth.Device,
 | 
			
		||||
@ -104,21 +106,21 @@ namespace Emby.Server.Implementations.HttpServer.Security
 | 
			
		||||
        private void ValidateUserAccess(
 | 
			
		||||
            User user,
 | 
			
		||||
            IRequest request,
 | 
			
		||||
            IAuthenticationAttributes authAttribtues,
 | 
			
		||||
            IAuthenticationAttributes authAttributes,
 | 
			
		||||
            AuthorizationInfo auth)
 | 
			
		||||
        {
 | 
			
		||||
            if (user.Policy.IsDisabled)
 | 
			
		||||
            if (user.HasPermission(PermissionKind.IsDisabled))
 | 
			
		||||
            {
 | 
			
		||||
                throw new SecurityException("User account has been disabled.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!user.Policy.EnableRemoteAccess && !_networkManager.IsInLocalNetwork(request.RemoteIp))
 | 
			
		||||
            if (!user.HasPermission(PermissionKind.EnableRemoteAccess) && !_networkManager.IsInLocalNetwork(request.RemoteIp))
 | 
			
		||||
            {
 | 
			
		||||
                throw new SecurityException("User account has been disabled.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!user.Policy.IsAdministrator
 | 
			
		||||
                && !authAttribtues.EscapeParentalControl
 | 
			
		||||
            if (!user.HasPermission(PermissionKind.IsAdministrator)
 | 
			
		||||
                && !authAttributes.EscapeParentalControl
 | 
			
		||||
                && !user.IsParentalScheduleAllowed())
 | 
			
		||||
            {
 | 
			
		||||
                request.Response.Headers.Add("X-Application-Error-Code", "ParentalControl");
 | 
			
		||||
@ -180,7 +182,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
 | 
			
		||||
        {
 | 
			
		||||
            if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                if (user == null || !user.Policy.IsAdministrator)
 | 
			
		||||
                if (user == null || !user.HasPermission(PermissionKind.IsAdministrator))
 | 
			
		||||
                {
 | 
			
		||||
                    throw new SecurityException("User does not have admin access.");
 | 
			
		||||
                }
 | 
			
		||||
@ -188,7 +190,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
 | 
			
		||||
 | 
			
		||||
            if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                if (user == null || !user.Policy.EnableContentDeletion)
 | 
			
		||||
                if (user == null || !user.HasPermission(PermissionKind.EnableContentDeletion))
 | 
			
		||||
                {
 | 
			
		||||
                    throw new SecurityException("User does not have delete access.");
 | 
			
		||||
                }
 | 
			
		||||
@ -196,7 +198,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
 | 
			
		||||
 | 
			
		||||
            if (roles.Contains("download", StringComparer.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                if (user == null || !user.Policy.EnableContentDownloading)
 | 
			
		||||
                if (user == null || !user.HasPermission(PermissionKind.EnableContentDownloading))
 | 
			
		||||
                {
 | 
			
		||||
                    throw new SecurityException("User does not have download access.");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@ -116,7 +116,6 @@ namespace Emby.Server.Implementations.HttpServer.Security
 | 
			
		||||
                    {
 | 
			
		||||
                        info.Device = tokenInfo.DeviceName;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    else if (!string.Equals(info.Device, tokenInfo.DeviceName, StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (allowTokenInfoUpdate)
 | 
			
		||||
@ -149,9 +148,9 @@ namespace Emby.Server.Implementations.HttpServer.Security
 | 
			
		||||
                    {
 | 
			
		||||
                        info.User = _userManager.GetUserById(tokenInfo.UserId);
 | 
			
		||||
 | 
			
		||||
                        if (info.User != null && !string.Equals(info.User.Name, tokenInfo.UserName, StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                        if (info.User != null && !string.Equals(info.User.Username, tokenInfo.UserName, StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                        {
 | 
			
		||||
                            tokenInfo.UserName = info.User.Name;
 | 
			
		||||
                            tokenInfo.UserName = info.User.Username;
 | 
			
		||||
                            updateToken = true;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
#pragma warning disable CS1591
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.Net;
 | 
			
		||||
using MediaBrowser.Controller.Security;
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,7 @@ namespace Emby.Server.Implementations.HttpServer
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The logger.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<WebSocketConnection> _logger;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The json serializer options.
 | 
			
		||||
@ -234,8 +234,10 @@ namespace Emby.Server.Implementations.HttpServer
 | 
			
		||||
        private Task SendKeepAliveResponse()
 | 
			
		||||
        {
 | 
			
		||||
            LastKeepAliveDate = DateTime.UtcNow;
 | 
			
		||||
            return SendAsync(new WebSocketMessage<string>
 | 
			
		||||
            return SendAsync(
 | 
			
		||||
                new WebSocketMessage<string>
 | 
			
		||||
                {
 | 
			
		||||
                    MessageId = Guid.NewGuid(),
 | 
			
		||||
                    MessageType = "KeepAlive"
 | 
			
		||||
                }, CancellationToken.None);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,7 @@ namespace Emby.Server.Implementations.IO
 | 
			
		||||
{
 | 
			
		||||
    public class LibraryMonitor : ILibraryMonitor
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<LibraryMonitor> _logger;
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
        private readonly IServerConfigurationManager _configurationManager;
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
@ -266,7 +266,6 @@ namespace Emby.Server.Implementations.IO
 | 
			
		||||
                    {
 | 
			
		||||
                        DisposeWatcher(newWatcher, false);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
@ -393,7 +392,6 @@ namespace Emby.Server.Implementations.IO
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            }))
 | 
			
		||||
            {
 | 
			
		||||
                monitorPath = false;
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,7 @@ namespace Emby.Server.Implementations.IO
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class ManagedFileSystem : IFileSystem
 | 
			
		||||
    {
 | 
			
		||||
        protected ILogger Logger;
 | 
			
		||||
        protected ILogger<ManagedFileSystem> Logger;
 | 
			
		||||
 | 
			
		||||
        private readonly List<IShortcutHandler> _shortcutHandlers = new List<IShortcutHandler>();
 | 
			
		||||
        private readonly string _tempPath;
 | 
			
		||||
 | 
			
		||||
@ -71,7 +71,6 @@ namespace Emby.Server.Implementations.Images
 | 
			
		||||
                    new ValueTuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending)
 | 
			
		||||
                },
 | 
			
		||||
                IncludeItemTypes = includeItemTypes
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -78,7 +78,6 @@ namespace Emby.Server.Implementations.Images
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return i;
 | 
			
		||||
 | 
			
		||||
            }).GroupBy(x => x.Id)
 | 
			
		||||
            .Select(x => x.First());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,8 @@ using Emby.Server.Implementations.Library.Resolvers;
 | 
			
		||||
using Emby.Server.Implementations.Library.Validators;
 | 
			
		||||
using Emby.Server.Implementations.Playlists;
 | 
			
		||||
using Emby.Server.Implementations.ScheduledTasks;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using Jellyfin.Data.Enums;
 | 
			
		||||
using MediaBrowser.Common.Extensions;
 | 
			
		||||
using MediaBrowser.Common.Progress;
 | 
			
		||||
using MediaBrowser.Controller;
 | 
			
		||||
@ -25,7 +27,6 @@ using MediaBrowser.Controller.Drawing;
 | 
			
		||||
using MediaBrowser.Controller.Dto;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Audio;
 | 
			
		||||
using MediaBrowser.Controller.Entities.TV;
 | 
			
		||||
using MediaBrowser.Controller.IO;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.LiveTv;
 | 
			
		||||
@ -46,6 +47,9 @@ using MediaBrowser.Model.Querying;
 | 
			
		||||
using MediaBrowser.Model.Tasks;
 | 
			
		||||
using MediaBrowser.Providers.MediaInfo;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
 | 
			
		||||
using Genre = MediaBrowser.Controller.Entities.Genre;
 | 
			
		||||
using Person = MediaBrowser.Controller.Entities.Person;
 | 
			
		||||
using SortOrder = MediaBrowser.Model.Entities.SortOrder;
 | 
			
		||||
using VideoResolver = Emby.Naming.Video.VideoResolver;
 | 
			
		||||
 | 
			
		||||
@ -56,7 +60,7 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class LibraryManager : ILibraryManager
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<LibraryManager> _logger;
 | 
			
		||||
        private readonly ITaskManager _taskManager;
 | 
			
		||||
        private readonly IUserManager _userManager;
 | 
			
		||||
        private readonly IUserDataManager _userDataRepository;
 | 
			
		||||
@ -510,8 +514,8 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
            return key.GetMD5();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null)
 | 
			
		||||
            => ResolvePath(fileInfo, new DirectoryService(_fileSystem), null, parent);
 | 
			
		||||
        public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null, bool allowIgnorePath = true)
 | 
			
		||||
            => ResolvePath(fileInfo, new DirectoryService(_fileSystem), null, parent, allowIgnorePath: allowIgnorePath);
 | 
			
		||||
 | 
			
		||||
        private BaseItem ResolvePath(
 | 
			
		||||
            FileSystemMetadata fileInfo,
 | 
			
		||||
@ -519,7 +523,8 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
            IItemResolver[] resolvers,
 | 
			
		||||
            Folder parent = null,
 | 
			
		||||
            string collectionType = null,
 | 
			
		||||
            LibraryOptions libraryOptions = null)
 | 
			
		||||
            LibraryOptions libraryOptions = null,
 | 
			
		||||
            bool allowIgnorePath = true)
 | 
			
		||||
        {
 | 
			
		||||
            if (fileInfo == null)
 | 
			
		||||
            {
 | 
			
		||||
@ -543,7 +548,7 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // Return null if ignore rules deem that we should do so
 | 
			
		||||
            if (IgnoreFile(args.FileInfo, args.Parent))
 | 
			
		||||
            if (allowIgnorePath && IgnoreFile(args.FileInfo, args.Parent))
 | 
			
		||||
            {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
@ -707,7 +712,9 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
 | 
			
		||||
            Directory.CreateDirectory(rootFolderPath);
 | 
			
		||||
 | 
			
		||||
            var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath))).DeepCopy<Folder, AggregateFolder>();
 | 
			
		||||
            var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ??
 | 
			
		||||
                             ((Folder) ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath), allowIgnorePath: false))
 | 
			
		||||
                             .DeepCopy<Folder, AggregateFolder>();
 | 
			
		||||
 | 
			
		||||
            // In case program data folder was moved
 | 
			
		||||
            if (!string.Equals(rootFolder.Path, rootFolderPath, StringComparison.Ordinal))
 | 
			
		||||
@ -788,7 +795,7 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                        if (tmpItem == null)
 | 
			
		||||
                        {
 | 
			
		||||
                            _logger.LogDebug("Creating new userRootFolder with DeepCopy");
 | 
			
		||||
                            tmpItem = ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath))).DeepCopy<Folder, UserRootFolder>();
 | 
			
		||||
                            tmpItem = ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath), allowIgnorePath: false)).DeepCopy<Folder, UserRootFolder>();
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        // In case program data folder was moved
 | 
			
		||||
@ -1536,7 +1543,8 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Handle grouping
 | 
			
		||||
                if (user != null && !string.IsNullOrEmpty(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType) && user.Configuration.GroupedFolders.Length > 0)
 | 
			
		||||
                if (user != null && !string.IsNullOrEmpty(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType)
 | 
			
		||||
                    && user.GetPreference(PreferenceKind.GroupedFolders).Length > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    return GetUserRootFolder()
 | 
			
		||||
                        .GetChildren(user, true)
 | 
			
		||||
@ -2853,7 +2861,6 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                    _logger.LogError(ex, "Error getting person");
 | 
			
		||||
                    return null;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            }).Where(i => i != null).ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -148,17 +148,14 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                    {
 | 
			
		||||
                        videoStream.BitRate = 30000000;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    else if (width >= 1900)
 | 
			
		||||
                    {
 | 
			
		||||
                        videoStream.BitRate = 20000000;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    else if (width >= 1200)
 | 
			
		||||
                    {
 | 
			
		||||
                        videoStream.BitRate = 8000000;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    else if (width >= 700)
 | 
			
		||||
                    {
 | 
			
		||||
                        videoStream.BitRate = 2000000;
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,8 @@ using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using Jellyfin.Data.Enums;
 | 
			
		||||
using MediaBrowser.Common.Configuration;
 | 
			
		||||
using MediaBrowser.Common.Extensions;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
@ -14,7 +16,6 @@ using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.MediaEncoding;
 | 
			
		||||
using MediaBrowser.Controller.Persistence;
 | 
			
		||||
using MediaBrowser.Controller.Providers;
 | 
			
		||||
using MediaBrowser.Model.Configuration;
 | 
			
		||||
using MediaBrowser.Model.Dlna;
 | 
			
		||||
using MediaBrowser.Model.Dto;
 | 
			
		||||
using MediaBrowser.Model.Entities;
 | 
			
		||||
@ -33,7 +34,7 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
        private readonly IJsonSerializer _jsonSerializer;
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<MediaSourceManager> _logger;
 | 
			
		||||
        private readonly IUserDataManager _userDataManager;
 | 
			
		||||
        private readonly IMediaEncoder _mediaEncoder;
 | 
			
		||||
        private readonly ILocalizationManager _localizationManager;
 | 
			
		||||
@ -190,10 +191,7 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                {
 | 
			
		||||
                    if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (!user.Policy.EnableAudioPlaybackTranscoding)
 | 
			
		||||
                        {
 | 
			
		||||
                            source.SupportsTranscoding = false;
 | 
			
		||||
                        }
 | 
			
		||||
                        source.SupportsTranscoding = user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@ -352,7 +350,9 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
 | 
			
		||||
        private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
 | 
			
		||||
        {
 | 
			
		||||
            if (userData.SubtitleStreamIndex.HasValue && user.Configuration.RememberSubtitleSelections && user.Configuration.SubtitleMode != SubtitlePlaybackMode.None && allowRememberingSelection)
 | 
			
		||||
            if (userData.SubtitleStreamIndex.HasValue
 | 
			
		||||
                && user.RememberSubtitleSelections
 | 
			
		||||
                && user.SubtitleMode != SubtitlePlaybackMode.None && allowRememberingSelection)
 | 
			
		||||
            {
 | 
			
		||||
                var index = userData.SubtitleStreamIndex.Value;
 | 
			
		||||
                // Make sure the saved index is still valid
 | 
			
		||||
@ -363,26 +363,27 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var preferredSubs = string.IsNullOrEmpty(user.Configuration.SubtitleLanguagePreference)
 | 
			
		||||
                ? Array.Empty<string>() : NormalizeLanguage(user.Configuration.SubtitleLanguagePreference);
 | 
			
		||||
 | 
			
		||||
            var preferredSubs = string.IsNullOrEmpty(user.SubtitleLanguagePreference)
 | 
			
		||||
                ? Array.Empty<string>() : NormalizeLanguage(user.SubtitleLanguagePreference);
 | 
			
		||||
 | 
			
		||||
            var defaultAudioIndex = source.DefaultAudioStreamIndex;
 | 
			
		||||
            var audioLangage = defaultAudioIndex == null
 | 
			
		||||
                ? null
 | 
			
		||||
                : source.MediaStreams.Where(i => i.Type == MediaStreamType.Audio && i.Index == defaultAudioIndex).Select(i => i.Language).FirstOrDefault();
 | 
			
		||||
 | 
			
		||||
            source.DefaultSubtitleStreamIndex = MediaStreamSelector.GetDefaultSubtitleStreamIndex(source.MediaStreams,
 | 
			
		||||
            source.DefaultSubtitleStreamIndex = MediaStreamSelector.GetDefaultSubtitleStreamIndex(
 | 
			
		||||
                source.MediaStreams,
 | 
			
		||||
                preferredSubs,
 | 
			
		||||
                user.Configuration.SubtitleMode,
 | 
			
		||||
                user.SubtitleMode,
 | 
			
		||||
                audioLangage);
 | 
			
		||||
 | 
			
		||||
            MediaStreamSelector.SetSubtitleStreamScores(source.MediaStreams, preferredSubs,
 | 
			
		||||
                user.Configuration.SubtitleMode, audioLangage);
 | 
			
		||||
            MediaStreamSelector.SetSubtitleStreamScores(source.MediaStreams, preferredSubs, user.SubtitleMode, audioLangage);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
 | 
			
		||||
        {
 | 
			
		||||
            if (userData.AudioStreamIndex.HasValue && user.Configuration.RememberAudioSelections && allowRememberingSelection)
 | 
			
		||||
            if (userData.AudioStreamIndex.HasValue && user.RememberAudioSelections && allowRememberingSelection)
 | 
			
		||||
            {
 | 
			
		||||
                var index = userData.AudioStreamIndex.Value;
 | 
			
		||||
                // Make sure the saved index is still valid
 | 
			
		||||
@ -393,11 +394,11 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference)
 | 
			
		||||
            var preferredAudio = string.IsNullOrEmpty(user.AudioLanguagePreference)
 | 
			
		||||
                ? Array.Empty<string>()
 | 
			
		||||
                : NormalizeLanguage(user.Configuration.AudioLanguagePreference);
 | 
			
		||||
                : NormalizeLanguage(user.AudioLanguagePreference);
 | 
			
		||||
 | 
			
		||||
            source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.Configuration.PlayDefaultAudioTrack);
 | 
			
		||||
            source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.PlayDefaultAudioTrack);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetDefaultAudioAndSubtitleStreamIndexes(BaseItem item, MediaSourceInfo source, User user)
 | 
			
		||||
@ -435,7 +436,6 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return 1;
 | 
			
		||||
 | 
			
		||||
            }).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0)
 | 
			
		||||
            .ThenByDescending(i =>
 | 
			
		||||
            {
 | 
			
		||||
@ -534,7 +534,7 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                mediaSource.RunTimeTicks = null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Audio);
 | 
			
		||||
            var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
 | 
			
		||||
 | 
			
		||||
            if (audioStream == null || audioStream.Index == -1)
 | 
			
		||||
            {
 | 
			
		||||
@ -545,7 +545,7 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                mediaSource.DefaultAudioStreamIndex = audioStream.Index;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Video);
 | 
			
		||||
            var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
 | 
			
		||||
            if (videoStream != null)
 | 
			
		||||
            {
 | 
			
		||||
                if (!videoStream.BitRate.HasValue)
 | 
			
		||||
@ -556,17 +556,14 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                    {
 | 
			
		||||
                        videoStream.BitRate = 30000000;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    else if (width >= 1900)
 | 
			
		||||
                    {
 | 
			
		||||
                        videoStream.BitRate = 20000000;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    else if (width >= 1200)
 | 
			
		||||
                    {
 | 
			
		||||
                        videoStream.BitRate = 8000000;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    else if (width >= 700)
 | 
			
		||||
                    {
 | 
			
		||||
                        videoStream.BitRate = 2000000;
 | 
			
		||||
@ -622,7 +619,6 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                    MediaSource = mediaSource,
 | 
			
		||||
                    ExtractChapters = false,
 | 
			
		||||
                    MediaType = DlnaProfileType.Video
 | 
			
		||||
 | 
			
		||||
                }, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                mediaSource.MediaStreams = info.MediaStreams;
 | 
			
		||||
@ -670,13 +666,14 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                    mediaSource.AnalyzeDurationMs = 3000;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                mediaInfo = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
 | 
			
		||||
                mediaInfo = await _mediaEncoder.GetMediaInfo(
 | 
			
		||||
                    new MediaInfoRequest
 | 
			
		||||
                {
 | 
			
		||||
                    MediaSource = mediaSource,
 | 
			
		||||
                    MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
 | 
			
		||||
                    ExtractChapters = false
 | 
			
		||||
 | 
			
		||||
                }, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
                },
 | 
			
		||||
                    cancellationToken).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                if (cacheFilePath != null)
 | 
			
		||||
                {
 | 
			
		||||
@ -749,17 +746,14 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                    {
 | 
			
		||||
                        videoStream.BitRate = 30000000;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    else if (width >= 1900)
 | 
			
		||||
                    {
 | 
			
		||||
                        videoStream.BitRate = 20000000;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    else if (width >= 1200)
 | 
			
		||||
                    {
 | 
			
		||||
                        videoStream.BitRate = 8000000;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    else if (width >= 700)
 | 
			
		||||
                    {
 | 
			
		||||
                        videoStream.BitRate = 2000000;
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using MediaBrowser.Model.Configuration;
 | 
			
		||||
using Jellyfin.Data.Enums;
 | 
			
		||||
using MediaBrowser.Model.Entities;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.Library
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Dto;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Audio;
 | 
			
		||||
@ -10,6 +11,7 @@ using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.Playlists;
 | 
			
		||||
using MediaBrowser.Model.Entities;
 | 
			
		||||
using MediaBrowser.Model.Querying;
 | 
			
		||||
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.Library
 | 
			
		||||
{
 | 
			
		||||
@ -75,7 +77,6 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                {
 | 
			
		||||
                    return Guid.Empty;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            }).Where(i => !i.Equals(Guid.Empty)).ToArray();
 | 
			
		||||
 | 
			
		||||
            return GetInstantMixFromGenreIds(genreIds, user, dtoOptions);
 | 
			
		||||
@ -105,32 +106,27 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
                return GetInstantMixFromGenreIds(new[] { item.Id }, user, dtoOptions);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var playlist = item as Playlist;
 | 
			
		||||
            if (playlist != null)
 | 
			
		||||
            if (item is Playlist playlist)
 | 
			
		||||
            {
 | 
			
		||||
                return GetInstantMixFromPlaylist(playlist, user, dtoOptions);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var album = item as MusicAlbum;
 | 
			
		||||
            if (album != null)
 | 
			
		||||
            if (item is MusicAlbum album)
 | 
			
		||||
            {
 | 
			
		||||
                return GetInstantMixFromAlbum(album, user, dtoOptions);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var artist = item as MusicArtist;
 | 
			
		||||
            if (artist != null)
 | 
			
		||||
            if (item is MusicArtist artist)
 | 
			
		||||
            {
 | 
			
		||||
                return GetInstantMixFromArtist(artist, user, dtoOptions);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var song = item as Audio;
 | 
			
		||||
            if (song != null)
 | 
			
		||||
            if (item is Audio song)
 | 
			
		||||
            {
 | 
			
		||||
                return GetInstantMixFromSong(song, user, dtoOptions);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var folder = item as Folder;
 | 
			
		||||
            if (folder != null)
 | 
			
		||||
            if (item is Folder folder)
 | 
			
		||||
            {
 | 
			
		||||
                return GetInstantMixFromFolder(folder, user, dtoOptions);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -109,7 +109,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
 | 
			
		||||
            IEnumerable<FileSystemMetadata> list,
 | 
			
		||||
            bool allowSubfolders,
 | 
			
		||||
            IDirectoryService directoryService,
 | 
			
		||||
            ILogger logger,
 | 
			
		||||
            ILogger<MusicAlbumResolver> logger,
 | 
			
		||||
            IFileSystem fileSystem,
 | 
			
		||||
            ILibraryManager libraryManager)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
@ -69,7 +69,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrEmpty(id))
 | 
			
		||||
            {
 | 
			
		||||
                item.SetProviderId(MetadataProviders.Tmdb, id);
 | 
			
		||||
                item.SetProviderId(MetadataProvider.Tmdb, id);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -350,7 +350,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
 | 
			
		||||
 | 
			
		||||
                    if (!string.IsNullOrWhiteSpace(tmdbid))
 | 
			
		||||
                    {
 | 
			
		||||
                        item.SetProviderId(MetadataProviders.Tmdb, tmdbid);
 | 
			
		||||
                        item.SetProviderId(MetadataProvider.Tmdb, tmdbid);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@ -361,7 +361,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
 | 
			
		||||
 | 
			
		||||
                    if (!string.IsNullOrWhiteSpace(imdbid))
 | 
			
		||||
                    {
 | 
			
		||||
                        item.SetProviderId(MetadataProviders.Imdb, imdbid);
 | 
			
		||||
                        item.SetProviderId(MetadataProvider.Imdb, imdbid);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -73,7 +73,6 @@ namespace Emby.Server.Implementations.Library.Resolvers
 | 
			
		||||
                    {
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                })
 | 
			
		||||
                .Select(i => _fileSystem.GetFileNameWithoutExtension(i))
 | 
			
		||||
                .FirstOrDefault();
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
 | 
			
		||||
        private readonly IServerConfigurationManager _config;
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
        private readonly ILocalizationManager _localization;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<SeasonResolver> _logger;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Initializes a new instance of the <see cref="SeasonResolver"/> class.
 | 
			
		||||
@ -94,7 +94,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
 | 
			
		||||
                            _localization.GetLocalizedString("NameSeasonNumber"),
 | 
			
		||||
                            seasonNumber,
 | 
			
		||||
                            args.GetLibraryOptions().PreferredMetadataLanguage);
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return season;
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
 | 
			
		||||
    public class SeriesResolver : FolderResolver<Series>
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<SeriesResolver> _logger;
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@ -119,7 +119,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
 | 
			
		||||
            IEnumerable<FileSystemMetadata> fileSystemChildren,
 | 
			
		||||
            IDirectoryService directoryService,
 | 
			
		||||
            IFileSystem fileSystem,
 | 
			
		||||
            ILogger logger,
 | 
			
		||||
            ILogger<SeriesResolver> logger,
 | 
			
		||||
            ILibraryManager libraryManager,
 | 
			
		||||
            bool isTvContentType)
 | 
			
		||||
        {
 | 
			
		||||
@ -217,7 +217,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrEmpty(id))
 | 
			
		||||
            {
 | 
			
		||||
                item.SetProviderId(MetadataProviders.Tvdb, id);
 | 
			
		||||
                item.SetProviderId(MetadataProvider.Tvdb, id);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Dto;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Audio;
 | 
			
		||||
@ -12,12 +13,14 @@ using MediaBrowser.Model.Entities;
 | 
			
		||||
using MediaBrowser.Model.Querying;
 | 
			
		||||
using MediaBrowser.Model.Search;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Genre = MediaBrowser.Controller.Entities.Genre;
 | 
			
		||||
using Person = MediaBrowser.Controller.Entities.Person;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.Library
 | 
			
		||||
{
 | 
			
		||||
    public class SearchEngine : ISearchEngine
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<SearchEngine> _logger;
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
        private readonly IUserManager _userManager;
 | 
			
		||||
 | 
			
		||||
@ -204,7 +207,6 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
            return mediaItems.Select(i => new SearchHintInfo
 | 
			
		||||
            {
 | 
			
		||||
                Item = i
 | 
			
		||||
 | 
			
		||||
            }).ToList();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Configuration;
 | 
			
		||||
using MediaBrowser.Controller.Dto;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
@ -13,6 +14,7 @@ using MediaBrowser.Controller.Persistence;
 | 
			
		||||
using MediaBrowser.Model.Dto;
 | 
			
		||||
using MediaBrowser.Model.Entities;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Book = MediaBrowser.Controller.Entities.Book;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.Library
 | 
			
		||||
{
 | 
			
		||||
@ -26,7 +28,7 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
        private readonly ConcurrentDictionary<string, UserItemData> _userData =
 | 
			
		||||
            new ConcurrentDictionary<string, UserItemData>(StringComparer.OrdinalIgnoreCase);
 | 
			
		||||
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<UserDataManager> _logger;
 | 
			
		||||
        private readonly IServerConfigurationManager _config;
 | 
			
		||||
        private readonly IUserManager _userManager;
 | 
			
		||||
        private readonly IUserDataRepository _repository;
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -5,6 +5,8 @@ using System.Collections.Generic;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using Jellyfin.Data.Enums;
 | 
			
		||||
using MediaBrowser.Controller.Channels;
 | 
			
		||||
using MediaBrowser.Controller.Configuration;
 | 
			
		||||
using MediaBrowser.Controller.Dto;
 | 
			
		||||
@ -17,6 +19,8 @@ using MediaBrowser.Model.Entities;
 | 
			
		||||
using MediaBrowser.Model.Globalization;
 | 
			
		||||
using MediaBrowser.Model.Library;
 | 
			
		||||
using MediaBrowser.Model.Querying;
 | 
			
		||||
using Genre = MediaBrowser.Controller.Entities.Genre;
 | 
			
		||||
using Person = MediaBrowser.Controller.Entities.Person;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.Library
 | 
			
		||||
{
 | 
			
		||||
@ -125,12 +129,12 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
 | 
			
		||||
            if (!query.IncludeHidden)
 | 
			
		||||
            {
 | 
			
		||||
                list = list.Where(i => !user.Configuration.MyMediaExcludes.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture))).ToList();
 | 
			
		||||
                list = list.Where(i => !user.GetPreference(PreferenceKind.MyMediaExcludes).Contains(i.Id.ToString("N", CultureInfo.InvariantCulture))).ToList();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var sorted = _libraryManager.Sort(list, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).ToList();
 | 
			
		||||
 | 
			
		||||
            var orders = user.Configuration.OrderedViews.ToList();
 | 
			
		||||
            var orders = user.GetPreference(PreferenceKind.OrderedViews).ToList();
 | 
			
		||||
 | 
			
		||||
            return list
 | 
			
		||||
                .OrderBy(i =>
 | 
			
		||||
@ -165,7 +169,13 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
            return GetUserSubViewWithName(name, parentId, type, sortName);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Folder GetUserView(List<ICollectionFolder> parents, string viewType, string localizationKey, string sortName, User user, string[] presetViews)
 | 
			
		||||
        private Folder GetUserView(
 | 
			
		||||
            List<ICollectionFolder> parents,
 | 
			
		||||
            string viewType,
 | 
			
		||||
            string localizationKey,
 | 
			
		||||
            string sortName,
 | 
			
		||||
            Jellyfin.Data.Entities.User user,
 | 
			
		||||
            string[] presetViews)
 | 
			
		||||
        {
 | 
			
		||||
            if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase)))
 | 
			
		||||
            {
 | 
			
		||||
@ -270,7 +280,8 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
            {
 | 
			
		||||
                parents = _libraryManager.GetUserRootFolder().GetChildren(user, true)
 | 
			
		||||
                    .Where(i => i is Folder)
 | 
			
		||||
                    .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))
 | 
			
		||||
                    .Where(i => !user.GetPreference(PreferenceKind.LatestItemExcludes)
 | 
			
		||||
                        .Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))
 | 
			
		||||
                    .ToList();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -331,12 +342,11 @@ namespace Emby.Server.Implementations.Library
 | 
			
		||||
 | 
			
		||||
            var excludeItemTypes = includeItemTypes.Length == 0 && mediaTypes.Count == 0 ? new[]
 | 
			
		||||
            {
 | 
			
		||||
                typeof(Person).Name,
 | 
			
		||||
                typeof(Studio).Name,
 | 
			
		||||
                typeof(Year).Name,
 | 
			
		||||
                typeof(MusicGenre).Name,
 | 
			
		||||
                typeof(Genre).Name
 | 
			
		||||
 | 
			
		||||
                nameof(Person),
 | 
			
		||||
                nameof(Studio),
 | 
			
		||||
                nameof(Year),
 | 
			
		||||
                nameof(MusicGenre),
 | 
			
		||||
                nameof(Genre)
 | 
			
		||||
            } : Array.Empty<string>();
 | 
			
		||||
 | 
			
		||||
            var query = new InternalItemsQuery(user)
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// The _library manager.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<ArtistsValidator> _logger;
 | 
			
		||||
        private readonly IItemRepository _itemRepo;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// <param name="itemRepo">The item repository.</param>
 | 
			
		||||
        public ArtistsPostScanTask(
 | 
			
		||||
            ILibraryManager libraryManager,
 | 
			
		||||
            ILogger<ArtistsPostScanTask> logger,
 | 
			
		||||
            ILogger<ArtistsValidator> logger,
 | 
			
		||||
            IItemRepository itemRepo)
 | 
			
		||||
        {
 | 
			
		||||
            _libraryManager = libraryManager;
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The logger.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<ArtistsValidator> _logger;
 | 
			
		||||
        private readonly IItemRepository _itemRepo;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@ -33,7 +33,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// <param name="libraryManager">The library manager.</param>
 | 
			
		||||
        /// <param name="logger">The logger.</param>
 | 
			
		||||
        /// <param name="itemRepo">The item repository.</param>
 | 
			
		||||
        public ArtistsValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
 | 
			
		||||
        public ArtistsValidator(ILibraryManager libraryManager, ILogger<ArtistsValidator> logger, IItemRepository itemRepo)
 | 
			
		||||
        {
 | 
			
		||||
            _libraryManager = libraryManager;
 | 
			
		||||
            _logger = logger;
 | 
			
		||||
@ -98,7 +98,6 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
                _libraryManager.DeleteItem(item, new DeleteOptions
 | 
			
		||||
                {
 | 
			
		||||
                    DeleteFileLocation = false
 | 
			
		||||
 | 
			
		||||
                }, false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// The _library manager.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<GenresValidator> _logger;
 | 
			
		||||
        private readonly IItemRepository _itemRepo;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// <param name="itemRepo">The item repository.</param>
 | 
			
		||||
        public GenresPostScanTask(
 | 
			
		||||
            ILibraryManager libraryManager,
 | 
			
		||||
            ILogger<GenresPostScanTask> logger,
 | 
			
		||||
            ILogger<GenresValidator> logger,
 | 
			
		||||
            IItemRepository itemRepo)
 | 
			
		||||
        {
 | 
			
		||||
            _libraryManager = libraryManager;
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The logger.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<GenresValidator> _logger;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Initializes a new instance of the <see cref="GenresValidator"/> class.
 | 
			
		||||
@ -29,7 +29,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// <param name="libraryManager">The library manager.</param>
 | 
			
		||||
        /// <param name="logger">The logger.</param>
 | 
			
		||||
        /// <param name="itemRepo">The item repository.</param>
 | 
			
		||||
        public GenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
 | 
			
		||||
        public GenresValidator(ILibraryManager libraryManager, ILogger<GenresValidator> logger, IItemRepository itemRepo)
 | 
			
		||||
        {
 | 
			
		||||
            _libraryManager = libraryManager;
 | 
			
		||||
            _logger = logger;
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// The library manager.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<MusicGenresValidator> _logger;
 | 
			
		||||
        private readonly IItemRepository _itemRepo;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// <param name="itemRepo">The item repository.</param>
 | 
			
		||||
        public MusicGenresPostScanTask(
 | 
			
		||||
            ILibraryManager libraryManager,
 | 
			
		||||
            ILogger<MusicGenresPostScanTask> logger,
 | 
			
		||||
            ILogger<MusicGenresValidator> logger,
 | 
			
		||||
            IItemRepository itemRepo)
 | 
			
		||||
        {
 | 
			
		||||
            _libraryManager = libraryManager;
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The logger.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<MusicGenresValidator> _logger;
 | 
			
		||||
        private readonly IItemRepository _itemRepo;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@ -29,7 +29,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// <param name="libraryManager">The library manager.</param>
 | 
			
		||||
        /// <param name="logger">The logger.</param>
 | 
			
		||||
        /// <param name="itemRepo">The item repository.</param>
 | 
			
		||||
        public MusicGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
 | 
			
		||||
        public MusicGenresValidator(ILibraryManager libraryManager, ILogger<MusicGenresValidator> logger, IItemRepository itemRepo)
 | 
			
		||||
        {
 | 
			
		||||
            _libraryManager = libraryManager;
 | 
			
		||||
            _logger = logger;
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<StudiosValidator> _logger;
 | 
			
		||||
        private readonly IItemRepository _itemRepo;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// <param name="itemRepo">The item repository.</param>
 | 
			
		||||
        public StudiosPostScanTask(
 | 
			
		||||
            ILibraryManager libraryManager,
 | 
			
		||||
            ILogger<StudiosPostScanTask> logger,
 | 
			
		||||
            ILogger<StudiosValidator> logger,
 | 
			
		||||
            IItemRepository itemRepo)
 | 
			
		||||
        {
 | 
			
		||||
            _libraryManager = libraryManager;
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The logger.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<StudiosValidator> _logger;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Initializes a new instance of the <see cref="StudiosValidator" /> class.
 | 
			
		||||
@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
        /// <param name="libraryManager">The library manager.</param>
 | 
			
		||||
        /// <param name="logger">The logger.</param>
 | 
			
		||||
        /// <param name="itemRepo">The item repository.</param>
 | 
			
		||||
        public StudiosValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
 | 
			
		||||
        public StudiosValidator(ILibraryManager libraryManager, ILogger<StudiosValidator> logger, IItemRepository itemRepo)
 | 
			
		||||
        {
 | 
			
		||||
            _libraryManager = libraryManager;
 | 
			
		||||
            _logger = logger;
 | 
			
		||||
@ -92,7 +92,6 @@ namespace Emby.Server.Implementations.Library.Validators
 | 
			
		||||
                _libraryManager.DeleteItem(item, new DeleteOptions
 | 
			
		||||
                {
 | 
			
		||||
                    DeleteFileLocation = false
 | 
			
		||||
 | 
			
		||||
                }, false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -46,7 +46,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
 | 
			
		||||
        private const int TunerDiscoveryDurationMs = 3000;
 | 
			
		||||
 | 
			
		||||
        private readonly IServerApplicationHost _appHost;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<EmbyTV> _logger;
 | 
			
		||||
        private readonly IHttpClient _httpClient;
 | 
			
		||||
        private readonly IServerConfigurationManager _config;
 | 
			
		||||
        private readonly IJsonSerializer _jsonSerializer;
 | 
			
		||||
@ -1547,7 +1547,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
 | 
			
		||||
                        IsFolder = false,
 | 
			
		||||
                        Recursive = true,
 | 
			
		||||
                        DtoOptions = new DtoOptions(true)
 | 
			
		||||
 | 
			
		||||
                    })
 | 
			
		||||
                    .Where(i => i.IsFileProtocol && File.Exists(i.Path))
 | 
			
		||||
                    .Skip(seriesTimer.KeepUpTo - 1)
 | 
			
		||||
@ -1893,22 +1892,22 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
 | 
			
		||||
                    writer.WriteStartDocument(true);
 | 
			
		||||
                    writer.WriteStartElement("tvshow");
 | 
			
		||||
                    string id;
 | 
			
		||||
                    if (timer.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out id))
 | 
			
		||||
                    if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Tvdb.ToString(), out id))
 | 
			
		||||
                    {
 | 
			
		||||
                        writer.WriteElementString("id", id);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (timer.SeriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out id))
 | 
			
		||||
                    if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out id))
 | 
			
		||||
                    {
 | 
			
		||||
                        writer.WriteElementString("imdb_id", id);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (timer.SeriesProviderIds.TryGetValue(MetadataProviders.Tmdb.ToString(), out id))
 | 
			
		||||
                    if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out id))
 | 
			
		||||
                    {
 | 
			
		||||
                        writer.WriteElementString("tmdbid", id);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (timer.SeriesProviderIds.TryGetValue(MetadataProviders.Zap2It.ToString(), out id))
 | 
			
		||||
                    if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Zap2It.ToString(), out id))
 | 
			
		||||
                    {
 | 
			
		||||
                        writer.WriteElementString("zap2itid", id);
 | 
			
		||||
                    }
 | 
			
		||||
@ -2075,14 +2074,14 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
 | 
			
		||||
                        writer.WriteElementString("credits", person);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    var tmdbCollection = item.GetProviderId(MetadataProviders.TmdbCollection);
 | 
			
		||||
                    var tmdbCollection = item.GetProviderId(MetadataProvider.TmdbCollection);
 | 
			
		||||
 | 
			
		||||
                    if (!string.IsNullOrEmpty(tmdbCollection))
 | 
			
		||||
                    {
 | 
			
		||||
                        writer.WriteElementString("collectionnumber", tmdbCollection);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    var imdb = item.GetProviderId(MetadataProviders.Imdb);
 | 
			
		||||
                    var imdb = item.GetProviderId(MetadataProvider.Imdb);
 | 
			
		||||
                    if (!string.IsNullOrEmpty(imdb))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (!isSeriesEpisode)
 | 
			
		||||
@ -2096,7 +2095,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
 | 
			
		||||
                        lockData = false;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    var tvdb = item.GetProviderId(MetadataProviders.Tvdb);
 | 
			
		||||
                    var tvdb = item.GetProviderId(MetadataProvider.Tvdb);
 | 
			
		||||
                    if (!string.IsNullOrEmpty(tvdb))
 | 
			
		||||
                    {
 | 
			
		||||
                        writer.WriteElementString("tvdbid", tvdb);
 | 
			
		||||
@ -2105,7 +2104,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
 | 
			
		||||
                        lockData = false;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    var tmdb = item.GetProviderId(MetadataProviders.Tmdb);
 | 
			
		||||
                    var tmdb = item.GetProviderId(MetadataProvider.Tmdb);
 | 
			
		||||
                    if (!string.IsNullOrEmpty(tmdb))
 | 
			
		||||
                    {
 | 
			
		||||
                        writer.WriteElementString("tmdbid", tmdb);
 | 
			
		||||
 | 
			
		||||
@ -56,7 +56,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
 | 
			
		||||
                    name += " " + info.EpisodeTitle;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            else if (info.IsMovie && info.ProductionYear != null)
 | 
			
		||||
            {
 | 
			
		||||
                name += " (" + info.ProductionYear + ")";
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
 | 
			
		||||
{
 | 
			
		||||
    public class SchedulesDirect : IListingsProvider
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<SchedulesDirect> _logger;
 | 
			
		||||
        private readonly IJsonSerializer _jsonSerializer;
 | 
			
		||||
        private readonly IHttpClient _httpClient;
 | 
			
		||||
        private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1);
 | 
			
		||||
@ -342,7 +342,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
 | 
			
		||||
            {
 | 
			
		||||
                info.SeriesId = programId.Substring(0, 10);
 | 
			
		||||
 | 
			
		||||
                info.SeriesProviderIds[MetadataProviders.Zap2It.ToString()] = info.SeriesId;
 | 
			
		||||
                info.SeriesProviderIds[MetadataProvider.Zap2It.ToString()] = info.SeriesId;
 | 
			
		||||
 | 
			
		||||
                if (details.metadata != null)
 | 
			
		||||
                {
 | 
			
		||||
@ -1218,7 +1218,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
 | 
			
		||||
                public string programID { get; set; }
 | 
			
		||||
                public List<ImageData> data { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -26,7 +26,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IServerConfigurationManager _config;
 | 
			
		||||
        private readonly IHttpClient _httpClient;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<XmlTvListingsProvider> _logger;
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
        private readonly IZipClient _zipClient;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -26,7 +26,7 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
 | 
			
		||||
        private const string ServiceName = "Emby";
 | 
			
		||||
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<LiveTvDtoService> _logger;
 | 
			
		||||
        private readonly IImageProcessor _imageProcessor;
 | 
			
		||||
        private readonly IDtoService _dtoService;
 | 
			
		||||
        private readonly IApplicationHost _appHost;
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,8 @@ using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Emby.Server.Implementations.Library;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using Jellyfin.Data.Enums;
 | 
			
		||||
using MediaBrowser.Common.Configuration;
 | 
			
		||||
using MediaBrowser.Common.Extensions;
 | 
			
		||||
using MediaBrowser.Common.Progress;
 | 
			
		||||
@ -14,8 +16,6 @@ using MediaBrowser.Controller.Channels;
 | 
			
		||||
using MediaBrowser.Controller.Configuration;
 | 
			
		||||
using MediaBrowser.Controller.Dto;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Movies;
 | 
			
		||||
using MediaBrowser.Controller.Entities.TV;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.LiveTv;
 | 
			
		||||
using MediaBrowser.Controller.Persistence;
 | 
			
		||||
@ -31,6 +31,8 @@ using MediaBrowser.Model.Querying;
 | 
			
		||||
using MediaBrowser.Model.Serialization;
 | 
			
		||||
using MediaBrowser.Model.Tasks;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
 | 
			
		||||
using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
{
 | 
			
		||||
@ -44,7 +46,7 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
        private const string EtagKey = "ProgramEtag";
 | 
			
		||||
 | 
			
		||||
        private readonly IServerConfigurationManager _config;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<LiveTvManager> _logger;
 | 
			
		||||
        private readonly IItemRepository _itemRepo;
 | 
			
		||||
        private readonly IUserManager _userManager;
 | 
			
		||||
        private readonly IDtoService _dtoService;
 | 
			
		||||
@ -696,7 +698,6 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
                    {
 | 
			
		||||
                        Path = info.ThumbImageUrl,
 | 
			
		||||
                        Type = ImageType.Thumb
 | 
			
		||||
 | 
			
		||||
                    }, 0);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@ -709,7 +710,6 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
                    {
 | 
			
		||||
                        Path = info.LogoImageUrl,
 | 
			
		||||
                        Type = ImageType.Logo
 | 
			
		||||
 | 
			
		||||
                    }, 0);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@ -722,7 +722,6 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
                    {
 | 
			
		||||
                        Path = info.BackdropImageUrl,
 | 
			
		||||
                        Type = ImageType.Backdrop
 | 
			
		||||
 | 
			
		||||
                    }, 0);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@ -760,7 +759,8 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
 | 
			
		||||
            var dto = _dtoService.GetBaseItemDto(program, new DtoOptions(), user);
 | 
			
		||||
 | 
			
		||||
            var list = new List<Tuple<BaseItemDto, string, string>>() {
 | 
			
		||||
            var list = new List<Tuple<BaseItemDto, string, string>>
 | 
			
		||||
            {
 | 
			
		||||
                new Tuple<BaseItemDto, string, string>(dto, program.ExternalId, program.ExternalSeriesId)
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
@ -1168,7 +1168,6 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
                        IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name },
 | 
			
		||||
                        ChannelIds = new Guid[] { currentChannel.Id },
 | 
			
		||||
                        DtoOptions = new DtoOptions(true)
 | 
			
		||||
 | 
			
		||||
                    }).Cast<LiveTvProgram>().ToDictionary(i => i.Id);
 | 
			
		||||
 | 
			
		||||
                    var newPrograms = new List<LiveTvProgram>();
 | 
			
		||||
@ -1738,7 +1737,6 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
            var results = await GetTimers(new TimerQuery
 | 
			
		||||
            {
 | 
			
		||||
                Id = id
 | 
			
		||||
 | 
			
		||||
            }, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
            return results.Items.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
 | 
			
		||||
@ -1790,7 +1788,6 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
                .Select(i =>
 | 
			
		||||
                {
 | 
			
		||||
                    return i.Item1;
 | 
			
		||||
 | 
			
		||||
                })
 | 
			
		||||
                .ToArray();
 | 
			
		||||
 | 
			
		||||
@ -1845,7 +1842,6 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return _tvDtoService.GetSeriesTimerInfoDto(i.Item1, i.Item2, channelName);
 | 
			
		||||
 | 
			
		||||
                })
 | 
			
		||||
                .ToArray();
 | 
			
		||||
 | 
			
		||||
@ -1878,7 +1874,6 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
                OrderBy = new[] { (ItemSortBy.StartDate, SortOrder.Ascending) },
 | 
			
		||||
                TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Id },
 | 
			
		||||
                DtoOptions = options
 | 
			
		||||
 | 
			
		||||
            }) : new List<BaseItem>();
 | 
			
		||||
 | 
			
		||||
            RemoveFields(options);
 | 
			
		||||
@ -2167,20 +2162,19 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
            var info = new LiveTvInfo
 | 
			
		||||
            {
 | 
			
		||||
                Services = services,
 | 
			
		||||
                IsEnabled = services.Length > 0
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            info.EnabledUsers = _userManager.Users
 | 
			
		||||
                IsEnabled = services.Length > 0,
 | 
			
		||||
                EnabledUsers = _userManager.Users
 | 
			
		||||
                    .Where(IsLiveTvEnabled)
 | 
			
		||||
                    .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture))
 | 
			
		||||
                .ToArray();
 | 
			
		||||
                    .ToArray()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            return info;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool IsLiveTvEnabled(User user)
 | 
			
		||||
        {
 | 
			
		||||
            return user.Policy.EnableLiveTvAccess && (Services.Count > 1 || GetConfiguration().TunerHosts.Length > 0);
 | 
			
		||||
            return user.HasPermission(PermissionKind.EnableLiveTvAccess) && (Services.Count > 1 || GetConfiguration().TunerHosts.Length > 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<User> GetEnabledUsers()
 | 
			
		||||
@ -2457,7 +2451,6 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
                UserId = user.Id,
 | 
			
		||||
                IsRecordingsFolder = true,
 | 
			
		||||
                RefreshLatestChannelItems = refreshChannels
 | 
			
		||||
 | 
			
		||||
            }).Items);
 | 
			
		||||
 | 
			
		||||
            return folders.Cast<BaseItem>().ToList();
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@ namespace Emby.Server.Implementations.LiveTv
 | 
			
		||||
        private const string StreamIdDelimeterString = "_";
 | 
			
		||||
 | 
			
		||||
        private readonly ILiveTvManager _liveTvManager;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<LiveTvMediaSourceProvider> _logger;
 | 
			
		||||
        private readonly IMediaSourceManager _mediaSourceManager;
 | 
			
		||||
        private readonly IServerApplicationHost _appHost;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -22,14 +22,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
 | 
			
		||||
    public abstract class BaseTunerHost
 | 
			
		||||
    {
 | 
			
		||||
        protected readonly IServerConfigurationManager Config;
 | 
			
		||||
        protected readonly ILogger Logger;
 | 
			
		||||
        protected readonly ILogger<BaseTunerHost> Logger;
 | 
			
		||||
        protected IJsonSerializer JsonSerializer;
 | 
			
		||||
        protected readonly IFileSystem FileSystem;
 | 
			
		||||
 | 
			
		||||
        private readonly ConcurrentDictionary<string, ChannelCache> _channelCache =
 | 
			
		||||
            new ConcurrentDictionary<string, ChannelCache>(StringComparer.OrdinalIgnoreCase);
 | 
			
		||||
 | 
			
		||||
        protected BaseTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IFileSystem fileSystem)
 | 
			
		||||
        protected BaseTunerHost(IServerConfigurationManager config, ILogger<BaseTunerHost> logger, IJsonSerializer jsonSerializer, IFileSystem fileSystem)
 | 
			
		||||
        {
 | 
			
		||||
            Config = config;
 | 
			
		||||
            Logger = logger;
 | 
			
		||||
@ -99,7 +99,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (IOException)
 | 
			
		||||
                        {
 | 
			
		||||
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@ -116,7 +115,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (IOException)
 | 
			
		||||
                        {
 | 
			
		||||
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@ -111,7 +111,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
 | 
			
		||||
                ChannelType = ChannelType.TV,
 | 
			
		||||
                IsLegacyTuner = (i.URL ?? string.Empty).StartsWith("hdhomerun", StringComparison.OrdinalIgnoreCase),
 | 
			
		||||
                Path = i.URL
 | 
			
		||||
 | 
			
		||||
            }).Cast<ChannelInfo>().ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -481,7 +480,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
 | 
			
		||||
                                Height = height,
 | 
			
		||||
                                BitRate = videoBitrate,
 | 
			
		||||
                                NalLengthSize = nal
 | 
			
		||||
 | 
			
		||||
                            },
 | 
			
		||||
                            new MediaStream
 | 
			
		||||
                            {
 | 
			
		||||
@ -722,7 +720,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                catch (OperationCanceledException)
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
@ -220,11 +220,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
 | 
			
		||||
            }
 | 
			
		||||
            catch (IOException)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            catch (ArgumentException)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
@ -127,7 +127,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
 | 
			
		||||
        {
 | 
			
		||||
            using (var stream = await new M3uParser(Logger, _httpClient, _appHost).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false))
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -210,7 +210,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!IsValidChannelNumber(numberString))
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.Localization
 | 
			
		||||
 | 
			
		||||
        private readonly IServerConfigurationManager _configurationManager;
 | 
			
		||||
        private readonly IJsonSerializer _jsonSerializer;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<LocalizationManager> _logger;
 | 
			
		||||
 | 
			
		||||
        private readonly Dictionary<string, Dictionary<string, ParentalRating>> _allParentalRatings =
 | 
			
		||||
            new Dictionary<string, Dictionary<string, ParentalRating>>(StringComparer.OrdinalIgnoreCase);
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@ namespace Emby.Server.Implementations.MediaEncoder
 | 
			
		||||
    {
 | 
			
		||||
        private readonly CultureInfo _usCulture = new CultureInfo("en-US");
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<EncodingManager> _logger;
 | 
			
		||||
        private readonly IMediaEncoder _encoder;
 | 
			
		||||
        private readonly IChapterManager _chapterManager;
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
 | 
			
		||||
@ -98,7 +98,6 @@ namespace Emby.Server.Implementations.Net
 | 
			
		||||
            }
 | 
			
		||||
            catch (SocketException)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
@ -109,7 +108,6 @@ namespace Emby.Server.Implementations.Net
 | 
			
		||||
            }
 | 
			
		||||
            catch (SocketException)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@ namespace Emby.Server.Implementations.Networking
 | 
			
		||||
{
 | 
			
		||||
    public class NetworkManager : INetworkManager
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<NetworkManager> _logger;
 | 
			
		||||
 | 
			
		||||
        private IPAddress[] _localIpAddresses;
 | 
			
		||||
        private readonly object _localIpAddressSyncLock = new object();
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text.Json.Serialization;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Playlists;
 | 
			
		||||
using MediaBrowser.Model.Querying;
 | 
			
		||||
@ -44,7 +45,7 @@ namespace Emby.Server.Implementations.Playlists
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            query.Recursive = true;
 | 
			
		||||
            query.IncludeItemTypes = new string[] { "Playlist" };
 | 
			
		||||
            query.IncludeItemTypes = new[] { "Playlist" };
 | 
			
		||||
            query.Parent = null;
 | 
			
		||||
            return LibraryManager.GetItemsResult(query);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Jellyfin.Data.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Dto;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Audio;
 | 
			
		||||
@ -21,6 +22,8 @@ using Microsoft.Extensions.Configuration;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using PlaylistsNET.Content;
 | 
			
		||||
using PlaylistsNET.Models;
 | 
			
		||||
using Genre = MediaBrowser.Controller.Entities.Genre;
 | 
			
		||||
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.Playlists
 | 
			
		||||
{
 | 
			
		||||
@ -29,7 +32,7 @@ namespace Emby.Server.Implementations.Playlists
 | 
			
		||||
        private readonly ILibraryManager _libraryManager;
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
        private readonly ILibraryMonitor _iLibraryMonitor;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<PlaylistManager> _logger;
 | 
			
		||||
        private readonly IUserManager _userManager;
 | 
			
		||||
        private readonly IProviderManager _providerManager;
 | 
			
		||||
        private readonly IConfiguration _appConfig;
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ namespace Emby.Server.Implementations
 | 
			
		||||
    public class ResourceFileManager : IResourceFileManager
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<ResourceFileManager> _logger;
 | 
			
		||||
 | 
			
		||||
        public ResourceFileManager(ILogger<ResourceFileManager> logger, IFileSystem fileSystem)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
@ -36,7 +36,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
 | 
			
		||||
 | 
			
		||||
        private readonly IJsonSerializer _jsonSerializer;
 | 
			
		||||
        private readonly IApplicationPaths _applicationPaths;
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<TaskManager> _logger;
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The _logger.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<ChapterImagesTask> _logger;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The _library manager.
 | 
			
		||||
@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
 | 
			
		||||
            IFileSystem fileSystem,
 | 
			
		||||
            ILocalizationManager localization)
 | 
			
		||||
        {
 | 
			
		||||
            _logger = loggerFactory.CreateLogger(GetType().Name);
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<ChapterImagesTask>();
 | 
			
		||||
            _libraryManager = libraryManager;
 | 
			
		||||
            _itemRepo = itemRepo;
 | 
			
		||||
            _appPaths = appPaths;
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
 | 
			
		||||
        /// <value>The application paths.</value>
 | 
			
		||||
        private IApplicationPaths ApplicationPaths { get; set; }
 | 
			
		||||
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
        private readonly ILogger<DeleteCacheFileTask> _logger;
 | 
			
		||||
 | 
			
		||||
        private readonly IFileSystem _fileSystem;
 | 
			
		||||
        private readonly ILocalizationManager _localization;
 | 
			
		||||
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user