Merge remote-tracking branch 'upstream/master' into integration-tests
This commit is contained in:
commit
cd98938190
|
@ -1,13 +1,13 @@
|
|||
parameters:
|
||||
- name: Packages
|
||||
type: object
|
||||
default: {}
|
||||
- name: LinuxImage
|
||||
type: string
|
||||
default: "ubuntu-latest"
|
||||
- name: DotNetSdkVersion
|
||||
type: string
|
||||
default: 3.1.100
|
||||
- name: Packages
|
||||
type: object
|
||||
default: {}
|
||||
- name: LinuxImage
|
||||
type: string
|
||||
default: "ubuntu-latest"
|
||||
- name: DotNetSdkVersion
|
||||
type: string
|
||||
default: 3.1.100
|
||||
|
||||
jobs:
|
||||
- job: CompatibilityCheck
|
||||
|
|
|
@ -20,41 +20,34 @@ jobs:
|
|||
submodules: true
|
||||
persistCredentials: true
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Clone Web Branch"
|
||||
condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
- task: DownloadPipelineArtifact@2
|
||||
displayName: "Download Web Branch"
|
||||
condition: in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion')
|
||||
inputs:
|
||||
script: "git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web"
|
||||
path: '$(Agent.TempDirectory)'
|
||||
artifact: 'jellyfin-web-production'
|
||||
source: 'specific'
|
||||
project: 'jellyfin'
|
||||
pipeline: 'Jellyfin Web'
|
||||
runBranch: variables['Build.SourceBranch']
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Clone Web Target"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest'))
|
||||
- task: DownloadPipelineArtifact@2
|
||||
displayName: "Download Web Target"
|
||||
condition: eq(variables['Build.Reason'], 'PullRequest')
|
||||
inputs:
|
||||
script: "git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web"
|
||||
path: '$(Agent.TempDirectory)'
|
||||
artifact: 'jellyfin-web-production'
|
||||
source: 'specific'
|
||||
project: 'jellyfin'
|
||||
pipeline: 'Jellyfin Web'
|
||||
runBranch: variables['System.PullRequest.TargetBranch']
|
||||
|
||||
- task: NodeTool@0
|
||||
displayName: "Install Node"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
- task: ExtractFiles@1
|
||||
displayName: "Extract Web Client"
|
||||
inputs:
|
||||
versionSpec: "12.x"
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Build Web Client"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
script: yarn install
|
||||
workingDirectory: $(Agent.TempDirectory)/jellyfin-web
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: "Copy Web Client"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist
|
||||
contents: "**"
|
||||
targetFolder: $(Build.SourcesDirectory)/MediaBrowser.WebDashboard/jellyfin-web
|
||||
cleanTargetFolder: true
|
||||
overWrite: true
|
||||
flattenFolders: false
|
||||
archiveFilePatterns: '$(Agent.TempDirectory)/*.zip'
|
||||
destinationFolder: '$(Build.SourcesDirectory)/MediaBrowser.WebDashboard'
|
||||
cleanDestinationFolder: false
|
||||
|
||||
- task: UseDotNet@2
|
||||
displayName: "Update DotNet"
|
||||
|
|
|
@ -1,26 +1,25 @@
|
|||
parameters:
|
||||
- name: ImageNames
|
||||
type: object
|
||||
default:
|
||||
Linux: "ubuntu-latest"
|
||||
Windows: "windows-latest"
|
||||
macOS: "macos-latest"
|
||||
- name: TestProjects
|
||||
type: string
|
||||
default: "tests/**/*Tests.csproj"
|
||||
- name: DotNetSdkVersion
|
||||
type: string
|
||||
default: 3.1.100
|
||||
- name: ImageNames
|
||||
type: object
|
||||
default:
|
||||
Linux: "ubuntu-latest"
|
||||
Windows: "windows-latest"
|
||||
macOS: "macos-latest"
|
||||
- name: TestProjects
|
||||
type: string
|
||||
default: "tests/**/*Tests.csproj"
|
||||
- name: DotNetSdkVersion
|
||||
type: string
|
||||
default: 3.1.100
|
||||
|
||||
jobs:
|
||||
- job: MainTest
|
||||
displayName: Main Test
|
||||
- job: Test
|
||||
displayName: Test
|
||||
strategy:
|
||||
matrix:
|
||||
${{ each imageName in parameters.ImageNames }}:
|
||||
${{ imageName.key }}:
|
||||
ImageName: ${{ imageName.value }}
|
||||
maxParallel: 3
|
||||
pool:
|
||||
vmImage: "$(ImageName)"
|
||||
steps:
|
||||
|
@ -29,14 +28,30 @@ jobs:
|
|||
submodules: true
|
||||
persistCredentials: false
|
||||
|
||||
# This is required for the SonarCloud analyzer
|
||||
- task: UseDotNet@2
|
||||
displayName: "Install .NET Core SDK 2.1"
|
||||
condition: eq(variables['ImageName'], 'ubuntu-latest')
|
||||
inputs:
|
||||
packageType: sdk
|
||||
version: '2.1.805'
|
||||
|
||||
- task: UseDotNet@2
|
||||
displayName: "Update DotNet"
|
||||
inputs:
|
||||
packageType: sdk
|
||||
version: ${{ parameters.DotNetSdkVersion }}
|
||||
|
||||
- task: SonarCloudPrepare@1
|
||||
displayName: 'Prepare analysis on SonarCloud'
|
||||
condition: eq(variables['ImageName'], 'ubuntu-latest')
|
||||
inputs:
|
||||
SonarCloud: 'Sonarcloud for Jellyfin'
|
||||
organization: 'jellyfin'
|
||||
projectKey: 'jellyfin_jellyfin'
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: Run .NET Core CLI tests
|
||||
displayName: 'Run CLI Tests'
|
||||
inputs:
|
||||
command: "test"
|
||||
projects: ${{ parameters.TestProjects }}
|
||||
|
@ -45,9 +60,17 @@ jobs:
|
|||
testRunTitle: $(Agent.JobName)
|
||||
workingDirectory: "$(Build.SourcesDirectory)"
|
||||
|
||||
- task: SonarCloudAnalyze@1
|
||||
displayName: 'Run Code Analysis'
|
||||
condition: eq(variables['ImageName'], 'ubuntu-latest')
|
||||
|
||||
- task: SonarCloudPublish@1
|
||||
displayName: 'Publish Quality Gate Result'
|
||||
condition: eq(variables['ImageName'], 'ubuntu-latest')
|
||||
|
||||
- task: Palmmedia.reportgenerator.reportgenerator-build-release-task.reportgenerator@4
|
||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) # !! THIS is for V1 only V2 will/should support merging
|
||||
displayName: ReportGenerator (merge)
|
||||
displayName: 'Run ReportGenerator'
|
||||
inputs:
|
||||
reports: "$(Agent.TempDirectory)/**/coverage.cobertura.xml"
|
||||
targetdir: "$(Agent.TempDirectory)/merged/"
|
||||
|
@ -56,10 +79,11 @@ jobs:
|
|||
## V2 is already in the repository but it does not work "wrong number of segments" YAML error.
|
||||
- task: PublishCodeCoverageResults@1
|
||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) # !! THIS is for V1 only V2 will/should support merging
|
||||
displayName: Publish Code Coverage
|
||||
displayName: 'Publish Code Coverage'
|
||||
inputs:
|
||||
codeCoverageTool: "cobertura"
|
||||
#summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml' # !!THIS IS FOR V2
|
||||
summaryFileLocation: "$(Agent.TempDirectory)/merged/**.xml"
|
||||
pathToSources: $(Build.SourcesDirectory)
|
||||
failIfCoverageEmpty: true
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
name: $(Date:yyyyMMdd)$(Rev:.r)
|
||||
|
||||
variables:
|
||||
- name: TestProjects
|
||||
value: "tests/**/*Tests.csproj"
|
||||
- name: RestoreBuildProjects
|
||||
value: "Jellyfin.Server/Jellyfin.Server.csproj"
|
||||
- name: DotNetSdkVersion
|
||||
value: 3.1.100
|
||||
- name: TestProjects
|
||||
value: "tests/**/*Tests.csproj"
|
||||
- name: RestoreBuildProjects
|
||||
value: "Jellyfin.Server/Jellyfin.Server.csproj"
|
||||
- name: DotNetSdkVersion
|
||||
value: 3.1.100
|
||||
|
||||
pr:
|
||||
autoCancel: true
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{713F42B5-878E-499D-A878-E4C652B1D5E8}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SharedVersion.cs" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#nullable enable
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{805844AB-E92F-45E6-9D99-4F6D48D129A5}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SharedVersion.cs" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{08FFF49B-F175-4807-A2B5-73B0EBD9F716}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -8,7 +8,6 @@ using MediaBrowser.Common.Extensions;
|
|||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Drawing;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
@ -33,8 +32,7 @@ namespace Emby.Drawing
|
|||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IServerApplicationPaths _appPaths;
|
||||
private readonly IImageEncoder _imageEncoder;
|
||||
private readonly Func<ILibraryManager> _libraryManager;
|
||||
private readonly Func<IMediaEncoder> _mediaEncoder;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
|
||||
private bool _disposed = false;
|
||||
|
||||
|
@ -45,20 +43,17 @@ namespace Emby.Drawing
|
|||
/// <param name="appPaths">The server application paths.</param>
|
||||
/// <param name="fileSystem">The filesystem.</param>
|
||||
/// <param name="imageEncoder">The image encoder.</param>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
/// <param name="mediaEncoder">The media encoder.</param>
|
||||
public ImageProcessor(
|
||||
ILogger<ImageProcessor> logger,
|
||||
IServerApplicationPaths appPaths,
|
||||
IFileSystem fileSystem,
|
||||
IImageEncoder imageEncoder,
|
||||
Func<ILibraryManager> libraryManager,
|
||||
Func<IMediaEncoder> mediaEncoder)
|
||||
IMediaEncoder mediaEncoder)
|
||||
{
|
||||
_logger = logger;
|
||||
_fileSystem = fileSystem;
|
||||
_imageEncoder = imageEncoder;
|
||||
_libraryManager = libraryManager;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_appPaths = appPaths;
|
||||
}
|
||||
|
@ -121,26 +116,9 @@ namespace Emby.Drawing
|
|||
/// <inheritdoc />
|
||||
public async Task<(string path, string mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
var libraryManager = _libraryManager();
|
||||
|
||||
ItemImageInfo originalImage = options.Image;
|
||||
BaseItem item = options.Item;
|
||||
|
||||
if (!originalImage.IsLocalFile)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
item = libraryManager.GetItemById(options.ItemId);
|
||||
}
|
||||
|
||||
originalImage = await libraryManager.ConvertImageToLocal(item, originalImage, options.ImageIndex).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
string originalImagePath = originalImage.Path;
|
||||
DateTime dateModified = originalImage.DateModified;
|
||||
ImageDimensions? originalImageSize = null;
|
||||
|
@ -312,10 +290,6 @@ namespace Emby.Drawing
|
|||
|
||||
/// <inheritdoc />
|
||||
public ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info)
|
||||
=> GetImageDimensions(item, info, true);
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem)
|
||||
{
|
||||
int width = info.Width;
|
||||
int height = info.Height;
|
||||
|
@ -332,11 +306,6 @@ namespace Emby.Drawing
|
|||
info.Width = size.Width;
|
||||
info.Height = size.Height;
|
||||
|
||||
if (updateItem)
|
||||
{
|
||||
_libraryManager().UpdateImages(item);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -351,19 +320,12 @@ namespace Emby.Drawing
|
|||
/// <inheritdoc />
|
||||
public string GetImageCacheTag(BaseItem item, ChapterInfo chapter)
|
||||
{
|
||||
try
|
||||
return GetImageCacheTag(item, new ItemImageInfo
|
||||
{
|
||||
return GetImageCacheTag(item, new ItemImageInfo
|
||||
{
|
||||
Path = chapter.ImagePath,
|
||||
Type = ImageType.Chapter,
|
||||
DateModified = chapter.ImageDateModified
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Path = chapter.ImagePath,
|
||||
Type = ImageType.Chapter,
|
||||
DateModified = chapter.ImageDateModified
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<(string path, DateTime dateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
|
||||
|
@ -384,13 +346,13 @@ namespace Emby.Drawing
|
|||
{
|
||||
string filename = (originalImagePath + dateModified.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("N", CultureInfo.InvariantCulture);
|
||||
|
||||
string cacheExtension = _mediaEncoder().SupportsEncoder("libwebp") ? ".webp" : ".png";
|
||||
string cacheExtension = _mediaEncoder.SupportsEncoder("libwebp") ? ".webp" : ".png";
|
||||
var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + cacheExtension);
|
||||
|
||||
var file = _fileSystem.GetFileInfo(outputPath);
|
||||
if (!file.Exists)
|
||||
{
|
||||
await _mediaEncoder().ConvertImage(originalImagePath, outputPath).ConfigureAwait(false);
|
||||
await _mediaEncoder.ConvertImage(originalImagePath, outputPath).ConfigureAwait(false);
|
||||
dateModified = _fileSystem.GetLastWriteTimeUtc(outputPath);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{2E030C33-6923-4530-9E54-FA29FA6AD1A9}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{89AB4548-770D-41FD-A891-8DAFF44F452C}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||
|
|
|
@ -160,7 +160,7 @@ namespace Emby.Photos
|
|||
|
||||
try
|
||||
{
|
||||
var size = _imageProcessor.GetImageDimensions(item, img, false);
|
||||
var size = _imageProcessor.GetImageDimensions(item, img);
|
||||
|
||||
if (size.Width > 0 && size.Height > 0)
|
||||
{
|
||||
|
|
|
@ -422,7 +422,7 @@ namespace Emby.Server.Implementations.Activity
|
|||
});
|
||||
}
|
||||
|
||||
private void OnPluginUpdated(object sender, GenericEventArgs<(IPlugin, PackageVersionInfo)> e)
|
||||
private void OnPluginUpdated(object sender, GenericEventArgs<(IPlugin, VersionInfo)> e)
|
||||
{
|
||||
CreateLogEntry(new ActivityLogEntry
|
||||
{
|
||||
|
@ -434,8 +434,8 @@ namespace Emby.Server.Implementations.Activity
|
|||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("VersionNumber"),
|
||||
e.Argument.Item2.versionStr),
|
||||
Overview = e.Argument.Item2.description
|
||||
e.Argument.Item2.version),
|
||||
Overview = e.Argument.Item2.changelog
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -451,7 +451,7 @@ namespace Emby.Server.Implementations.Activity
|
|||
});
|
||||
}
|
||||
|
||||
private void OnPluginInstalled(object sender, GenericEventArgs<PackageVersionInfo> e)
|
||||
private void OnPluginInstalled(object sender, GenericEventArgs<VersionInfo> e)
|
||||
{
|
||||
CreateLogEntry(new ActivityLogEntry
|
||||
{
|
||||
|
@ -463,7 +463,7 @@ namespace Emby.Server.Implementations.Activity
|
|||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("VersionNumber"),
|
||||
e.Argument.versionStr)
|
||||
e.Argument.version)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,6 @@ using MediaBrowser.Model.Activity;
|
|||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Cryptography;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
|
@ -104,7 +103,6 @@ using MediaBrowser.WebDashboard.Api;
|
|||
using MediaBrowser.XbmcMetadata.Providers;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
|
||||
|
@ -121,14 +119,20 @@ namespace Emby.Server.Implementations
|
|||
/// </summary>
|
||||
private static readonly string[] _relevantEnvVarPrefixes = { "JELLYFIN_", "DOTNET_", "ASPNETCORE_" };
|
||||
|
||||
private SqliteUserRepository _userRepository;
|
||||
private SqliteDisplayPreferencesRepository _displayPreferencesRepository;
|
||||
private readonly IFileSystem _fileSystemManager;
|
||||
private readonly INetworkManager _networkManager;
|
||||
private readonly IXmlSerializer _xmlSerializer;
|
||||
private readonly IStartupOptions _startupOptions;
|
||||
|
||||
private IMediaEncoder _mediaEncoder;
|
||||
private ISessionManager _sessionManager;
|
||||
private IHttpServer _httpServer;
|
||||
private IHttpClient _httpClient;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance can self restart.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance can self restart; otherwise, <c>false</c>.</value>
|
||||
public abstract bool CanSelfRestart { get; }
|
||||
public bool CanSelfRestart => _startupOptions.RestartPath != null;
|
||||
|
||||
public virtual bool CanLaunchWebBrowser
|
||||
{
|
||||
|
@ -139,7 +143,7 @@ namespace Emby.Server.Implementations
|
|||
return false;
|
||||
}
|
||||
|
||||
if (StartupOptions.IsService)
|
||||
if (_startupOptions.IsService)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -209,21 +213,6 @@ namespace Emby.Server.Implementations
|
|||
/// <value>The configuration manager.</value>
|
||||
protected IConfigurationManager ConfigurationManager { get; set; }
|
||||
|
||||
public IFileSystem FileSystemManager { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public PackageVersionClass SystemUpdateLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
#if BETA
|
||||
return PackageVersionClass.Beta;
|
||||
#else
|
||||
return PackageVersionClass.Release;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the service provider.
|
||||
/// </summary>
|
||||
|
@ -245,110 +234,6 @@ namespace Emby.Server.Implementations
|
|||
/// <value>The server configuration manager.</value>
|
||||
public IServerConfigurationManager ServerConfigurationManager => (IServerConfigurationManager)ConfigurationManager;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user manager.
|
||||
/// </summary>
|
||||
/// <value>The user manager.</value>
|
||||
public IUserManager UserManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the library manager.
|
||||
/// </summary>
|
||||
/// <value>The library manager.</value>
|
||||
internal ILibraryManager LibraryManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the directory watchers.
|
||||
/// </summary>
|
||||
/// <value>The directory watchers.</value>
|
||||
private ILibraryMonitor LibraryMonitor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the provider manager.
|
||||
/// </summary>
|
||||
/// <value>The provider manager.</value>
|
||||
private IProviderManager ProviderManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the HTTP server.
|
||||
/// </summary>
|
||||
/// <value>The HTTP server.</value>
|
||||
private IHttpServer HttpServer { get; set; }
|
||||
|
||||
private IDtoService DtoService { get; set; }
|
||||
|
||||
public IImageProcessor ImageProcessor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the media encoder.
|
||||
/// </summary>
|
||||
/// <value>The media encoder.</value>
|
||||
private IMediaEncoder MediaEncoder { get; set; }
|
||||
|
||||
private ISubtitleEncoder SubtitleEncoder { get; set; }
|
||||
|
||||
private ISessionManager SessionManager { get; set; }
|
||||
|
||||
private ILiveTvManager LiveTvManager { get; set; }
|
||||
|
||||
public LocalizationManager LocalizationManager { get; set; }
|
||||
|
||||
private IEncodingManager EncodingManager { get; set; }
|
||||
|
||||
private IChannelManager ChannelManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user data repository.
|
||||
/// </summary>
|
||||
/// <value>The user data repository.</value>
|
||||
private IUserDataManager UserDataManager { get; set; }
|
||||
|
||||
internal SqliteItemRepository ItemRepository { get; set; }
|
||||
|
||||
private INotificationManager NotificationManager { get; set; }
|
||||
|
||||
private ISubtitleManager SubtitleManager { get; set; }
|
||||
|
||||
private IChapterManager ChapterManager { get; set; }
|
||||
|
||||
private IDeviceManager DeviceManager { get; set; }
|
||||
|
||||
internal IUserViewManager UserViewManager { get; set; }
|
||||
|
||||
private IAuthenticationRepository AuthenticationRepository { get; set; }
|
||||
|
||||
private ITVSeriesManager TVSeriesManager { get; set; }
|
||||
|
||||
private ICollectionManager CollectionManager { get; set; }
|
||||
|
||||
private IMediaSourceManager MediaSourceManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the installation manager.
|
||||
/// </summary>
|
||||
/// <value>The installation manager.</value>
|
||||
protected IInstallationManager InstallationManager { get; private set; }
|
||||
|
||||
protected IAuthService AuthService { get; private set; }
|
||||
|
||||
public IStartupOptions StartupOptions { get; }
|
||||
|
||||
internal IImageEncoder ImageEncoder { get; private set; }
|
||||
|
||||
protected readonly IXmlSerializer XmlSerializer;
|
||||
|
||||
protected ISocketFactory SocketFactory { get; private set; }
|
||||
|
||||
protected ITaskManager TaskManager { get; private set; }
|
||||
|
||||
public IHttpClient HttpClient { get; private set; }
|
||||
|
||||
protected INetworkManager NetworkManager { get; set; }
|
||||
|
||||
public IJsonSerializer JsonSerializer { get; private set; }
|
||||
|
||||
protected IIsoManager IsoManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApplicationHost" /> class.
|
||||
/// </summary>
|
||||
|
@ -357,29 +242,33 @@ namespace Emby.Server.Implementations
|
|||
ILoggerFactory loggerFactory,
|
||||
IStartupOptions options,
|
||||
IFileSystem fileSystem,
|
||||
IImageEncoder imageEncoder,
|
||||
INetworkManager networkManager)
|
||||
{
|
||||
XmlSerializer = new MyXmlSerializer();
|
||||
_xmlSerializer = new MyXmlSerializer();
|
||||
|
||||
NetworkManager = networkManager;
|
||||
_networkManager = networkManager;
|
||||
networkManager.LocalSubnetsFn = GetConfiguredLocalSubnets;
|
||||
|
||||
ApplicationPaths = applicationPaths;
|
||||
LoggerFactory = loggerFactory;
|
||||
FileSystemManager = fileSystem;
|
||||
_fileSystemManager = fileSystem;
|
||||
|
||||
ConfigurationManager = new ServerConfigurationManager(ApplicationPaths, LoggerFactory, XmlSerializer, FileSystemManager);
|
||||
ConfigurationManager = new ServerConfigurationManager(ApplicationPaths, LoggerFactory, _xmlSerializer, _fileSystemManager);
|
||||
|
||||
Logger = LoggerFactory.CreateLogger("App");
|
||||
Logger = LoggerFactory.CreateLogger<ApplicationHost>();
|
||||
|
||||
StartupOptions = options;
|
||||
|
||||
ImageEncoder = imageEncoder;
|
||||
_startupOptions = options;
|
||||
|
||||
fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
|
||||
|
||||
NetworkManager.NetworkChanged += OnNetworkChanged;
|
||||
_networkManager.NetworkChanged += OnNetworkChanged;
|
||||
|
||||
CertificateInfo = new CertificateInfo
|
||||
{
|
||||
Path = ServerConfigurationManager.Configuration.CertificatePath,
|
||||
Password = ServerConfigurationManager.Configuration.CertificatePassword
|
||||
};
|
||||
Certificate = GetCertificate(CertificateInfo);
|
||||
}
|
||||
|
||||
public string ExpandVirtualPath(string path)
|
||||
|
@ -447,10 +336,7 @@ namespace Emby.Server.Implementations
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
/// <inheritdoc/>
|
||||
public string Name => ApplicationProductName;
|
||||
|
||||
/// <summary>
|
||||
|
@ -540,7 +426,7 @@ namespace Emby.Server.Implementations
|
|||
|
||||
ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
|
||||
|
||||
MediaEncoder.SetFFmpegPath();
|
||||
_mediaEncoder.SetFFmpegPath();
|
||||
|
||||
Logger.LogInformation("ServerId: {0}", SystemId);
|
||||
|
||||
|
@ -552,7 +438,7 @@ namespace Emby.Server.Implementations
|
|||
Logger.LogInformation("Executed all pre-startup entry points in {Elapsed:g}", stopWatch.Elapsed);
|
||||
|
||||
Logger.LogInformation("Core startup complete");
|
||||
HttpServer.GlobalResponse = null;
|
||||
_httpServer.GlobalResponse = null;
|
||||
|
||||
stopWatch.Restart();
|
||||
await Task.WhenAll(StartEntryPoints(entryPoints, false)).ConfigureAwait(false);
|
||||
|
@ -576,7 +462,7 @@ namespace Emby.Server.Implementations
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task InitAsync(IServiceCollection serviceCollection, IConfiguration startupConfig)
|
||||
public void Init(IServiceCollection serviceCollection)
|
||||
{
|
||||
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
|
||||
HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
|
||||
|
@ -588,8 +474,6 @@ namespace Emby.Server.Implementations
|
|||
HttpsPort = ServerConfiguration.DefaultHttpsPort;
|
||||
}
|
||||
|
||||
JsonSerializer = new JsonSerializer();
|
||||
|
||||
if (Plugins != null)
|
||||
{
|
||||
var pluginBuilder = new StringBuilder();
|
||||
|
@ -609,7 +493,7 @@ namespace Emby.Server.Implementations
|
|||
|
||||
DiscoverTypes();
|
||||
|
||||
await RegisterServices(serviceCollection, startupConfig).ConfigureAwait(false);
|
||||
RegisterServices(serviceCollection);
|
||||
}
|
||||
|
||||
public async Task ExecuteWebsocketHandlerAsync(HttpContext context, Func<Task> next)
|
||||
|
@ -620,7 +504,7 @@ namespace Emby.Server.Implementations
|
|||
return;
|
||||
}
|
||||
|
||||
await HttpServer.ProcessWebSocketRequest(context).ConfigureAwait(false);
|
||||
await _httpServer.ProcessWebSocketRequest(context).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next)
|
||||
|
@ -636,14 +520,16 @@ namespace Emby.Server.Implementations
|
|||
var localPath = context.Request.Path.ToString();
|
||||
|
||||
var req = new WebSocketSharpRequest(request, response, request.Path, LoggerFactory.CreateLogger<WebSocketSharpRequest>());
|
||||
await HttpServer.RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, context.RequestAborted).ConfigureAwait(false);
|
||||
await _httpServer.RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, context.RequestAborted).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers services/resources with the service collection that will be available via DI.
|
||||
/// </summary>
|
||||
protected async Task RegisterServices(IServiceCollection serviceCollection, IConfiguration startupConfig)
|
||||
protected virtual void RegisterServices(IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddSingleton(_startupOptions);
|
||||
|
||||
serviceCollection.AddMemoryCache();
|
||||
|
||||
serviceCollection.AddSingleton(ConfigurationManager);
|
||||
|
@ -651,240 +537,169 @@ namespace Emby.Server.Implementations
|
|||
|
||||
serviceCollection.AddSingleton<IApplicationPaths>(ApplicationPaths);
|
||||
|
||||
serviceCollection.AddSingleton(JsonSerializer);
|
||||
serviceCollection.AddSingleton<IJsonSerializer, JsonSerializer>();
|
||||
|
||||
// TODO: Support for injecting ILogger should be deprecated in favour of ILogger<T> and this removed
|
||||
serviceCollection.AddSingleton<ILogger>(Logger);
|
||||
// TODO: Remove support for injecting ILogger completely
|
||||
serviceCollection.AddSingleton((provider) =>
|
||||
{
|
||||
Logger.LogWarning("Injecting ILogger directly is deprecated and should be replaced with ILogger<T>");
|
||||
return Logger;
|
||||
});
|
||||
|
||||
serviceCollection.AddSingleton(FileSystemManager);
|
||||
serviceCollection.AddSingleton(_fileSystemManager);
|
||||
serviceCollection.AddSingleton<TvdbClientManager>();
|
||||
|
||||
HttpClient = new HttpClientManager.HttpClientManager(
|
||||
ApplicationPaths,
|
||||
LoggerFactory.CreateLogger<HttpClientManager.HttpClientManager>(),
|
||||
FileSystemManager,
|
||||
() => ApplicationUserAgent);
|
||||
serviceCollection.AddSingleton(HttpClient);
|
||||
serviceCollection.AddSingleton<IHttpClient, HttpClientManager.HttpClientManager>();
|
||||
|
||||
serviceCollection.AddSingleton(NetworkManager);
|
||||
serviceCollection.AddSingleton(_networkManager);
|
||||
|
||||
IsoManager = new IsoManager();
|
||||
serviceCollection.AddSingleton(IsoManager);
|
||||
serviceCollection.AddSingleton<IIsoManager, IsoManager>();
|
||||
|
||||
TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, LoggerFactory, FileSystemManager);
|
||||
serviceCollection.AddSingleton(TaskManager);
|
||||
serviceCollection.AddSingleton<ITaskManager, TaskManager>();
|
||||
|
||||
serviceCollection.AddSingleton(XmlSerializer);
|
||||
serviceCollection.AddSingleton(_xmlSerializer);
|
||||
|
||||
serviceCollection.AddSingleton(typeof(IStreamHelper), typeof(StreamHelper));
|
||||
serviceCollection.AddSingleton<IStreamHelper, StreamHelper>();
|
||||
|
||||
var cryptoProvider = new CryptographyProvider();
|
||||
serviceCollection.AddSingleton<ICryptoProvider>(cryptoProvider);
|
||||
serviceCollection.AddSingleton<ICryptoProvider, CryptographyProvider>();
|
||||
|
||||
SocketFactory = new SocketFactory();
|
||||
serviceCollection.AddSingleton(SocketFactory);
|
||||
serviceCollection.AddSingleton<ISocketFactory, SocketFactory>();
|
||||
|
||||
serviceCollection.AddSingleton(typeof(IInstallationManager), typeof(InstallationManager));
|
||||
serviceCollection.AddSingleton<IInstallationManager, InstallationManager>();
|
||||
|
||||
serviceCollection.AddSingleton(typeof(IZipClient), typeof(ZipClient));
|
||||
serviceCollection.AddSingleton<IZipClient, ZipClient>();
|
||||
|
||||
serviceCollection.AddSingleton(typeof(IHttpResultFactory), typeof(HttpResultFactory));
|
||||
serviceCollection.AddSingleton<IHttpResultFactory, HttpResultFactory>();
|
||||
|
||||
serviceCollection.AddSingleton<IServerApplicationHost>(this);
|
||||
serviceCollection.AddSingleton<IServerApplicationPaths>(ApplicationPaths);
|
||||
|
||||
serviceCollection.AddSingleton(ServerConfigurationManager);
|
||||
|
||||
LocalizationManager = new LocalizationManager(ServerConfigurationManager, JsonSerializer, LoggerFactory.CreateLogger<LocalizationManager>());
|
||||
await LocalizationManager.LoadAll().ConfigureAwait(false);
|
||||
serviceCollection.AddSingleton<ILocalizationManager>(LocalizationManager);
|
||||
serviceCollection.AddSingleton<ILocalizationManager, LocalizationManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IBlurayExaminer>(new BdInfoExaminer(FileSystemManager));
|
||||
serviceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>();
|
||||
|
||||
UserDataManager = new UserDataManager(LoggerFactory, ServerConfigurationManager, () => UserManager);
|
||||
serviceCollection.AddSingleton(UserDataManager);
|
||||
serviceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>();
|
||||
serviceCollection.AddSingleton<IUserDataManager, UserDataManager>();
|
||||
|
||||
_displayPreferencesRepository = new SqliteDisplayPreferencesRepository(
|
||||
LoggerFactory.CreateLogger<SqliteDisplayPreferencesRepository>(),
|
||||
ApplicationPaths,
|
||||
FileSystemManager);
|
||||
serviceCollection.AddSingleton<IDisplayPreferencesRepository>(_displayPreferencesRepository);
|
||||
serviceCollection.AddSingleton<IDisplayPreferencesRepository, SqliteDisplayPreferencesRepository>();
|
||||
|
||||
ItemRepository = new SqliteItemRepository(ServerConfigurationManager, this, LoggerFactory.CreateLogger<SqliteItemRepository>(), LocalizationManager);
|
||||
serviceCollection.AddSingleton<IItemRepository>(ItemRepository);
|
||||
serviceCollection.AddSingleton<IItemRepository, SqliteItemRepository>();
|
||||
|
||||
AuthenticationRepository = GetAuthenticationRepository();
|
||||
serviceCollection.AddSingleton(AuthenticationRepository);
|
||||
serviceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
|
||||
|
||||
_userRepository = GetUserRepository();
|
||||
serviceCollection.AddSingleton<IUserRepository, SqliteUserRepository>();
|
||||
|
||||
UserManager = new UserManager(
|
||||
LoggerFactory.CreateLogger<UserManager>(),
|
||||
_userRepository,
|
||||
XmlSerializer,
|
||||
NetworkManager,
|
||||
() => ImageProcessor,
|
||||
() => DtoService,
|
||||
this,
|
||||
JsonSerializer,
|
||||
FileSystemManager,
|
||||
cryptoProvider);
|
||||
// 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>();
|
||||
|
||||
serviceCollection.AddSingleton(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
|
||||
serviceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>));
|
||||
serviceCollection.AddSingleton<IMediaEncoder>(provider =>
|
||||
ActivatorUtilities.CreateInstance<MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(provider, _startupOptions.FFmpegPath ?? string.Empty));
|
||||
|
||||
MediaEncoder = new MediaBrowser.MediaEncoding.Encoder.MediaEncoder(
|
||||
LoggerFactory.CreateLogger<MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(),
|
||||
ServerConfigurationManager,
|
||||
FileSystemManager,
|
||||
LocalizationManager,
|
||||
() => SubtitleEncoder,
|
||||
startupConfig,
|
||||
StartupOptions.FFmpegPath);
|
||||
serviceCollection.AddSingleton(MediaEncoder);
|
||||
// TODO: Refactor to eliminate the circular dependencies here so that Lazy<T> isn't required
|
||||
serviceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>));
|
||||
serviceCollection.AddTransient(provider => new Lazy<IProviderManager>(provider.GetRequiredService<IProviderManager>));
|
||||
serviceCollection.AddTransient(provider => new Lazy<IUserViewManager>(provider.GetRequiredService<IUserViewManager>));
|
||||
serviceCollection.AddSingleton<ILibraryManager, LibraryManager>();
|
||||
|
||||
LibraryManager = new LibraryManager(this, LoggerFactory, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager, MediaEncoder);
|
||||
serviceCollection.AddSingleton(LibraryManager);
|
||||
serviceCollection.AddSingleton<IMusicManager, MusicManager>();
|
||||
|
||||
var musicManager = new MusicManager(LibraryManager);
|
||||
serviceCollection.AddSingleton<IMusicManager>(musicManager);
|
||||
serviceCollection.AddSingleton<ILibraryMonitor, LibraryMonitor>();
|
||||
|
||||
LibraryMonitor = new LibraryMonitor(LoggerFactory, LibraryManager, ServerConfigurationManager, FileSystemManager);
|
||||
serviceCollection.AddSingleton(LibraryMonitor);
|
||||
|
||||
serviceCollection.AddSingleton<ISearchEngine>(new SearchEngine(LoggerFactory, LibraryManager, UserManager));
|
||||
|
||||
CertificateInfo = GetCertificateInfo(true);
|
||||
Certificate = GetCertificate(CertificateInfo);
|
||||
serviceCollection.AddSingleton<ISearchEngine, SearchEngine>();
|
||||
|
||||
serviceCollection.AddSingleton<ServiceController>();
|
||||
serviceCollection.AddSingleton<IHttpListener, WebSocketSharpListener>();
|
||||
serviceCollection.AddSingleton<IHttpServer, HttpListenerHost>();
|
||||
|
||||
ImageProcessor = new ImageProcessor(LoggerFactory.CreateLogger<ImageProcessor>(), ServerConfigurationManager.ApplicationPaths, FileSystemManager, ImageEncoder, () => LibraryManager, () => MediaEncoder);
|
||||
serviceCollection.AddSingleton(ImageProcessor);
|
||||
serviceCollection.AddSingleton<IImageProcessor, ImageProcessor>();
|
||||
|
||||
TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager, ServerConfigurationManager);
|
||||
serviceCollection.AddSingleton(TVSeriesManager);
|
||||
serviceCollection.AddSingleton<ITVSeriesManager, TVSeriesManager>();
|
||||
|
||||
DeviceManager = new DeviceManager(AuthenticationRepository, JsonSerializer, LibraryManager, LocalizationManager, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager);
|
||||
serviceCollection.AddSingleton(DeviceManager);
|
||||
serviceCollection.AddSingleton<IDeviceManager, DeviceManager>();
|
||||
|
||||
MediaSourceManager = new MediaSourceManager(ItemRepository, ApplicationPaths, LocalizationManager, UserManager, LibraryManager, LoggerFactory, JsonSerializer, FileSystemManager, UserDataManager, () => MediaEncoder);
|
||||
serviceCollection.AddSingleton(MediaSourceManager);
|
||||
serviceCollection.AddSingleton<IMediaSourceManager, MediaSourceManager>();
|
||||
|
||||
SubtitleManager = new SubtitleManager(LoggerFactory, FileSystemManager, LibraryMonitor, MediaSourceManager, LocalizationManager);
|
||||
serviceCollection.AddSingleton(SubtitleManager);
|
||||
serviceCollection.AddSingleton<ISubtitleManager, SubtitleManager>();
|
||||
|
||||
ProviderManager = new ProviderManager(HttpClient, SubtitleManager, ServerConfigurationManager, LibraryMonitor, LoggerFactory, FileSystemManager, ApplicationPaths, () => LibraryManager, JsonSerializer);
|
||||
serviceCollection.AddSingleton(ProviderManager);
|
||||
serviceCollection.AddSingleton<IProviderManager, ProviderManager>();
|
||||
|
||||
DtoService = new DtoService(LoggerFactory, LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ProviderManager, this, () => MediaSourceManager, () => LiveTvManager);
|
||||
serviceCollection.AddSingleton(DtoService);
|
||||
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
|
||||
serviceCollection.AddTransient(provider => new Lazy<ILiveTvManager>(provider.GetRequiredService<ILiveTvManager>));
|
||||
serviceCollection.AddSingleton<IDtoService, DtoService>();
|
||||
|
||||
ChannelManager = new ChannelManager(
|
||||
UserManager,
|
||||
DtoService,
|
||||
LibraryManager,
|
||||
LoggerFactory.CreateLogger<ChannelManager>(),
|
||||
ServerConfigurationManager,
|
||||
FileSystemManager,
|
||||
UserDataManager,
|
||||
JsonSerializer,
|
||||
ProviderManager);
|
||||
serviceCollection.AddSingleton(ChannelManager);
|
||||
serviceCollection.AddSingleton<IChannelManager, ChannelManager>();
|
||||
|
||||
SessionManager = new SessionManager(
|
||||
LoggerFactory.CreateLogger<SessionManager>(),
|
||||
UserDataManager,
|
||||
LibraryManager,
|
||||
UserManager,
|
||||
musicManager,
|
||||
DtoService,
|
||||
ImageProcessor,
|
||||
this,
|
||||
AuthenticationRepository,
|
||||
DeviceManager,
|
||||
MediaSourceManager);
|
||||
serviceCollection.AddSingleton(SessionManager);
|
||||
serviceCollection.AddSingleton<ISessionManager, SessionManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IDlnaManager>(
|
||||
new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LoggerFactory, JsonSerializer, this));
|
||||
serviceCollection.AddSingleton<IDlnaManager, DlnaManager>();
|
||||
|
||||
CollectionManager = new CollectionManager(LibraryManager, ApplicationPaths, LocalizationManager, FileSystemManager, LibraryMonitor, LoggerFactory, ProviderManager);
|
||||
serviceCollection.AddSingleton(CollectionManager);
|
||||
serviceCollection.AddSingleton<ICollectionManager, CollectionManager>();
|
||||
|
||||
serviceCollection.AddSingleton(typeof(IPlaylistManager), typeof(PlaylistManager));
|
||||
serviceCollection.AddSingleton<IPlaylistManager, PlaylistManager>();
|
||||
|
||||
LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, LoggerFactory, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, FileSystemManager, () => ChannelManager);
|
||||
serviceCollection.AddSingleton(LiveTvManager);
|
||||
serviceCollection.AddSingleton<LiveTvDtoService>();
|
||||
serviceCollection.AddSingleton<ILiveTvManager, LiveTvManager>();
|
||||
|
||||
UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
|
||||
serviceCollection.AddSingleton(UserViewManager);
|
||||
serviceCollection.AddSingleton<IUserViewManager, UserViewManager>();
|
||||
|
||||
NotificationManager = new NotificationManager(
|
||||
LoggerFactory.CreateLogger<NotificationManager>(),
|
||||
UserManager,
|
||||
ServerConfigurationManager);
|
||||
serviceCollection.AddSingleton(NotificationManager);
|
||||
serviceCollection.AddSingleton<INotificationManager, NotificationManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IDeviceDiscovery>(new DeviceDiscovery(ServerConfigurationManager));
|
||||
serviceCollection.AddSingleton<IDeviceDiscovery, DeviceDiscovery>();
|
||||
|
||||
ChapterManager = new ChapterManager(ItemRepository);
|
||||
serviceCollection.AddSingleton(ChapterManager);
|
||||
serviceCollection.AddSingleton<IChapterManager, ChapterManager>();
|
||||
|
||||
EncodingManager = new MediaEncoder.EncodingManager(
|
||||
LoggerFactory.CreateLogger<MediaEncoder.EncodingManager>(),
|
||||
FileSystemManager,
|
||||
MediaEncoder,
|
||||
ChapterManager,
|
||||
LibraryManager);
|
||||
serviceCollection.AddSingleton(EncodingManager);
|
||||
serviceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
|
||||
|
||||
var activityLogRepo = GetActivityLogRepository();
|
||||
serviceCollection.AddSingleton(activityLogRepo);
|
||||
serviceCollection.AddSingleton<IActivityManager>(new ActivityManager(activityLogRepo, UserManager));
|
||||
serviceCollection.AddSingleton<IActivityRepository, ActivityRepository>();
|
||||
serviceCollection.AddSingleton<IActivityManager, ActivityManager>();
|
||||
|
||||
var authContext = new AuthorizationContext(AuthenticationRepository, UserManager);
|
||||
serviceCollection.AddSingleton<IAuthorizationContext>(authContext);
|
||||
serviceCollection.AddSingleton<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
|
||||
serviceCollection.AddSingleton<IAuthorizationContext, AuthorizationContext>();
|
||||
serviceCollection.AddSingleton<ISessionContext, SessionContext>();
|
||||
|
||||
AuthService = new AuthService(LoggerFactory.CreateLogger<AuthService>(), authContext, ServerConfigurationManager, SessionManager, NetworkManager);
|
||||
serviceCollection.AddSingleton(AuthService);
|
||||
serviceCollection.AddSingleton<IAuthService, AuthService>();
|
||||
|
||||
SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(
|
||||
LibraryManager,
|
||||
LoggerFactory.CreateLogger<MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>(),
|
||||
ApplicationPaths,
|
||||
FileSystemManager,
|
||||
MediaEncoder,
|
||||
HttpClient,
|
||||
MediaSourceManager);
|
||||
serviceCollection.AddSingleton(SubtitleEncoder);
|
||||
serviceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>();
|
||||
|
||||
serviceCollection.AddSingleton(typeof(IResourceFileManager), typeof(ResourceFileManager));
|
||||
serviceCollection.AddSingleton<IResourceFileManager, ResourceFileManager>();
|
||||
serviceCollection.AddSingleton<EncodingHelper>();
|
||||
|
||||
serviceCollection.AddSingleton(typeof(IAttachmentExtractor), typeof(MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor));
|
||||
|
||||
_displayPreferencesRepository.Initialize();
|
||||
|
||||
var userDataRepo = new SqliteUserDataRepository(LoggerFactory.CreateLogger<SqliteUserDataRepository>(), ApplicationPaths);
|
||||
|
||||
SetStaticProperties();
|
||||
|
||||
((UserManager)UserManager).Initialize();
|
||||
|
||||
((UserDataManager)UserDataManager).Repository = userDataRepo;
|
||||
ItemRepository.Initialize(userDataRepo, UserManager);
|
||||
((LibraryManager)LibraryManager).ItemRepository = ItemRepository;
|
||||
serviceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create services registered with the service container that need to be initialized at application startup.
|
||||
/// </summary>
|
||||
public void InitializeServices()
|
||||
/// <returns>A task representing the service initialization operation.</returns>
|
||||
public async Task InitializeServices()
|
||||
{
|
||||
HttpServer = Resolve<IHttpServer>();
|
||||
var localizationManager = (LocalizationManager)Resolve<ILocalizationManager>();
|
||||
await localizationManager.LoadAll().ConfigureAwait(false);
|
||||
|
||||
_mediaEncoder = Resolve<IMediaEncoder>();
|
||||
_sessionManager = Resolve<ISessionManager>();
|
||||
_httpServer = Resolve<IHttpServer>();
|
||||
_httpClient = Resolve<IHttpClient>();
|
||||
|
||||
((SqliteDisplayPreferencesRepository)Resolve<IDisplayPreferencesRepository>()).Initialize();
|
||||
((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
|
||||
((SqliteUserRepository)Resolve<IUserRepository>()).Initialize();
|
||||
((ActivityRepository)Resolve<IActivityRepository>()).Initialize();
|
||||
|
||||
SetStaticProperties();
|
||||
|
||||
var userManager = (UserManager)Resolve<IUserManager>();
|
||||
userManager.Initialize();
|
||||
|
||||
var userDataRepo = (SqliteUserDataRepository)Resolve<IUserDataRepository>();
|
||||
((SqliteItemRepository)Resolve<IItemRepository>()).Initialize(userDataRepo, userManager);
|
||||
|
||||
FindParts();
|
||||
}
|
||||
|
||||
public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths)
|
||||
|
@ -953,75 +768,38 @@ namespace Emby.Server.Implementations
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user repository.
|
||||
/// </summary>
|
||||
/// <returns><see cref="Task{SqliteUserRepository}" />.</returns>
|
||||
private SqliteUserRepository GetUserRepository()
|
||||
{
|
||||
var repo = new SqliteUserRepository(
|
||||
LoggerFactory.CreateLogger<SqliteUserRepository>(),
|
||||
ApplicationPaths);
|
||||
|
||||
repo.Initialize();
|
||||
|
||||
return repo;
|
||||
}
|
||||
|
||||
private IAuthenticationRepository GetAuthenticationRepository()
|
||||
{
|
||||
var repo = new AuthenticationRepository(LoggerFactory, ServerConfigurationManager);
|
||||
|
||||
repo.Initialize();
|
||||
|
||||
return repo;
|
||||
}
|
||||
|
||||
private IActivityRepository GetActivityLogRepository()
|
||||
{
|
||||
var repo = new ActivityRepository(LoggerFactory.CreateLogger<ActivityRepository>(), ServerConfigurationManager.ApplicationPaths, FileSystemManager);
|
||||
|
||||
repo.Initialize();
|
||||
|
||||
return repo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dirty hacks.
|
||||
/// </summary>
|
||||
private void SetStaticProperties()
|
||||
{
|
||||
ItemRepository.ImageProcessor = ImageProcessor;
|
||||
|
||||
// For now there's no real way to inject these properly
|
||||
BaseItem.Logger = LoggerFactory.CreateLogger("BaseItem");
|
||||
BaseItem.Logger = Resolve<ILogger<BaseItem>>();
|
||||
BaseItem.ConfigurationManager = ServerConfigurationManager;
|
||||
BaseItem.LibraryManager = LibraryManager;
|
||||
BaseItem.ProviderManager = ProviderManager;
|
||||
BaseItem.LocalizationManager = LocalizationManager;
|
||||
BaseItem.ItemRepository = ItemRepository;
|
||||
User.UserManager = UserManager;
|
||||
BaseItem.FileSystem = FileSystemManager;
|
||||
BaseItem.UserDataManager = UserDataManager;
|
||||
BaseItem.ChannelManager = ChannelManager;
|
||||
Video.LiveTvManager = LiveTvManager;
|
||||
Folder.UserViewManager = UserViewManager;
|
||||
UserView.TVSeriesManager = TVSeriesManager;
|
||||
UserView.CollectionManager = CollectionManager;
|
||||
BaseItem.MediaSourceManager = MediaSourceManager;
|
||||
CollectionFolder.XmlSerializer = XmlSerializer;
|
||||
CollectionFolder.JsonSerializer = JsonSerializer;
|
||||
BaseItem.LibraryManager = Resolve<ILibraryManager>();
|
||||
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>();
|
||||
Video.LiveTvManager = Resolve<ILiveTvManager>();
|
||||
Folder.UserViewManager = Resolve<IUserViewManager>();
|
||||
UserView.TVSeriesManager = Resolve<ITVSeriesManager>();
|
||||
UserView.CollectionManager = Resolve<ICollectionManager>();
|
||||
BaseItem.MediaSourceManager = Resolve<IMediaSourceManager>();
|
||||
CollectionFolder.XmlSerializer = _xmlSerializer;
|
||||
CollectionFolder.JsonSerializer = Resolve<IJsonSerializer>();
|
||||
CollectionFolder.ApplicationHost = this;
|
||||
AuthenticatedAttribute.AuthService = AuthService;
|
||||
AuthenticatedAttribute.AuthService = Resolve<IAuthService>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the parts.
|
||||
/// Finds plugin components and register them with the appropriate services.
|
||||
/// </summary>
|
||||
public void FindParts()
|
||||
private void FindParts()
|
||||
{
|
||||
InstallationManager = ServiceProvider.GetService<IInstallationManager>();
|
||||
|
||||
if (!ServerConfigurationManager.Configuration.IsPortAuthorized)
|
||||
{
|
||||
ServerConfigurationManager.Configuration.IsPortAuthorized = true;
|
||||
|
@ -1034,34 +812,34 @@ namespace Emby.Server.Implementations
|
|||
.Where(i => i != null)
|
||||
.ToArray();
|
||||
|
||||
HttpServer.Init(GetExportTypes<IService>(), GetExports<IWebSocketListener>(), GetUrlPrefixes());
|
||||
_httpServer.Init(GetExportTypes<IService>(), GetExports<IWebSocketListener>(), GetUrlPrefixes());
|
||||
|
||||
LibraryManager.AddParts(
|
||||
Resolve<ILibraryManager>().AddParts(
|
||||
GetExports<IResolverIgnoreRule>(),
|
||||
GetExports<IItemResolver>(),
|
||||
GetExports<IIntroProvider>(),
|
||||
GetExports<IBaseItemComparer>(),
|
||||
GetExports<ILibraryPostScanTask>());
|
||||
|
||||
ProviderManager.AddParts(
|
||||
Resolve<IProviderManager>().AddParts(
|
||||
GetExports<IImageProvider>(),
|
||||
GetExports<IMetadataService>(),
|
||||
GetExports<IMetadataProvider>(),
|
||||
GetExports<IMetadataSaver>(),
|
||||
GetExports<IExternalId>());
|
||||
|
||||
LiveTvManager.AddParts(GetExports<ILiveTvService>(), GetExports<ITunerHost>(), GetExports<IListingsProvider>());
|
||||
Resolve<ILiveTvManager>().AddParts(GetExports<ILiveTvService>(), GetExports<ITunerHost>(), GetExports<IListingsProvider>());
|
||||
|
||||
SubtitleManager.AddParts(GetExports<ISubtitleProvider>());
|
||||
Resolve<ISubtitleManager>().AddParts(GetExports<ISubtitleProvider>());
|
||||
|
||||
ChannelManager.AddParts(GetExports<IChannel>());
|
||||
Resolve<IChannelManager>().AddParts(GetExports<IChannel>());
|
||||
|
||||
MediaSourceManager.AddParts(GetExports<IMediaSourceProvider>());
|
||||
Resolve<IMediaSourceManager>().AddParts(GetExports<IMediaSourceProvider>());
|
||||
|
||||
NotificationManager.AddParts(GetExports<INotificationService>(), GetExports<INotificationTypeFactory>());
|
||||
UserManager.AddParts(GetExports<IAuthenticationProvider>(), GetExports<IPasswordResetProvider>());
|
||||
Resolve<INotificationManager>().AddParts(GetExports<INotificationService>(), GetExports<INotificationTypeFactory>());
|
||||
Resolve<IUserManager>().AddParts(GetExports<IAuthenticationProvider>(), GetExports<IPasswordResetProvider>());
|
||||
|
||||
IsoManager.AddParts(GetExports<IIsoMounter>());
|
||||
Resolve<IIsoManager>().AddParts(GetExports<IIsoMounter>());
|
||||
}
|
||||
|
||||
private IPlugin LoadPlugin(IPlugin plugin)
|
||||
|
@ -1168,16 +946,6 @@ namespace Emby.Server.Implementations
|
|||
});
|
||||
}
|
||||
|
||||
private CertificateInfo GetCertificateInfo(bool generateCertificate)
|
||||
{
|
||||
// Custom cert
|
||||
return new CertificateInfo
|
||||
{
|
||||
Path = ServerConfigurationManager.Configuration.CertificatePath,
|
||||
Password = ServerConfigurationManager.Configuration.CertificatePassword
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when [configuration updated].
|
||||
/// </summary>
|
||||
|
@ -1204,14 +972,13 @@ namespace Emby.Server.Implementations
|
|||
}
|
||||
}
|
||||
|
||||
if (!HttpServer.UrlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase))
|
||||
if (!_httpServer.UrlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
requiresRestart = true;
|
||||
}
|
||||
|
||||
var currentCertPath = CertificateInfo?.Path;
|
||||
var newCertInfo = GetCertificateInfo(false);
|
||||
var newCertPath = newCertInfo?.Path;
|
||||
var newCertPath = ServerConfigurationManager.Configuration.CertificatePath;
|
||||
|
||||
if (!string.Equals(currentCertPath, newCertPath, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
@ -1264,7 +1031,7 @@ namespace Emby.Server.Implementations
|
|||
{
|
||||
try
|
||||
{
|
||||
await SessionManager.SendServerRestartNotification(CancellationToken.None).ConfigureAwait(false);
|
||||
await _sessionManager.SendServerRestartNotification(CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -1368,7 +1135,7 @@ namespace Emby.Server.Implementations
|
|||
IsShuttingDown = IsShuttingDown,
|
||||
Version = ApplicationVersionString,
|
||||
WebSocketPortNumber = HttpPort,
|
||||
CompletedInstallations = InstallationManager.CompletedInstallations.ToArray(),
|
||||
CompletedInstallations = Resolve<IInstallationManager>().CompletedInstallations.ToArray(),
|
||||
Id = SystemId,
|
||||
ProgramDataPath = ApplicationPaths.ProgramDataPath,
|
||||
WebPath = ApplicationPaths.WebPath,
|
||||
|
@ -1388,15 +1155,14 @@ namespace Emby.Server.Implementations
|
|||
ServerName = FriendlyName,
|
||||
LocalAddress = localAddress,
|
||||
SupportsLibraryMonitor = true,
|
||||
EncoderLocation = MediaEncoder.EncoderLocation,
|
||||
EncoderLocation = _mediaEncoder.EncoderLocation,
|
||||
SystemArchitecture = RuntimeInformation.OSArchitecture,
|
||||
SystemUpdateLevel = SystemUpdateLevel,
|
||||
PackageName = StartupOptions.PackageName
|
||||
PackageName = _startupOptions.PackageName
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<WakeOnLanInfo> GetWakeOnLanInfo()
|
||||
=> NetworkManager.GetMacAddresses()
|
||||
=> _networkManager.GetMacAddresses()
|
||||
.Select(i => new WakeOnLanInfo(i))
|
||||
.ToList();
|
||||
|
||||
|
@ -1508,7 +1274,7 @@ namespace Emby.Server.Implementations
|
|||
|
||||
if (addresses.Count == 0)
|
||||
{
|
||||
addresses.AddRange(NetworkManager.GetLocalIpAddresses(ServerConfigurationManager.Configuration.IgnoreVirtualInterfaces));
|
||||
addresses.AddRange(_networkManager.GetLocalIpAddresses(ServerConfigurationManager.Configuration.IgnoreVirtualInterfaces));
|
||||
}
|
||||
|
||||
var resultList = new List<IPAddress>();
|
||||
|
@ -1575,7 +1341,7 @@ namespace Emby.Server.Implementations
|
|||
|
||||
try
|
||||
{
|
||||
using (var response = await HttpClient.SendAsync(
|
||||
using (var response = await _httpClient.SendAsync(
|
||||
new HttpRequestOptions
|
||||
{
|
||||
Url = apiUrl,
|
||||
|
@ -1628,7 +1394,7 @@ namespace Emby.Server.Implementations
|
|||
|
||||
try
|
||||
{
|
||||
await SessionManager.SendServerShutdownNotification(CancellationToken.None).ConfigureAwait(false);
|
||||
await _sessionManager.SendServerShutdownNotification(CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -1749,14 +1515,8 @@ namespace Emby.Server.Implementations
|
|||
Logger.LogError(ex, "Error disposing {Type}", part.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
_userRepository?.Dispose();
|
||||
_displayPreferencesRepository?.Dispose();
|
||||
}
|
||||
|
||||
_userRepository = null;
|
||||
_displayPreferencesRepository = null;
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace Emby.Server.Implementations
|
|||
{
|
||||
{ HostWebClientKey, bool.TrueString },
|
||||
{ HttpListenerHost.DefaultRedirectKey, "web/index.html" },
|
||||
{ InstallationManager.PluginManifestUrlKey, "https://repo.jellyfin.org/releases/plugin/manifest.json" },
|
||||
{ InstallationManager.PluginManifestUrlKey, "https://repo.jellyfin.org/releases/plugin/manifest-stable.json" },
|
||||
{ FfmpegProbeSizeKey, "1G" },
|
||||
{ FfmpegAnalyzeDurationKey, "200M" },
|
||||
{ PlaylistsAllowDuplicatesKey, bool.TrueString }
|
||||
|
|
|
@ -39,12 +39,11 @@ namespace Emby.Server.Implementations.Data
|
|||
{
|
||||
private const string ChaptersTableName = "Chapters2";
|
||||
|
||||
/// <summary>
|
||||
/// The _app paths
|
||||
/// </summary>
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IServerApplicationHost _appHost;
|
||||
private readonly ILocalizationManager _localization;
|
||||
// TODO: Remove this dependency. GetImageCacheTag() is the only method used and it can be converted to a static helper method
|
||||
private readonly IImageProcessor _imageProcessor;
|
||||
|
||||
private readonly TypeMapper _typeMapper;
|
||||
private readonly JsonSerializerOptions _jsonOptions;
|
||||
|
@ -71,7 +70,8 @@ namespace Emby.Server.Implementations.Data
|
|||
IServerConfigurationManager config,
|
||||
IServerApplicationHost appHost,
|
||||
ILogger<SqliteItemRepository> logger,
|
||||
ILocalizationManager localization)
|
||||
ILocalizationManager localization,
|
||||
IImageProcessor imageProcessor)
|
||||
: base(logger)
|
||||
{
|
||||
if (config == null)
|
||||
|
@ -82,6 +82,7 @@ namespace Emby.Server.Implementations.Data
|
|||
_config = config;
|
||||
_appHost = appHost;
|
||||
_localization = localization;
|
||||
_imageProcessor = imageProcessor;
|
||||
|
||||
_typeMapper = new TypeMapper();
|
||||
_jsonOptions = JsonDefaults.GetOptions();
|
||||
|
@ -98,8 +99,6 @@ namespace Emby.Server.Implementations.Data
|
|||
/// <inheritdoc />
|
||||
protected override TempStoreMode TempStore => TempStoreMode.Memory;
|
||||
|
||||
public IImageProcessor ImageProcessor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Opens the connection to the database
|
||||
/// </summary>
|
||||
|
@ -1991,7 +1990,14 @@ namespace Emby.Server.Implementations.Data
|
|||
|
||||
if (!string.IsNullOrEmpty(chapter.ImagePath))
|
||||
{
|
||||
chapter.ImageTag = ImageProcessor.GetImageCacheTag(item, chapter);
|
||||
try
|
||||
{
|
||||
chapter.ImageTag = _imageProcessor.GetImageCacheTag(item, chapter);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Failed to create image cache tag.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,10 +38,11 @@ namespace Emby.Server.Implementations.Devices
|
|||
private readonly IServerConfigurationManager _config;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
|
||||
private readonly IAuthenticationRepository _authRepo;
|
||||
private readonly Dictionary<string, ClientCapabilities> _capabilitiesCache;
|
||||
|
||||
public event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>> DeviceOptionsUpdated;
|
||||
|
||||
public event EventHandler<GenericEventArgs<CameraImageUploadInfo>> CameraImageUploaded;
|
||||
|
||||
private readonly object _cameraUploadSyncLock = new object();
|
||||
|
@ -65,10 +66,9 @@ namespace Emby.Server.Implementations.Devices
|
|||
_libraryManager = libraryManager;
|
||||
_localizationManager = localizationManager;
|
||||
_authRepo = authRepo;
|
||||
_capabilitiesCache = new Dictionary<string, ClientCapabilities>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
|
||||
private Dictionary<string, ClientCapabilities> _capabilitiesCache = new Dictionary<string, ClientCapabilities>(StringComparer.OrdinalIgnoreCase);
|
||||
public void SaveCapabilities(string deviceId, ClientCapabilities capabilities)
|
||||
{
|
||||
var path = Path.Combine(GetDevicePath(deviceId), "capabilities.json");
|
||||
|
|
|
@ -38,21 +38,23 @@ namespace Emby.Server.Implementations.Dto
|
|||
private readonly IProviderManager _providerManager;
|
||||
|
||||
private readonly IApplicationHost _appHost;
|
||||
private readonly Func<IMediaSourceManager> _mediaSourceManager;
|
||||
private readonly Func<ILiveTvManager> _livetvManager;
|
||||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
private readonly Lazy<ILiveTvManager> _livetvManagerFactory;
|
||||
|
||||
private ILiveTvManager LivetvManager => _livetvManagerFactory.Value;
|
||||
|
||||
public DtoService(
|
||||
ILoggerFactory loggerFactory,
|
||||
ILogger<DtoService> logger,
|
||||
ILibraryManager libraryManager,
|
||||
IUserDataManager userDataRepository,
|
||||
IItemRepository itemRepo,
|
||||
IImageProcessor imageProcessor,
|
||||
IProviderManager providerManager,
|
||||
IApplicationHost appHost,
|
||||
Func<IMediaSourceManager> mediaSourceManager,
|
||||
Func<ILiveTvManager> livetvManager)
|
||||
IMediaSourceManager mediaSourceManager,
|
||||
Lazy<ILiveTvManager> livetvManagerFactory)
|
||||
{
|
||||
_logger = loggerFactory.CreateLogger(nameof(DtoService));
|
||||
_logger = logger;
|
||||
_libraryManager = libraryManager;
|
||||
_userDataRepository = userDataRepository;
|
||||
_itemRepo = itemRepo;
|
||||
|
@ -60,7 +62,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
_providerManager = providerManager;
|
||||
_appHost = appHost;
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
_livetvManager = livetvManager;
|
||||
_livetvManagerFactory = livetvManagerFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -125,12 +127,12 @@ namespace Emby.Server.Implementations.Dto
|
|||
|
||||
if (programTuples.Count > 0)
|
||||
{
|
||||
_livetvManager().AddInfoToProgramDto(programTuples, options.Fields, user).GetAwaiter().GetResult();
|
||||
LivetvManager.AddInfoToProgramDto(programTuples, options.Fields, user).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
if (channelTuples.Count > 0)
|
||||
{
|
||||
_livetvManager().AddChannelInfo(channelTuples, options, user);
|
||||
LivetvManager.AddChannelInfo(channelTuples, options, user);
|
||||
}
|
||||
|
||||
return returnItems;
|
||||
|
@ -142,12 +144,12 @@ namespace Emby.Server.Implementations.Dto
|
|||
if (item is LiveTvChannel tvChannel)
|
||||
{
|
||||
var list = new List<(BaseItemDto, LiveTvChannel)>(1) { (dto, tvChannel) };
|
||||
_livetvManager().AddChannelInfo(list, options, user);
|
||||
LivetvManager.AddChannelInfo(list, options, user);
|
||||
}
|
||||
else if (item is LiveTvProgram)
|
||||
{
|
||||
var list = new List<(BaseItem, BaseItemDto)>(1) { (item, dto) };
|
||||
var task = _livetvManager().AddInfoToProgramDto(list, options.Fields, user);
|
||||
var task = LivetvManager.AddInfoToProgramDto(list, options.Fields, user);
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
|
@ -223,7 +225,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
if (item is IHasMediaSources
|
||||
&& options.ContainsField(ItemFields.MediaSources))
|
||||
{
|
||||
dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(item, true, user).ToArray();
|
||||
dto.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, true, user).ToArray();
|
||||
|
||||
NormalizeMediaSourceContainers(dto);
|
||||
}
|
||||
|
@ -254,7 +256,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
dto.Etag = item.GetEtag(user);
|
||||
}
|
||||
|
||||
var liveTvManager = _livetvManager();
|
||||
var liveTvManager = LivetvManager;
|
||||
var activeRecording = liveTvManager.GetActiveRecordingInfo(item.Path);
|
||||
if (activeRecording != null)
|
||||
{
|
||||
|
@ -1045,7 +1047,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
}
|
||||
else
|
||||
{
|
||||
mediaStreams = _mediaSourceManager().GetStaticMediaSources(item, true)[0].MediaStreams.ToArray();
|
||||
mediaStreams = _mediaSourceManager.GetStaticMediaSources(item, true)[0].MediaStreams.ToArray();
|
||||
}
|
||||
|
||||
dto.MediaStreams = mediaStreams;
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{E383961B-9356-4D5D-8233-9A1079D03055}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Emby.Naming\Emby.Naming.csproj" />
|
||||
<ProjectReference Include="..\Emby.Notifications\Emby.Notifications.csproj" />
|
||||
|
|
|
@ -16,46 +16,63 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
private readonly IServerApplicationHost _appHost;
|
||||
private readonly IConfiguration _appConfig;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IStartupOptions _startupOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StartupWizard"/> class.
|
||||
/// </summary>
|
||||
/// <param name="appHost">The application host.</param>
|
||||
/// <param name="appConfig">The application configuration.</param>
|
||||
/// <param name="config">The configuration manager.</param>
|
||||
public StartupWizard(IServerApplicationHost appHost, IConfiguration appConfig, IServerConfigurationManager config)
|
||||
/// <param name="startupOptions">The application startup options.</param>
|
||||
public StartupWizard(
|
||||
IServerApplicationHost appHost,
|
||||
IConfiguration appConfig,
|
||||
IServerConfigurationManager config,
|
||||
IStartupOptions startupOptions)
|
||||
{
|
||||
_appHost = appHost;
|
||||
_appConfig = appConfig;
|
||||
_config = config;
|
||||
_startupOptions = startupOptions;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task RunAsync()
|
||||
{
|
||||
Run();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void Run()
|
||||
{
|
||||
if (!_appHost.CanLaunchWebBrowser)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_appConfig.HostWebClient())
|
||||
// Always launch the startup wizard if possible when it has not been completed
|
||||
if (!_config.Configuration.IsStartupWizardCompleted && _appConfig.HostWebClient())
|
||||
{
|
||||
BrowserLauncher.OpenSwaggerPage(_appHost);
|
||||
BrowserLauncher.OpenWebApp(_appHost);
|
||||
return;
|
||||
}
|
||||
else if (!_config.Configuration.IsStartupWizardCompleted)
|
||||
|
||||
// Do nothing if the web app is configured to not run automatically
|
||||
if (!_config.Configuration.AutoRunWebApp || _startupOptions.NoAutoRunWebApp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Launch the swagger page if the web client is not hosted, otherwise open the web client
|
||||
if (_appConfig.HostWebClient())
|
||||
{
|
||||
BrowserLauncher.OpenWebApp(_appHost);
|
||||
}
|
||||
else if (_config.Configuration.AutoRunWebApp)
|
||||
else
|
||||
{
|
||||
var options = ((ApplicationHost)_appHost).StartupOptions;
|
||||
|
||||
if (!options.NoAutoRunWebApp)
|
||||
{
|
||||
BrowserLauncher.OpenWebApp(_appHost);
|
||||
}
|
||||
BrowserLauncher.OpenSwaggerPage(_appHost);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
|
@ -24,7 +25,7 @@ namespace Emby.Server.Implementations.HttpClientManager
|
|||
private readonly ILogger _logger;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly Func<string> _defaultUserAgentFn;
|
||||
private readonly IApplicationHost _appHost;
|
||||
|
||||
/// <summary>
|
||||
/// Holds a dictionary of http clients by host. Use GetHttpClient(host) to retrieve or create a client for web requests.
|
||||
|
@ -40,12 +41,12 @@ namespace Emby.Server.Implementations.HttpClientManager
|
|||
IApplicationPaths appPaths,
|
||||
ILogger<HttpClientManager> logger,
|
||||
IFileSystem fileSystem,
|
||||
Func<string> defaultUserAgentFn)
|
||||
IApplicationHost appHost)
|
||||
{
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_fileSystem = fileSystem;
|
||||
_appPaths = appPaths ?? throw new ArgumentNullException(nameof(appPaths));
|
||||
_defaultUserAgentFn = defaultUserAgentFn;
|
||||
_appHost = appHost;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -91,7 +92,7 @@ namespace Emby.Server.Implementations.HttpClientManager
|
|||
if (options.EnableDefaultUserAgent
|
||||
&& !request.Headers.TryGetValues(HeaderNames.UserAgent, out _))
|
||||
{
|
||||
request.Headers.Add(HeaderNames.UserAgent, _defaultUserAgentFn());
|
||||
request.Headers.Add(HeaderNames.UserAgent, _appHost.ApplicationUserAgent);
|
||||
}
|
||||
|
||||
switch (options.DecompressionMethod)
|
||||
|
|
|
@ -14,6 +14,7 @@ using Emby.Server.Implementations.Services;
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Events;
|
||||
|
@ -230,7 +231,8 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
switch (ex)
|
||||
{
|
||||
case ArgumentException _: return 400;
|
||||
case SecurityException _: return 401;
|
||||
case AuthenticationException _: return 401;
|
||||
case SecurityException _: return 403;
|
||||
case DirectoryNotFoundException _:
|
||||
case FileNotFoundException _:
|
||||
case ResourceNotFoundException _: return 404;
|
||||
|
@ -239,55 +241,52 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
}
|
||||
}
|
||||
|
||||
private async Task ErrorHandler(Exception ex, IRequest httpReq, bool logExceptionStackTrace, string urlToLog)
|
||||
private async Task ErrorHandler(Exception ex, IRequest httpReq, int statusCode, string urlToLog)
|
||||
{
|
||||
try
|
||||
bool ignoreStackTrace =
|
||||
ex is SocketException
|
||||
|| ex is IOException
|
||||
|| ex is OperationCanceledException
|
||||
|| ex is SecurityException
|
||||
|| ex is AuthenticationException
|
||||
|| ex is FileNotFoundException;
|
||||
|
||||
if (ignoreStackTrace)
|
||||
{
|
||||
ex = GetActualException(ex);
|
||||
|
||||
if (logExceptionStackTrace)
|
||||
{
|
||||
_logger.LogError(ex, "Error processing request. URL: {Url}", urlToLog);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("Error processing request: {Message}. URL: {Url}", ex.Message.TrimEnd('.'), urlToLog);
|
||||
}
|
||||
|
||||
var httpRes = httpReq.Response;
|
||||
|
||||
if (httpRes.HasStarted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var statusCode = GetStatusCode(ex);
|
||||
httpRes.StatusCode = statusCode;
|
||||
|
||||
var errContent = NormalizeExceptionMessage(ex.Message);
|
||||
httpRes.ContentType = "text/plain";
|
||||
httpRes.ContentLength = errContent.Length;
|
||||
await httpRes.WriteAsync(errContent).ConfigureAwait(false);
|
||||
_logger.LogError("Error processing request: {Message}. URL: {Url}", ex.Message.TrimEnd('.'), urlToLog);
|
||||
}
|
||||
catch (Exception errorEx)
|
||||
else
|
||||
{
|
||||
_logger.LogError(errorEx, "Error this.ProcessRequest(context)(Exception while writing error to the response). URL: {Url}", urlToLog);
|
||||
_logger.LogError(ex, "Error processing request. URL: {Url}", urlToLog);
|
||||
}
|
||||
|
||||
var httpRes = httpReq.Response;
|
||||
|
||||
if (httpRes.HasStarted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
httpRes.StatusCode = statusCode;
|
||||
|
||||
var errContent = NormalizeExceptionMessage(ex) ?? string.Empty;
|
||||
httpRes.ContentType = "text/plain";
|
||||
httpRes.ContentLength = errContent.Length;
|
||||
await httpRes.WriteAsync(errContent).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private string NormalizeExceptionMessage(string msg)
|
||||
private string NormalizeExceptionMessage(Exception ex)
|
||||
{
|
||||
if (msg == null)
|
||||
// Do not expose the exception message for AuthenticationException
|
||||
if (ex is AuthenticationException)
|
||||
{
|
||||
return string.Empty;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Strip any information we don't want to reveal
|
||||
|
||||
msg = msg.Replace(_config.ApplicationPaths.ProgramSystemPath, string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
msg = msg.Replace(_config.ApplicationPaths.ProgramDataPath, string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
return msg;
|
||||
return ex.Message
|
||||
?.Replace(_config.ApplicationPaths.ProgramSystemPath, string.Empty, StringComparison.OrdinalIgnoreCase)
|
||||
.Replace(_config.ApplicationPaths.ProgramDataPath, string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -536,22 +535,32 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
throw new FileNotFoundException();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception requestEx)
|
||||
{
|
||||
// Do not handle exceptions manually when in development mode
|
||||
// The framework-defined development exception page will be returned instead
|
||||
if (_hostEnvironment.IsDevelopment())
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
var requestInnerEx = GetActualException(requestEx);
|
||||
var statusCode = GetStatusCode(requestInnerEx);
|
||||
|
||||
bool ignoreStackTrace =
|
||||
ex is SocketException
|
||||
|| ex is IOException
|
||||
|| ex is OperationCanceledException
|
||||
|| ex is SecurityException
|
||||
|| ex is FileNotFoundException;
|
||||
await ErrorHandler(ex, httpReq, !ignoreStackTrace, urlToLog).ConfigureAwait(false);
|
||||
// Do not handle 500 server exceptions manually when in development mode
|
||||
// The framework-defined development exception page will be returned instead
|
||||
if (statusCode == 500 && _hostEnvironment.IsDevelopment())
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
await ErrorHandler(requestInnerEx, httpReq, statusCode, urlToLog).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception handlerException)
|
||||
{
|
||||
var aggregateEx = new AggregateException("Error while handling request exception", requestEx, handlerException);
|
||||
_logger.LogError(aggregateEx, "Error while handling exception in response to {Url}", urlToLog);
|
||||
|
||||
if (_hostEnvironment.IsDevelopment())
|
||||
{
|
||||
throw aggregateEx;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Authentication;
|
||||
using Emby.Server.Implementations.SocketSharp;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
@ -68,7 +69,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
|
||||
if (user == null && auth.UserId != Guid.Empty)
|
||||
{
|
||||
throw new SecurityException("User with Id " + auth.UserId + " not found");
|
||||
throw new AuthenticationException("User with Id " + auth.UserId + " not found");
|
||||
}
|
||||
|
||||
if (user != null)
|
||||
|
@ -108,18 +109,12 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
{
|
||||
if (user.Policy.IsDisabled)
|
||||
{
|
||||
throw new SecurityException("User account has been disabled.")
|
||||
{
|
||||
SecurityExceptionType = SecurityExceptionType.Unauthenticated
|
||||
};
|
||||
throw new SecurityException("User account has been disabled.");
|
||||
}
|
||||
|
||||
if (!user.Policy.EnableRemoteAccess && !_networkManager.IsInLocalNetwork(request.RemoteIp))
|
||||
{
|
||||
throw new SecurityException("User account has been disabled.")
|
||||
{
|
||||
SecurityExceptionType = SecurityExceptionType.Unauthenticated
|
||||
};
|
||||
throw new SecurityException("User account has been disabled.");
|
||||
}
|
||||
|
||||
if (!user.Policy.IsAdministrator
|
||||
|
@ -128,10 +123,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
{
|
||||
request.Response.Headers.Add("X-Application-Error-Code", "ParentalControl");
|
||||
|
||||
throw new SecurityException("This user account is not allowed access at this time.")
|
||||
{
|
||||
SecurityExceptionType = SecurityExceptionType.ParentalControl
|
||||
};
|
||||
throw new SecurityException("This user account is not allowed access at this time.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,10 +182,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
{
|
||||
if (user == null || !user.Policy.IsAdministrator)
|
||||
{
|
||||
throw new SecurityException("User does not have admin access.")
|
||||
{
|
||||
SecurityExceptionType = SecurityExceptionType.Unauthenticated
|
||||
};
|
||||
throw new SecurityException("User does not have admin access.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,10 +190,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
{
|
||||
if (user == null || !user.Policy.EnableContentDeletion)
|
||||
{
|
||||
throw new SecurityException("User does not have delete access.")
|
||||
{
|
||||
SecurityExceptionType = SecurityExceptionType.Unauthenticated
|
||||
};
|
||||
throw new SecurityException("User does not have delete access.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,10 +198,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
{
|
||||
if (user == null || !user.Policy.EnableContentDownloading)
|
||||
{
|
||||
throw new SecurityException("User does not have download access.")
|
||||
{
|
||||
SecurityExceptionType = SecurityExceptionType.Unauthenticated
|
||||
};
|
||||
throw new SecurityException("User does not have download access.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -230,14 +213,14 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
{
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
throw new SecurityException("Access token is required.");
|
||||
throw new AuthenticationException("Access token is required.");
|
||||
}
|
||||
|
||||
var info = GetTokenInfo(request);
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
throw new SecurityException("Access token is invalid or expired.");
|
||||
throw new AuthenticationException("Access token is invalid or expired.");
|
||||
}
|
||||
|
||||
//if (!string.IsNullOrEmpty(info.UserId))
|
||||
|
|
|
@ -17,6 +17,11 @@ namespace Emby.Server.Implementations.IO
|
|||
{
|
||||
public class LibraryMonitor : ILibraryMonitor
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IServerConfigurationManager _configurationManager;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
/// <summary>
|
||||
/// The file system watchers.
|
||||
/// </summary>
|
||||
|
@ -113,34 +118,23 @@ namespace Emby.Server.Implementations.IO
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error in ReportFileSystemChanged for {path}", path);
|
||||
_logger.LogError(ex, "Error in ReportFileSystemChanged for {path}", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the logger.
|
||||
/// </summary>
|
||||
/// <value>The logger.</value>
|
||||
private ILogger Logger { get; set; }
|
||||
|
||||
private ILibraryManager LibraryManager { get; set; }
|
||||
private IServerConfigurationManager ConfigurationManager { get; set; }
|
||||
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LibraryMonitor" /> class.
|
||||
/// </summary>
|
||||
public LibraryMonitor(
|
||||
ILoggerFactory loggerFactory,
|
||||
ILogger<LibraryMonitor> logger,
|
||||
ILibraryManager libraryManager,
|
||||
IServerConfigurationManager configurationManager,
|
||||
IFileSystem fileSystem)
|
||||
{
|
||||
LibraryManager = libraryManager;
|
||||
Logger = loggerFactory.CreateLogger(GetType().Name);
|
||||
ConfigurationManager = configurationManager;
|
||||
_libraryManager = libraryManager;
|
||||
_logger = logger;
|
||||
_configurationManager = configurationManager;
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
|
||||
|
@ -151,7 +145,7 @@ namespace Emby.Server.Implementations.IO
|
|||
return false;
|
||||
}
|
||||
|
||||
var options = LibraryManager.GetLibraryOptions(item);
|
||||
var options = _libraryManager.GetLibraryOptions(item);
|
||||
|
||||
if (options != null)
|
||||
{
|
||||
|
@ -163,12 +157,12 @@ namespace Emby.Server.Implementations.IO
|
|||
|
||||
public void Start()
|
||||
{
|
||||
LibraryManager.ItemAdded += OnLibraryManagerItemAdded;
|
||||
LibraryManager.ItemRemoved += OnLibraryManagerItemRemoved;
|
||||
_libraryManager.ItemAdded += OnLibraryManagerItemAdded;
|
||||
_libraryManager.ItemRemoved += OnLibraryManagerItemRemoved;
|
||||
|
||||
var pathsToWatch = new List<string>();
|
||||
|
||||
var paths = LibraryManager
|
||||
var paths = _libraryManager
|
||||
.RootFolder
|
||||
.Children
|
||||
.Where(IsLibraryMonitorEnabled)
|
||||
|
@ -261,7 +255,7 @@ namespace Emby.Server.Implementations.IO
|
|||
if (!Directory.Exists(path))
|
||||
{
|
||||
// Seeing a crash in the mono runtime due to an exception being thrown on a different thread
|
||||
Logger.LogInformation("Skipping realtime monitor for {Path} because the path does not exist", path);
|
||||
_logger.LogInformation("Skipping realtime monitor for {Path} because the path does not exist", path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -297,7 +291,7 @@ namespace Emby.Server.Implementations.IO
|
|||
if (_fileSystemWatchers.TryAdd(path, newWatcher))
|
||||
{
|
||||
newWatcher.EnableRaisingEvents = true;
|
||||
Logger.LogInformation("Watching directory " + path);
|
||||
_logger.LogInformation("Watching directory " + path);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -307,7 +301,7 @@ namespace Emby.Server.Implementations.IO
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error watching path: {path}", path);
|
||||
_logger.LogError(ex, "Error watching path: {path}", path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -333,7 +327,7 @@ namespace Emby.Server.Implementations.IO
|
|||
{
|
||||
using (watcher)
|
||||
{
|
||||
Logger.LogInformation("Stopping directory watching for path {Path}", watcher.Path);
|
||||
_logger.LogInformation("Stopping directory watching for path {Path}", watcher.Path);
|
||||
|
||||
watcher.Created -= OnWatcherChanged;
|
||||
watcher.Deleted -= OnWatcherChanged;
|
||||
|
@ -372,7 +366,7 @@ namespace Emby.Server.Implementations.IO
|
|||
var ex = e.GetException();
|
||||
var dw = (FileSystemWatcher)sender;
|
||||
|
||||
Logger.LogError(ex, "Error in Directory watcher for: {Path}", dw.Path);
|
||||
_logger.LogError(ex, "Error in Directory watcher for: {Path}", dw.Path);
|
||||
|
||||
DisposeWatcher(dw, true);
|
||||
}
|
||||
|
@ -390,7 +384,7 @@ namespace Emby.Server.Implementations.IO
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Exception in ReportFileSystemChanged. Path: {FullPath}", e.FullPath);
|
||||
_logger.LogError(ex, "Exception in ReportFileSystemChanged. Path: {FullPath}", e.FullPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,13 +410,13 @@ namespace Emby.Server.Implementations.IO
|
|||
{
|
||||
if (_fileSystem.AreEqual(i, path))
|
||||
{
|
||||
Logger.LogDebug("Ignoring change to {Path}", path);
|
||||
_logger.LogDebug("Ignoring change to {Path}", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_fileSystem.ContainsSubPath(i, path))
|
||||
{
|
||||
Logger.LogDebug("Ignoring change to {Path}", path);
|
||||
_logger.LogDebug("Ignoring change to {Path}", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -430,7 +424,7 @@ namespace Emby.Server.Implementations.IO
|
|||
var parent = Path.GetDirectoryName(i);
|
||||
if (!string.IsNullOrEmpty(parent) && _fileSystem.AreEqual(parent, path))
|
||||
{
|
||||
Logger.LogDebug("Ignoring change to {Path}", path);
|
||||
_logger.LogDebug("Ignoring change to {Path}", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -485,7 +479,7 @@ namespace Emby.Server.Implementations.IO
|
|||
}
|
||||
}
|
||||
|
||||
var newRefresher = new FileRefresher(path, ConfigurationManager, LibraryManager, Logger);
|
||||
var newRefresher = new FileRefresher(path, _configurationManager, _libraryManager, _logger);
|
||||
newRefresher.Completed += NewRefresher_Completed;
|
||||
_activeRefreshers.Add(newRefresher);
|
||||
}
|
||||
|
@ -502,8 +496,8 @@ namespace Emby.Server.Implementations.IO
|
|||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
LibraryManager.ItemAdded -= OnLibraryManagerItemAdded;
|
||||
LibraryManager.ItemRemoved -= OnLibraryManagerItemRemoved;
|
||||
_libraryManager.ItemAdded -= OnLibraryManagerItemAdded;
|
||||
_libraryManager.ItemRemoved -= OnLibraryManagerItemRemoved;
|
||||
|
||||
foreach (var watcher in _fileSystemWatchers.Values.ToList())
|
||||
{
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
if (resolvedUser == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(resolvedUser));
|
||||
throw new AuthenticationException($"Specified user does not exist.");
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
|
|
@ -54,9 +54,29 @@ namespace Emby.Server.Implementations.Library
|
|||
/// </summary>
|
||||
public class LibraryManager : ILibraryManager
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly ITaskManager _taskManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IUserDataManager _userDataRepository;
|
||||
private readonly IServerConfigurationManager _configurationManager;
|
||||
private readonly Lazy<ILibraryMonitor> _libraryMonitorFactory;
|
||||
private readonly Lazy<IProviderManager> _providerManagerFactory;
|
||||
private readonly Lazy<IUserViewManager> _userviewManagerFactory;
|
||||
private readonly IServerApplicationHost _appHost;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IItemRepository _itemRepository;
|
||||
private readonly ConcurrentDictionary<Guid, BaseItem> _libraryItemsCache;
|
||||
|
||||
private NamingOptions _namingOptions;
|
||||
private string[] _videoFileExtensions;
|
||||
|
||||
private ILibraryMonitor LibraryMonitor => _libraryMonitorFactory.Value;
|
||||
|
||||
private IProviderManager ProviderManager => _providerManagerFactory.Value;
|
||||
|
||||
private IUserViewManager UserViewManager => _userviewManagerFactory.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the postscan tasks.
|
||||
/// </summary>
|
||||
|
@ -89,12 +109,6 @@ namespace Emby.Server.Implementations.Library
|
|||
/// <value>The comparers.</value>
|
||||
private IBaseItemComparer[] Comparers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the active item repository
|
||||
/// </summary>
|
||||
/// <value>The item repository.</value>
|
||||
public IItemRepository ItemRepository { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [item added].
|
||||
/// </summary>
|
||||
|
@ -110,90 +124,47 @@ namespace Emby.Server.Implementations.Library
|
|||
/// </summary>
|
||||
public event EventHandler<ItemChangeEventArgs> ItemRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// The _logger
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// The _task manager
|
||||
/// </summary>
|
||||
private readonly ITaskManager _taskManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user data repository
|
||||
/// </summary>
|
||||
private readonly IUserDataManager _userDataRepository;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the configuration manager.
|
||||
/// </summary>
|
||||
/// <value>The configuration manager.</value>
|
||||
private IServerConfigurationManager ConfigurationManager { get; set; }
|
||||
|
||||
private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
|
||||
private readonly Func<IProviderManager> _providerManagerFactory;
|
||||
private readonly Func<IUserViewManager> _userviewManager;
|
||||
public bool IsScanRunning { get; private set; }
|
||||
|
||||
private IServerApplicationHost _appHost;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
|
||||
/// <summary>
|
||||
/// The _library items cache
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<Guid, BaseItem> _libraryItemsCache;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the library items cache.
|
||||
/// </summary>
|
||||
/// <value>The library items cache.</value>
|
||||
private ConcurrentDictionary<Guid, BaseItem> LibraryItemsCache => _libraryItemsCache;
|
||||
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LibraryManager" /> class.
|
||||
/// </summary>
|
||||
/// <param name="appHost">The application host</param>
|
||||
/// <param name="loggerFactory">The logger factory.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="taskManager">The task manager.</param>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
/// <param name="configurationManager">The configuration manager.</param>
|
||||
/// <param name="userDataRepository">The user data repository.</param>
|
||||
public LibraryManager(
|
||||
IServerApplicationHost appHost,
|
||||
ILoggerFactory loggerFactory,
|
||||
ILogger<LibraryManager> logger,
|
||||
ITaskManager taskManager,
|
||||
IUserManager userManager,
|
||||
IServerConfigurationManager configurationManager,
|
||||
IUserDataManager userDataRepository,
|
||||
Func<ILibraryMonitor> libraryMonitorFactory,
|
||||
Lazy<ILibraryMonitor> libraryMonitorFactory,
|
||||
IFileSystem fileSystem,
|
||||
Func<IProviderManager> providerManagerFactory,
|
||||
Func<IUserViewManager> userviewManager,
|
||||
IMediaEncoder mediaEncoder)
|
||||
Lazy<IProviderManager> providerManagerFactory,
|
||||
Lazy<IUserViewManager> userviewManagerFactory,
|
||||
IMediaEncoder mediaEncoder,
|
||||
IItemRepository itemRepository)
|
||||
{
|
||||
_appHost = appHost;
|
||||
_logger = loggerFactory.CreateLogger(nameof(LibraryManager));
|
||||
_logger = logger;
|
||||
_taskManager = taskManager;
|
||||
_userManager = userManager;
|
||||
ConfigurationManager = configurationManager;
|
||||
_configurationManager = configurationManager;
|
||||
_userDataRepository = userDataRepository;
|
||||
_libraryMonitorFactory = libraryMonitorFactory;
|
||||
_fileSystem = fileSystem;
|
||||
_providerManagerFactory = providerManagerFactory;
|
||||
_userviewManager = userviewManager;
|
||||
_userviewManagerFactory = userviewManagerFactory;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_itemRepository = itemRepository;
|
||||
|
||||
_libraryItemsCache = new ConcurrentDictionary<Guid, BaseItem>();
|
||||
|
||||
ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated;
|
||||
_configurationManager.ConfigurationUpdated += ConfigurationUpdated;
|
||||
|
||||
RecordConfigurationValues(configurationManager.Configuration);
|
||||
}
|
||||
|
@ -272,7 +243,7 @@ namespace Emby.Server.Implementations.Library
|
|||
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
|
||||
private void ConfigurationUpdated(object sender, EventArgs e)
|
||||
{
|
||||
var config = ConfigurationManager.Configuration;
|
||||
var config = _configurationManager.Configuration;
|
||||
|
||||
var wizardChanged = config.IsStartupWizardCompleted != _wizardCompleted;
|
||||
|
||||
|
@ -306,7 +277,7 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
}
|
||||
|
||||
LibraryItemsCache.AddOrUpdate(item.Id, item, delegate { return item; });
|
||||
_libraryItemsCache.AddOrUpdate(item.Id, item, delegate { return item; });
|
||||
}
|
||||
|
||||
public void DeleteItem(BaseItem item, DeleteOptions options)
|
||||
|
@ -437,10 +408,10 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
item.SetParent(null);
|
||||
|
||||
ItemRepository.DeleteItem(item.Id);
|
||||
_itemRepository.DeleteItem(item.Id);
|
||||
foreach (var child in children)
|
||||
{
|
||||
ItemRepository.DeleteItem(child.Id);
|
||||
_itemRepository.DeleteItem(child.Id);
|
||||
}
|
||||
|
||||
_libraryItemsCache.TryRemove(item.Id, out BaseItem removed);
|
||||
|
@ -509,15 +480,15 @@ namespace Emby.Server.Implementations.Library
|
|||
throw new ArgumentNullException(nameof(type));
|
||||
}
|
||||
|
||||
if (key.StartsWith(ConfigurationManager.ApplicationPaths.ProgramDataPath, StringComparison.Ordinal))
|
||||
if (key.StartsWith(_configurationManager.ApplicationPaths.ProgramDataPath, StringComparison.Ordinal))
|
||||
{
|
||||
// Try to normalize paths located underneath program-data in an attempt to make them more portable
|
||||
key = key.Substring(ConfigurationManager.ApplicationPaths.ProgramDataPath.Length)
|
||||
key = key.Substring(_configurationManager.ApplicationPaths.ProgramDataPath.Length)
|
||||
.TrimStart(new[] { '/', '\\' })
|
||||
.Replace("/", "\\");
|
||||
}
|
||||
|
||||
if (forceCaseInsensitive || !ConfigurationManager.Configuration.EnableCaseSensitiveItemIds)
|
||||
if (forceCaseInsensitive || !_configurationManager.Configuration.EnableCaseSensitiveItemIds)
|
||||
{
|
||||
key = key.ToLowerInvariant();
|
||||
}
|
||||
|
@ -550,7 +521,7 @@ namespace Emby.Server.Implementations.Library
|
|||
collectionType = GetContentTypeOverride(fullPath, true);
|
||||
}
|
||||
|
||||
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
|
||||
var args = new ItemResolveArgs(_configurationManager.ApplicationPaths, directoryService)
|
||||
{
|
||||
Parent = parent,
|
||||
Path = fullPath,
|
||||
|
@ -720,7 +691,7 @@ namespace Emby.Server.Implementations.Library
|
|||
/// <exception cref="InvalidOperationException">Cannot create the root folder until plugins have loaded.</exception>
|
||||
public AggregateFolder CreateRootFolder()
|
||||
{
|
||||
var rootFolderPath = ConfigurationManager.ApplicationPaths.RootFolderPath;
|
||||
var rootFolderPath = _configurationManager.ApplicationPaths.RootFolderPath;
|
||||
|
||||
Directory.CreateDirectory(rootFolderPath);
|
||||
|
||||
|
@ -734,7 +705,7 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
|
||||
// Add in the plug-in folders
|
||||
var path = Path.Combine(ConfigurationManager.ApplicationPaths.DataPath, "playlists");
|
||||
var path = Path.Combine(_configurationManager.ApplicationPaths.DataPath, "playlists");
|
||||
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
|
@ -786,7 +757,7 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
if (_userRootFolder == null)
|
||||
{
|
||||
var userRootPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
var userRootPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
|
||||
_logger.LogDebug("Creating userRootPath at {path}", userRootPath);
|
||||
Directory.CreateDirectory(userRootPath);
|
||||
|
@ -980,7 +951,7 @@ namespace Emby.Server.Implementations.Library
|
|||
where T : BaseItem, new()
|
||||
{
|
||||
var path = getPathFn(name);
|
||||
var forceCaseInsensitiveId = ConfigurationManager.Configuration.EnableNormalizedItemByNameIds;
|
||||
var forceCaseInsensitiveId = _configurationManager.Configuration.EnableNormalizedItemByNameIds;
|
||||
return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
|
||||
}
|
||||
|
||||
|
@ -994,7 +965,7 @@ namespace Emby.Server.Implementations.Library
|
|||
public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
// Ensure the location is available.
|
||||
Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath);
|
||||
Directory.CreateDirectory(_configurationManager.ApplicationPaths.PeoplePath);
|
||||
|
||||
return new PeopleValidator(this, _logger, _fileSystem).ValidatePeople(cancellationToken, progress);
|
||||
}
|
||||
|
@ -1031,7 +1002,7 @@ namespace Emby.Server.Implementations.Library
|
|||
public async Task ValidateMediaLibraryInternal(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
IsScanRunning = true;
|
||||
_libraryMonitorFactory().Stop();
|
||||
LibraryMonitor.Stop();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -1039,7 +1010,7 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
finally
|
||||
{
|
||||
_libraryMonitorFactory().Start();
|
||||
LibraryMonitor.Start();
|
||||
IsScanRunning = false;
|
||||
}
|
||||
}
|
||||
|
@ -1148,7 +1119,7 @@ namespace Emby.Server.Implementations.Library
|
|||
progress.Report(percent * 100);
|
||||
}
|
||||
|
||||
ItemRepository.UpdateInheritedValues(cancellationToken);
|
||||
_itemRepository.UpdateInheritedValues(cancellationToken);
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
@ -1168,9 +1139,9 @@ namespace Emby.Server.Implementations.Library
|
|||
var topLibraryFolders = GetUserRootFolder().Children.ToList();
|
||||
|
||||
_logger.LogDebug("Getting refreshQueue");
|
||||
var refreshQueue = includeRefreshState ? _providerManagerFactory().GetRefreshQueue() : null;
|
||||
var refreshQueue = includeRefreshState ? ProviderManager.GetRefreshQueue() : null;
|
||||
|
||||
return _fileSystem.GetDirectoryPaths(ConfigurationManager.ApplicationPaths.DefaultUserViewsPath)
|
||||
return _fileSystem.GetDirectoryPaths(_configurationManager.ApplicationPaths.DefaultUserViewsPath)
|
||||
.Select(dir => GetVirtualFolderInfo(dir, topLibraryFolders, refreshQueue))
|
||||
.ToList();
|
||||
}
|
||||
|
@ -1245,7 +1216,7 @@ namespace Emby.Server.Implementations.Library
|
|||
throw new ArgumentException("Guid can't be empty", nameof(id));
|
||||
}
|
||||
|
||||
if (LibraryItemsCache.TryGetValue(id, out BaseItem item))
|
||||
if (_libraryItemsCache.TryGetValue(id, out BaseItem item))
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
@ -1276,7 +1247,7 @@ namespace Emby.Server.Implementations.Library
|
|||
AddUserToQuery(query, query.User, allowExternalContent);
|
||||
}
|
||||
|
||||
return ItemRepository.GetItemList(query);
|
||||
return _itemRepository.GetItemList(query);
|
||||
}
|
||||
|
||||
public List<BaseItem> GetItemList(InternalItemsQuery query)
|
||||
|
@ -1300,7 +1271,7 @@ namespace Emby.Server.Implementations.Library
|
|||
AddUserToQuery(query, query.User);
|
||||
}
|
||||
|
||||
return ItemRepository.GetCount(query);
|
||||
return _itemRepository.GetCount(query);
|
||||
}
|
||||
|
||||
public List<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents)
|
||||
|
@ -1315,7 +1286,7 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
}
|
||||
|
||||
return ItemRepository.GetItemList(query);
|
||||
return _itemRepository.GetItemList(query);
|
||||
}
|
||||
|
||||
public QueryResult<BaseItem> QueryItems(InternalItemsQuery query)
|
||||
|
@ -1327,12 +1298,12 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
if (query.EnableTotalRecordCount)
|
||||
{
|
||||
return ItemRepository.GetItems(query);
|
||||
return _itemRepository.GetItems(query);
|
||||
}
|
||||
|
||||
return new QueryResult<BaseItem>
|
||||
{
|
||||
Items = ItemRepository.GetItemList(query).ToArray()
|
||||
Items = _itemRepository.GetItemList(query).ToArray()
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1343,7 +1314,7 @@ namespace Emby.Server.Implementations.Library
|
|||
AddUserToQuery(query, query.User);
|
||||
}
|
||||
|
||||
return ItemRepository.GetItemIdsList(query);
|
||||
return _itemRepository.GetItemIdsList(query);
|
||||
}
|
||||
|
||||
public QueryResult<(BaseItem, ItemCounts)> GetStudios(InternalItemsQuery query)
|
||||
|
@ -1354,7 +1325,7 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
|
||||
SetTopParentOrAncestorIds(query);
|
||||
return ItemRepository.GetStudios(query);
|
||||
return _itemRepository.GetStudios(query);
|
||||
}
|
||||
|
||||
public QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query)
|
||||
|
@ -1365,7 +1336,7 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
|
||||
SetTopParentOrAncestorIds(query);
|
||||
return ItemRepository.GetGenres(query);
|
||||
return _itemRepository.GetGenres(query);
|
||||
}
|
||||
|
||||
public QueryResult<(BaseItem, ItemCounts)> GetMusicGenres(InternalItemsQuery query)
|
||||
|
@ -1376,7 +1347,7 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
|
||||
SetTopParentOrAncestorIds(query);
|
||||
return ItemRepository.GetMusicGenres(query);
|
||||
return _itemRepository.GetMusicGenres(query);
|
||||
}
|
||||
|
||||
public QueryResult<(BaseItem, ItemCounts)> GetAllArtists(InternalItemsQuery query)
|
||||
|
@ -1387,7 +1358,7 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
|
||||
SetTopParentOrAncestorIds(query);
|
||||
return ItemRepository.GetAllArtists(query);
|
||||
return _itemRepository.GetAllArtists(query);
|
||||
}
|
||||
|
||||
public QueryResult<(BaseItem, ItemCounts)> GetArtists(InternalItemsQuery query)
|
||||
|
@ -1398,7 +1369,7 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
|
||||
SetTopParentOrAncestorIds(query);
|
||||
return ItemRepository.GetArtists(query);
|
||||
return _itemRepository.GetArtists(query);
|
||||
}
|
||||
|
||||
private void SetTopParentOrAncestorIds(InternalItemsQuery query)
|
||||
|
@ -1439,7 +1410,7 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
|
||||
SetTopParentOrAncestorIds(query);
|
||||
return ItemRepository.GetAlbumArtists(query);
|
||||
return _itemRepository.GetAlbumArtists(query);
|
||||
}
|
||||
|
||||
public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query)
|
||||
|
@ -1460,10 +1431,10 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
if (query.EnableTotalRecordCount)
|
||||
{
|
||||
return ItemRepository.GetItems(query);
|
||||
return _itemRepository.GetItems(query);
|
||||
}
|
||||
|
||||
var list = ItemRepository.GetItemList(query);
|
||||
var list = _itemRepository.GetItemList(query);
|
||||
|
||||
return new QueryResult<BaseItem>
|
||||
{
|
||||
|
@ -1509,7 +1480,7 @@ namespace Emby.Server.Implementations.Library
|
|||
string.IsNullOrEmpty(query.SeriesPresentationUniqueKey) &&
|
||||
query.ItemIds.Length == 0)
|
||||
{
|
||||
var userViews = _userviewManager().GetUserViews(new UserViewQuery
|
||||
var userViews = UserViewManager.GetUserViews(new UserViewQuery
|
||||
{
|
||||
UserId = user.Id,
|
||||
IncludeHidden = true,
|
||||
|
@ -1809,7 +1780,7 @@ namespace Emby.Server.Implementations.Library
|
|||
// Don't iterate multiple times
|
||||
var itemsList = items.ToList();
|
||||
|
||||
ItemRepository.SaveItems(itemsList, cancellationToken);
|
||||
_itemRepository.SaveItems(itemsList, cancellationToken);
|
||||
|
||||
foreach (var item in itemsList)
|
||||
{
|
||||
|
@ -1846,7 +1817,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
public void UpdateImages(BaseItem item)
|
||||
{
|
||||
ItemRepository.SaveImages(item);
|
||||
_itemRepository.SaveImages(item);
|
||||
|
||||
RegisterItem(item);
|
||||
}
|
||||
|
@ -1863,7 +1834,7 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
if (item.IsFileProtocol)
|
||||
{
|
||||
_providerManagerFactory().SaveMetadata(item, updateReason);
|
||||
ProviderManager.SaveMetadata(item, updateReason);
|
||||
}
|
||||
|
||||
item.DateLastSaved = DateTime.UtcNow;
|
||||
|
@ -1871,7 +1842,7 @@ namespace Emby.Server.Implementations.Library
|
|||
RegisterItem(item);
|
||||
}
|
||||
|
||||
ItemRepository.SaveItems(itemsList, cancellationToken);
|
||||
_itemRepository.SaveItems(itemsList, cancellationToken);
|
||||
|
||||
if (ItemUpdated != null)
|
||||
{
|
||||
|
@ -1947,7 +1918,7 @@ namespace Emby.Server.Implementations.Library
|
|||
/// <returns>BaseItem.</returns>
|
||||
public BaseItem RetrieveItem(Guid id)
|
||||
{
|
||||
return ItemRepository.RetrieveItem(id);
|
||||
return _itemRepository.RetrieveItem(id);
|
||||
}
|
||||
|
||||
public List<Folder> GetCollectionFolders(BaseItem item)
|
||||
|
@ -2066,7 +2037,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
private string GetContentTypeOverride(string path, bool inherit)
|
||||
{
|
||||
var nameValuePair = ConfigurationManager.Configuration.ContentTypes
|
||||
var nameValuePair = _configurationManager.Configuration.ContentTypes
|
||||
.FirstOrDefault(i => _fileSystem.AreEqual(i.Name, path)
|
||||
|| (inherit && !string.IsNullOrEmpty(i.Name)
|
||||
&& _fileSystem.ContainsSubPath(i.Name, path)));
|
||||
|
@ -2115,7 +2086,7 @@ namespace Emby.Server.Implementations.Library
|
|||
string sortName)
|
||||
{
|
||||
var path = Path.Combine(
|
||||
ConfigurationManager.ApplicationPaths.InternalMetadataPath,
|
||||
_configurationManager.ApplicationPaths.InternalMetadataPath,
|
||||
"views",
|
||||
_fileSystem.GetValidFilename(viewType));
|
||||
|
||||
|
@ -2147,7 +2118,7 @@ namespace Emby.Server.Implementations.Library
|
|||
if (refresh)
|
||||
{
|
||||
item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None);
|
||||
_providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.Normal);
|
||||
ProviderManager.QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.Normal);
|
||||
}
|
||||
|
||||
return item;
|
||||
|
@ -2165,7 +2136,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
var id = GetNewItemId(idValues, typeof(UserView));
|
||||
|
||||
var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N", CultureInfo.InvariantCulture));
|
||||
var path = Path.Combine(_configurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N", CultureInfo.InvariantCulture));
|
||||
|
||||
var item = GetItemById(id) as UserView;
|
||||
|
||||
|
@ -2202,7 +2173,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
if (refresh)
|
||||
{
|
||||
_providerManagerFactory().QueueRefresh(
|
||||
ProviderManager.QueueRefresh(
|
||||
item.Id,
|
||||
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||
{
|
||||
|
@ -2269,7 +2240,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
if (refresh)
|
||||
{
|
||||
_providerManagerFactory().QueueRefresh(
|
||||
ProviderManager.QueueRefresh(
|
||||
item.Id,
|
||||
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||
{
|
||||
|
@ -2303,7 +2274,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
var id = GetNewItemId(idValues, typeof(UserView));
|
||||
|
||||
var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N", CultureInfo.InvariantCulture));
|
||||
var path = Path.Combine(_configurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N", CultureInfo.InvariantCulture));
|
||||
|
||||
var item = GetItemById(id) as UserView;
|
||||
|
||||
|
@ -2346,7 +2317,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
if (refresh)
|
||||
{
|
||||
_providerManagerFactory().QueueRefresh(
|
||||
ProviderManager.QueueRefresh(
|
||||
item.Id,
|
||||
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||
{
|
||||
|
@ -2675,8 +2646,8 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
}
|
||||
|
||||
var metadataPath = ConfigurationManager.Configuration.MetadataPath;
|
||||
var metadataNetworkPath = ConfigurationManager.Configuration.MetadataNetworkPath;
|
||||
var metadataPath = _configurationManager.Configuration.MetadataPath;
|
||||
var metadataNetworkPath = _configurationManager.Configuration.MetadataNetworkPath;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(metadataPath) && !string.IsNullOrWhiteSpace(metadataNetworkPath))
|
||||
{
|
||||
|
@ -2687,7 +2658,7 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var map in ConfigurationManager.Configuration.PathSubstitutions)
|
||||
foreach (var map in _configurationManager.Configuration.PathSubstitutions)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(map.From))
|
||||
{
|
||||
|
@ -2756,7 +2727,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
public List<PersonInfo> GetPeople(InternalPeopleQuery query)
|
||||
{
|
||||
return ItemRepository.GetPeople(query);
|
||||
return _itemRepository.GetPeople(query);
|
||||
}
|
||||
|
||||
public List<PersonInfo> GetPeople(BaseItem item)
|
||||
|
@ -2779,7 +2750,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
public List<Person> GetPeopleItems(InternalPeopleQuery query)
|
||||
{
|
||||
return ItemRepository.GetPeopleNames(query).Select(i =>
|
||||
return _itemRepository.GetPeopleNames(query).Select(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -2796,7 +2767,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
public List<string> GetPeopleNames(InternalPeopleQuery query)
|
||||
{
|
||||
return ItemRepository.GetPeopleNames(query);
|
||||
return _itemRepository.GetPeopleNames(query);
|
||||
}
|
||||
|
||||
public void UpdatePeople(BaseItem item, List<PersonInfo> people)
|
||||
|
@ -2806,7 +2777,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return;
|
||||
}
|
||||
|
||||
ItemRepository.UpdatePeople(item.Id, people);
|
||||
_itemRepository.UpdatePeople(item.Id, people);
|
||||
}
|
||||
|
||||
public async Task<ItemImageInfo> ConvertImageToLocal(BaseItem item, ItemImageInfo image, int imageIndex)
|
||||
|
@ -2817,7 +2788,7 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
_logger.LogDebug("ConvertImageToLocal item {0} - image url: {1}", item.Id, url);
|
||||
|
||||
await _providerManagerFactory().SaveImage(item, url, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false);
|
||||
await ProviderManager.SaveImage(item, url, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
|
||||
|
||||
|
@ -2850,7 +2821,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
name = _fileSystem.GetValidFilename(name);
|
||||
|
||||
var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
|
||||
var virtualFolderPath = Path.Combine(rootFolderPath, name);
|
||||
while (Directory.Exists(virtualFolderPath))
|
||||
|
@ -2869,7 +2840,7 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
}
|
||||
|
||||
_libraryMonitorFactory().Stop();
|
||||
LibraryMonitor.Stop();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -2904,7 +2875,7 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
// Need to add a delay here or directory watchers may still pick up the changes
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
_libraryMonitorFactory().Start();
|
||||
LibraryMonitor.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2964,7 +2935,7 @@ namespace Emby.Server.Implementations.Library
|
|||
throw new FileNotFoundException("The network path does not exist.");
|
||||
}
|
||||
|
||||
var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
|
||||
|
||||
var shortcutFilename = Path.GetFileNameWithoutExtension(path);
|
||||
|
@ -3007,7 +2978,7 @@ namespace Emby.Server.Implementations.Library
|
|||
throw new FileNotFoundException("The network path does not exist.");
|
||||
}
|
||||
|
||||
var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
|
||||
|
||||
var libraryOptions = CollectionFolder.GetLibraryOptions(virtualFolderPath);
|
||||
|
@ -3060,7 +3031,7 @@ namespace Emby.Server.Implementations.Library
|
|||
throw new ArgumentNullException(nameof(name));
|
||||
}
|
||||
|
||||
var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
|
||||
var path = Path.Combine(rootFolderPath, name);
|
||||
|
||||
|
@ -3069,7 +3040,7 @@ namespace Emby.Server.Implementations.Library
|
|||
throw new FileNotFoundException("The media folder does not exist");
|
||||
}
|
||||
|
||||
_libraryMonitorFactory().Stop();
|
||||
LibraryMonitor.Stop();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -3089,7 +3060,7 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
// Need to add a delay here or directory watchers may still pick up the changes
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
_libraryMonitorFactory().Start();
|
||||
LibraryMonitor.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3103,7 +3074,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
var removeList = new List<NameValuePair>();
|
||||
|
||||
foreach (var contentType in ConfigurationManager.Configuration.ContentTypes)
|
||||
foreach (var contentType in _configurationManager.Configuration.ContentTypes)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(contentType.Name))
|
||||
{
|
||||
|
@ -3118,11 +3089,11 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
if (removeList.Count > 0)
|
||||
{
|
||||
ConfigurationManager.Configuration.ContentTypes = ConfigurationManager.Configuration.ContentTypes
|
||||
_configurationManager.Configuration.ContentTypes = _configurationManager.Configuration.ContentTypes
|
||||
.Except(removeList)
|
||||
.ToArray();
|
||||
.ToArray();
|
||||
|
||||
ConfigurationManager.SaveConfiguration();
|
||||
_configurationManager.SaveConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3133,7 +3104,7 @@ namespace Emby.Server.Implementations.Library
|
|||
throw new ArgumentNullException(nameof(mediaPath));
|
||||
}
|
||||
|
||||
var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
|
||||
|
||||
if (!Directory.Exists(virtualFolderPath))
|
||||
|
|
|
@ -33,13 +33,13 @@ namespace Emby.Server.Implementations.Library
|
|||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
private IMediaSourceProvider[] _providers;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IUserDataManager _userDataManager;
|
||||
private readonly Func<IMediaEncoder> _mediaEncoder;
|
||||
private ILocalizationManager _localizationManager;
|
||||
private IApplicationPaths _appPaths;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
|
||||
private IMediaSourceProvider[] _providers;
|
||||
|
||||
public MediaSourceManager(
|
||||
IItemRepository itemRepo,
|
||||
|
@ -47,16 +47,16 @@ namespace Emby.Server.Implementations.Library
|
|||
ILocalizationManager localizationManager,
|
||||
IUserManager userManager,
|
||||
ILibraryManager libraryManager,
|
||||
ILoggerFactory loggerFactory,
|
||||
ILogger<MediaSourceManager> logger,
|
||||
IJsonSerializer jsonSerializer,
|
||||
IFileSystem fileSystem,
|
||||
IUserDataManager userDataManager,
|
||||
Func<IMediaEncoder> mediaEncoder)
|
||||
IMediaEncoder mediaEncoder)
|
||||
{
|
||||
_itemRepo = itemRepo;
|
||||
_userManager = userManager;
|
||||
_libraryManager = libraryManager;
|
||||
_logger = loggerFactory.CreateLogger(nameof(MediaSourceManager));
|
||||
_logger = logger;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_fileSystem = fileSystem;
|
||||
_userDataManager = userDataManager;
|
||||
|
@ -496,7 +496,7 @@ namespace Emby.Server.Implementations.Library
|
|||
// hack - these two values were taken from LiveTVMediaSourceProvider
|
||||
string cacheKey = request.OpenToken;
|
||||
|
||||
await new LiveStreamHelper(_mediaEncoder(), _logger, _jsonSerializer, _appPaths)
|
||||
await new LiveStreamHelper(_mediaEncoder, _logger, _jsonSerializer, _appPaths)
|
||||
.AddMediaInfoWithProbe(mediaSource, isAudio, cacheKey, true, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
@ -621,7 +621,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
if (liveStreamInfo is IDirectStreamProvider)
|
||||
{
|
||||
var info = await _mediaEncoder().GetMediaInfo(new MediaInfoRequest
|
||||
var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
|
||||
{
|
||||
MediaSource = mediaSource,
|
||||
ExtractChapters = false,
|
||||
|
@ -674,7 +674,7 @@ 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,
|
||||
|
|
|
@ -17,16 +17,15 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
public class SearchEngine : ISearchEngine
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public SearchEngine(ILoggerFactory loggerFactory, ILibraryManager libraryManager, IUserManager userManager)
|
||||
public SearchEngine(ILogger<SearchEngine> logger, ILibraryManager libraryManager, IUserManager userManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
|
||||
_logger = loggerFactory.CreateLogger("SearchEngine");
|
||||
}
|
||||
|
||||
public QueryResult<SearchHintInfo> GetSearchHints(SearchQuery query)
|
||||
|
|
|
@ -28,25 +28,24 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
private readonly ILogger _logger;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IUserDataRepository _repository;
|
||||
|
||||
private Func<IUserManager> _userManager;
|
||||
|
||||
public UserDataManager(ILoggerFactory loggerFactory, IServerConfigurationManager config, Func<IUserManager> userManager)
|
||||
public UserDataManager(
|
||||
ILogger<UserDataManager> logger,
|
||||
IServerConfigurationManager config,
|
||||
IUserManager userManager,
|
||||
IUserDataRepository repository)
|
||||
{
|
||||
_logger = logger;
|
||||
_config = config;
|
||||
_logger = loggerFactory.CreateLogger(GetType().Name);
|
||||
_userManager = userManager;
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the repository.
|
||||
/// </summary>
|
||||
/// <value>The repository.</value>
|
||||
public IUserDataRepository Repository { get; set; }
|
||||
|
||||
public void SaveUserData(Guid userId, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken)
|
||||
{
|
||||
var user = _userManager().GetUserById(userId);
|
||||
var user = _userManager.GetUserById(userId);
|
||||
|
||||
SaveUserData(user, item, userData, reason, cancellationToken);
|
||||
}
|
||||
|
@ -71,7 +70,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
foreach (var key in keys)
|
||||
{
|
||||
Repository.SaveUserData(userId, key, userData, cancellationToken);
|
||||
_repository.SaveUserData(userId, key, userData, cancellationToken);
|
||||
}
|
||||
|
||||
var cacheKey = GetCacheKey(userId, item.Id);
|
||||
|
@ -96,9 +95,9 @@ namespace Emby.Server.Implementations.Library
|
|||
/// <returns></returns>
|
||||
public void SaveAllUserData(Guid userId, UserItemData[] userData, CancellationToken cancellationToken)
|
||||
{
|
||||
var user = _userManager().GetUserById(userId);
|
||||
var user = _userManager.GetUserById(userId);
|
||||
|
||||
Repository.SaveAllUserData(user.InternalId, userData, cancellationToken);
|
||||
_repository.SaveAllUserData(user.InternalId, userData, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -108,14 +107,14 @@ namespace Emby.Server.Implementations.Library
|
|||
/// <returns></returns>
|
||||
public List<UserItemData> GetAllUserData(Guid userId)
|
||||
{
|
||||
var user = _userManager().GetUserById(userId);
|
||||
var user = _userManager.GetUserById(userId);
|
||||
|
||||
return Repository.GetAllUserData(user.InternalId);
|
||||
return _repository.GetAllUserData(user.InternalId);
|
||||
}
|
||||
|
||||
public UserItemData GetUserData(Guid userId, Guid itemId, List<string> keys)
|
||||
{
|
||||
var user = _userManager().GetUserById(userId);
|
||||
var user = _userManager.GetUserById(userId);
|
||||
|
||||
return GetUserData(user, itemId, keys);
|
||||
}
|
||||
|
@ -131,7 +130,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
private UserItemData GetUserDataInternal(long internalUserId, List<string> keys)
|
||||
{
|
||||
var userData = Repository.GetUserData(internalUserId, keys);
|
||||
var userData = _repository.GetUserData(internalUserId, keys);
|
||||
|
||||
if (userData != null)
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@ using MediaBrowser.Controller.Drawing;
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
|
@ -44,22 +45,14 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
private readonly object _policySyncLock = new object();
|
||||
private readonly object _configSyncLock = new object();
|
||||
/// <summary>
|
||||
/// The logger.
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the active user repository.
|
||||
/// </summary>
|
||||
/// <value>The user repository.</value>
|
||||
private readonly ILogger _logger;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IXmlSerializer _xmlSerializer;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly INetworkManager _networkManager;
|
||||
|
||||
private readonly Func<IImageProcessor> _imageProcessorFactory;
|
||||
private readonly Func<IDtoService> _dtoServiceFactory;
|
||||
private readonly IImageProcessor _imageProcessor;
|
||||
private readonly Lazy<IDtoService> _dtoServiceFactory;
|
||||
private readonly IServerApplicationHost _appHost;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ICryptoProvider _cryptoProvider;
|
||||
|
@ -74,13 +67,15 @@ namespace Emby.Server.Implementations.Library
|
|||
private IPasswordResetProvider[] _passwordResetProviders;
|
||||
private DefaultPasswordResetProvider _defaultPasswordResetProvider;
|
||||
|
||||
private IDtoService DtoService => _dtoServiceFactory.Value;
|
||||
|
||||
public UserManager(
|
||||
ILogger<UserManager> logger,
|
||||
IUserRepository userRepository,
|
||||
IXmlSerializer xmlSerializer,
|
||||
INetworkManager networkManager,
|
||||
Func<IImageProcessor> imageProcessorFactory,
|
||||
Func<IDtoService> dtoServiceFactory,
|
||||
IImageProcessor imageProcessor,
|
||||
Lazy<IDtoService> dtoServiceFactory,
|
||||
IServerApplicationHost appHost,
|
||||
IJsonSerializer jsonSerializer,
|
||||
IFileSystem fileSystem,
|
||||
|
@ -90,7 +85,7 @@ namespace Emby.Server.Implementations.Library
|
|||
_userRepository = userRepository;
|
||||
_xmlSerializer = xmlSerializer;
|
||||
_networkManager = networkManager;
|
||||
_imageProcessorFactory = imageProcessorFactory;
|
||||
_imageProcessor = imageProcessor;
|
||||
_dtoServiceFactory = dtoServiceFactory;
|
||||
_appHost = appHost;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
|
@ -327,23 +322,19 @@ namespace Emby.Server.Implementations.Library
|
|||
if (user.Policy.IsDisabled)
|
||||
{
|
||||
_logger.LogInformation("Authentication request for {UserName} has been denied because this account is currently disabled (IP: {IP}).", username, remoteEndPoint);
|
||||
throw new AuthenticationException(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"The {0} account is currently disabled. Please consult with your administrator.",
|
||||
user.Name));
|
||||
throw new SecurityException($"The {user.Name} account is currently disabled. Please consult with your administrator.");
|
||||
}
|
||||
|
||||
if (!user.Policy.EnableRemoteAccess && !_networkManager.IsInLocalNetwork(remoteEndPoint))
|
||||
{
|
||||
_logger.LogInformation("Authentication request for {UserName} forbidden: remote access disabled and user not in local network (IP: {IP}).", username, remoteEndPoint);
|
||||
throw new AuthenticationException("Forbidden.");
|
||||
throw new SecurityException("Forbidden.");
|
||||
}
|
||||
|
||||
if (!user.IsParentalScheduleAllowed())
|
||||
{
|
||||
_logger.LogInformation("Authentication request for {UserName} is not allowed at this time due parental restrictions (IP: {IP}).", username, remoteEndPoint);
|
||||
throw new AuthenticationException("User is not allowed access at this time.");
|
||||
throw new SecurityException("User is not allowed access at this time.");
|
||||
}
|
||||
|
||||
// Update LastActivityDate and LastLoginDate, then save
|
||||
|
@ -605,7 +596,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
try
|
||||
{
|
||||
_dtoServiceFactory().AttachPrimaryImageAspectRatio(dto, user);
|
||||
DtoService.AttachPrimaryImageAspectRatio(dto, user);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -630,7 +621,7 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
try
|
||||
{
|
||||
return _imageProcessorFactory().GetImageCacheTag(item, image);
|
||||
return _imageProcessor.GetImageCacheTag(item, image);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -28,7 +28,6 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
|
||||
private readonly ILogger _logger;
|
||||
private readonly IImageProcessor _imageProcessor;
|
||||
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IApplicationHost _appHost;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
|
|
@ -49,29 +49,24 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
private readonly ILogger _logger;
|
||||
private readonly IItemRepository _itemRepo;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IUserDataManager _userDataManager;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly ITaskManager _taskManager;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly Func<IChannelManager> _channelManager;
|
||||
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly ILocalizationManager _localization;
|
||||
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IChannelManager _channelManager;
|
||||
private readonly LiveTvDtoService _tvDtoService;
|
||||
|
||||
private ILiveTvService[] _services = Array.Empty<ILiveTvService>();
|
||||
|
||||
private ITunerHost[] _tunerHosts = Array.Empty<ITunerHost>();
|
||||
private IListingsProvider[] _listingProviders = Array.Empty<IListingsProvider>();
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
public LiveTvManager(
|
||||
IServerApplicationHost appHost,
|
||||
IServerConfigurationManager config,
|
||||
ILoggerFactory loggerFactory,
|
||||
ILogger<LiveTvManager> logger,
|
||||
IItemRepository itemRepo,
|
||||
IImageProcessor imageProcessor,
|
||||
IUserDataManager userDataManager,
|
||||
IDtoService dtoService,
|
||||
IUserManager userManager,
|
||||
|
@ -80,10 +75,11 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
ILocalizationManager localization,
|
||||
IJsonSerializer jsonSerializer,
|
||||
IFileSystem fileSystem,
|
||||
Func<IChannelManager> channelManager)
|
||||
IChannelManager channelManager,
|
||||
LiveTvDtoService liveTvDtoService)
|
||||
{
|
||||
_config = config;
|
||||
_logger = loggerFactory.CreateLogger(nameof(LiveTvManager));
|
||||
_logger = logger;
|
||||
_itemRepo = itemRepo;
|
||||
_userManager = userManager;
|
||||
_libraryManager = libraryManager;
|
||||
|
@ -94,8 +90,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
_dtoService = dtoService;
|
||||
_userDataManager = userDataManager;
|
||||
_channelManager = channelManager;
|
||||
|
||||
_tvDtoService = new LiveTvDtoService(dtoService, imageProcessor, loggerFactory.CreateLogger<LiveTvDtoService>(), appHost, _libraryManager);
|
||||
_tvDtoService = liveTvDtoService;
|
||||
}
|
||||
|
||||
public event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
|
||||
|
@ -2496,7 +2491,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
.OrderBy(i => i.SortName)
|
||||
.ToList();
|
||||
|
||||
folders.AddRange(_channelManager().GetChannelsInternal(new MediaBrowser.Model.Channels.ChannelQuery
|
||||
folders.AddRange(_channelManager.GetChannelsInternal(new MediaBrowser.Model.Channels.ChannelQuery
|
||||
{
|
||||
UserId = user.Id,
|
||||
IsRecordingsFolder = true,
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
"HeaderFavoriteEpisodes": "قسمتهای مورد علاقه",
|
||||
"HeaderFavoriteShows": "سریالهای مورد علاقه",
|
||||
"HeaderFavoriteSongs": "آهنگهای مورد علاقه",
|
||||
"HeaderLiveTV": "تلویزیون زنده",
|
||||
"HeaderLiveTV": "پخش زنده",
|
||||
"HeaderNextUp": "قسمت بعدی",
|
||||
"HeaderRecordingGroups": "گروههای ضبط",
|
||||
"HomeVideos": "ویدیوهای خانگی",
|
||||
|
|
|
@ -104,13 +104,14 @@
|
|||
"TasksMaintenanceCategory": "メンテナンス",
|
||||
"TaskRefreshChannelsDescription": "ネットチャンネルの情報をリフレッシュします。",
|
||||
"TaskRefreshChannels": "チャンネルのリフレッシュ",
|
||||
"TaskCleanTranscodeDescription": "一日以上前のトランスコードを消去します。",
|
||||
"TaskCleanTranscode": "トランスコード用のディレクトリの掃除",
|
||||
"TaskCleanTranscodeDescription": "1日以上経過したトランスコードファイルを削除します。",
|
||||
"TaskCleanTranscode": "トランスコードディレクトリの削除",
|
||||
"TaskUpdatePluginsDescription": "自動更新可能なプラグインのアップデートをダウンロードしてインストールします。",
|
||||
"TaskUpdatePlugins": "プラグインの更新",
|
||||
"TaskRefreshPeopleDescription": "メディアライブラリで俳優や監督のメタデータをリフレッシュします。",
|
||||
"TaskRefreshPeople": "俳優や監督のデータのリフレッシュ",
|
||||
"TaskRefreshPeopleDescription": "メディアライブラリで俳優や監督のメタデータを更新します。",
|
||||
"TaskRefreshPeople": "俳優や監督のデータの更新",
|
||||
"TaskDownloadMissingSubtitlesDescription": "メタデータ構成に基づいて、欠落している字幕をインターネットで検索します。",
|
||||
"TaskRefreshChapterImagesDescription": "チャプターのあるビデオのサムネイルを作成します。",
|
||||
"TaskRefreshChapterImages": "チャプター画像を抽出する"
|
||||
"TaskRefreshChapterImages": "チャプター画像を抽出する",
|
||||
"TaskDownloadMissingSubtitles": "不足している字幕をダウンロードする"
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"Albums": "Albums",
|
||||
"AppDeviceValues": "App: {0}, Apparaat: {1}",
|
||||
"Application": "Applicatie",
|
||||
"Application": "Programma",
|
||||
"Artists": "Artiesten",
|
||||
"AuthenticationSucceededWithUserName": "{0} succesvol geauthenticeerd",
|
||||
"AuthenticationSucceededWithUserName": "{0} is succesvol geverifieerd",
|
||||
"Books": "Boeken",
|
||||
"CameraImageUploadedFrom": "Er is een nieuwe foto toegevoegd van {0}",
|
||||
"CameraImageUploadedFrom": "Er is een nieuwe afbeelding toegevoegd via {0}",
|
||||
"Channels": "Kanalen",
|
||||
"ChapterNameValue": "Hoofdstuk {0}",
|
||||
"Collections": "Verzamelingen",
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"HeaderLiveTV": "TV em Direto",
|
||||
"HeaderNextUp": "A Seguir",
|
||||
"HeaderRecordingGroups": "Grupos de Gravação",
|
||||
"HomeVideos": "Home videos",
|
||||
"HomeVideos": "Videos caseiros",
|
||||
"Inherit": "Herdar",
|
||||
"ItemAddedWithName": "{0} foi adicionado à biblioteca",
|
||||
"ItemRemovedWithName": "{0} foi removido da biblioteca",
|
||||
|
@ -92,5 +92,27 @@
|
|||
"UserStoppedPlayingItemWithValues": "{0} terminou a reprodução de {1} em {2}",
|
||||
"ValueHasBeenAddedToLibrary": "{0} foi adicionado à sua biblioteca multimédia",
|
||||
"ValueSpecialEpisodeName": "Especial - {0}",
|
||||
"VersionNumber": "Versão {0}"
|
||||
"VersionNumber": "Versão {0}",
|
||||
"TaskDownloadMissingSubtitlesDescription": "Procurar na internet por legendas em falta baseado na configuração de metadados.",
|
||||
"TaskDownloadMissingSubtitles": "Fazer download de legendas em falta",
|
||||
"TaskRefreshChannelsDescription": "Atualizar informação sobre canais da Internet.",
|
||||
"TaskRefreshChannels": "Atualizar Canais",
|
||||
"TaskCleanTranscodeDescription": "Apagar ficheiros de transcode com mais de um dia.",
|
||||
"TaskCleanTranscode": "Limpar a Diretoria de Transcode",
|
||||
"TaskUpdatePluginsDescription": "Faz o download e instala updates para os plugins que estão configurados para atualizar automaticamente.",
|
||||
"TaskUpdatePlugins": "Atualizar Plugins",
|
||||
"TaskRefreshPeopleDescription": "Atualizar metadados para atores e diretores na biblioteca.",
|
||||
"TaskRefreshPeople": "Atualizar Pessoas",
|
||||
"TaskCleanLogsDescription": "Apagar ficheiros de log que têm mais de {0} dias.",
|
||||
"TaskCleanLogs": "Limpar a Diretoria de Logs",
|
||||
"TaskRefreshLibraryDescription": "Scannear a biblioteca de música para novos ficheiros e atualizar os metadados.",
|
||||
"TaskRefreshLibrary": "Scannear Biblioteca de Música",
|
||||
"TaskRefreshChapterImagesDescription": "Criar thumbnails para os vídeos que têm capítulos.",
|
||||
"TaskRefreshChapterImages": "Extrair Imagens dos Capítulos",
|
||||
"TaskCleanCacheDescription": "Apagar ficheiros em cache que já não são necessários.",
|
||||
"TaskCleanCache": "Limpar Cache",
|
||||
"TasksChannelsCategory": "Canais da Internet",
|
||||
"TasksApplicationCategory": "Aplicação",
|
||||
"TasksLibraryCategory": "Biblioteca",
|
||||
"TasksMaintenanceCategory": "Manutenção"
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
"NotificationOptionAudioPlayback": "Ses çalma başladı",
|
||||
"NotificationOptionAudioPlaybackStopped": "Ses çalma durduruldu",
|
||||
"NotificationOptionCameraImageUploaded": "Kamera fotoğrafı yüklendi",
|
||||
"NotificationOptionInstallationFailed": "Yükleme başarısız oldu",
|
||||
"NotificationOptionInstallationFailed": "Kurulum hatası",
|
||||
"NotificationOptionNewLibraryContent": "Yeni içerik eklendi",
|
||||
"NotificationOptionPluginError": "Eklenti hatası",
|
||||
"NotificationOptionPluginInstalled": "Eklenti yüklendi",
|
||||
|
@ -95,7 +95,24 @@
|
|||
"VersionNumber": "Versiyon {0}",
|
||||
"TaskCleanCache": "Geçici dosya klasörünü temizle",
|
||||
"TasksChannelsCategory": "İnternet kanalları",
|
||||
"TasksApplicationCategory": "Yazılım",
|
||||
"TasksApplicationCategory": "Uygulama",
|
||||
"TasksLibraryCategory": "Kütüphane",
|
||||
"TasksMaintenanceCategory": "Onarım"
|
||||
"TasksMaintenanceCategory": "Onarım",
|
||||
"TaskRefreshPeopleDescription": "Medya kütüphanenizdeki videoların oyuncu ve yönetmen bilgilerini günceller.",
|
||||
"TaskDownloadMissingSubtitlesDescription": "Metadata ayarlarını baz alarak eksik altyazıları internette arar.",
|
||||
"TaskDownloadMissingSubtitles": "Eksik altyazıları indir",
|
||||
"TaskRefreshChannelsDescription": "Internet kanal bilgilerini yenile.",
|
||||
"TaskRefreshChannels": "Kanalları Yenile",
|
||||
"TaskCleanTranscodeDescription": "Bir günü dolmuş dönüştürme bilgisi içeren dosyaları siler.",
|
||||
"TaskCleanTranscode": "Dönüşüm Dizinini Temizle",
|
||||
"TaskUpdatePluginsDescription": "Otomatik güncellenmeye ayarlanmış eklentilerin güncellemelerini indirir ve kurar.",
|
||||
"TaskUpdatePlugins": "Eklentileri Güncelle",
|
||||
"TaskRefreshPeople": "Kullanıcıları Yenile",
|
||||
"TaskCleanLogsDescription": "{0} günden eski log dosyalarını siler.",
|
||||
"TaskCleanLogs": "Log Dizinini Temizle",
|
||||
"TaskRefreshLibraryDescription": "Medya kütüphanenize eklenen yeni dosyaları arar ve bilgileri yeniler.",
|
||||
"TaskRefreshLibrary": "Medya Kütüphanesini Tara",
|
||||
"TaskRefreshChapterImagesDescription": "Sahnelere ayrılmış videolar için küçük resimler oluştur.",
|
||||
"TaskRefreshChapterImages": "Bölüm Resimlerini Çıkar",
|
||||
"TaskCleanCacheDescription": "Sistem tarafından artık ihtiyaç duyulmayan önbellek dosyalarını siler."
|
||||
}
|
||||
|
|
|
@ -50,10 +50,10 @@
|
|||
"NotificationOptionCameraImageUploaded": "相機相片已上傳",
|
||||
"NotificationOptionInstallationFailed": "安裝失敗",
|
||||
"NotificationOptionNewLibraryContent": "已新增新內容",
|
||||
"NotificationOptionPluginError": "擴充元件錯誤",
|
||||
"NotificationOptionPluginInstalled": "擴充元件已安裝",
|
||||
"NotificationOptionPluginUninstalled": "擴充元件已移除",
|
||||
"NotificationOptionPluginUpdateInstalled": "已更新擴充元件",
|
||||
"NotificationOptionPluginError": "插件安裝錯誤",
|
||||
"NotificationOptionPluginInstalled": "插件已安裝",
|
||||
"NotificationOptionPluginUninstalled": "插件已移除",
|
||||
"NotificationOptionPluginUpdateInstalled": "插件已更新",
|
||||
"NotificationOptionServerRestartRequired": "伺服器需要重新啟動",
|
||||
"NotificationOptionTaskFailed": "排程任務失敗",
|
||||
"NotificationOptionUserLockedOut": "使用者已鎖定",
|
||||
|
@ -61,7 +61,7 @@
|
|||
"NotificationOptionVideoPlaybackStopped": "影片停止播放",
|
||||
"Photos": "相片",
|
||||
"Playlists": "播放清單",
|
||||
"Plugin": "外掛",
|
||||
"Plugin": "插件",
|
||||
"PluginInstalledWithName": "{0} 已安裝",
|
||||
"PluginUninstalledWithName": "{0} 已移除",
|
||||
"PluginUpdatedWithName": "{0} 已更新",
|
||||
|
@ -91,5 +91,27 @@
|
|||
"VersionNumber": "版本 {0}",
|
||||
"HeaderRecordingGroups": "錄製組",
|
||||
"Inherit": "繼承",
|
||||
"SubtitleDownloadFailureFromForItem": "無法為 {1} 從 {0} 下載字幕"
|
||||
"SubtitleDownloadFailureFromForItem": "無法為 {1} 從 {0} 下載字幕",
|
||||
"TaskDownloadMissingSubtitlesDescription": "在網路上透過描述資料搜尋遺失的字幕。",
|
||||
"TaskDownloadMissingSubtitles": "下載遺失的字幕",
|
||||
"TaskRefreshChannels": "重新整理頻道",
|
||||
"TaskUpdatePlugins": "更新插件",
|
||||
"TaskRefreshPeople": "重新整理人員",
|
||||
"TaskCleanLogsDescription": "刪除超過{0}天的紀錄檔案。",
|
||||
"TaskCleanLogs": "清空紀錄資料夾",
|
||||
"TaskRefreshLibraryDescription": "掃描媒體庫內新的檔案並重新整理描述資料。",
|
||||
"TaskRefreshLibrary": "掃描媒體庫",
|
||||
"TaskRefreshChapterImages": "擷取章節圖片",
|
||||
"TaskCleanCacheDescription": "刪除系統長時間不需要的快取。",
|
||||
"TaskCleanCache": "清除快取資料夾",
|
||||
"TasksLibraryCategory": "媒體庫",
|
||||
"TaskRefreshChannelsDescription": "重新整理網絡頻道資料。",
|
||||
"TaskCleanTranscodeDescription": "刪除超過一天的轉碼檔案。",
|
||||
"TaskCleanTranscode": "清除轉碼資料夾",
|
||||
"TaskUpdatePluginsDescription": "下載並安裝配置為自動更新的插件的更新。",
|
||||
"TaskRefreshPeopleDescription": "更新媒體庫中演員和導演的中繼資料。",
|
||||
"TaskRefreshChapterImagesDescription": "為有章節的視頻創建縮圖。",
|
||||
"TasksChannelsCategory": "網絡頻道",
|
||||
"TasksApplicationCategory": "應用程式",
|
||||
"TasksMaintenanceCategory": "維修"
|
||||
}
|
||||
|
|
|
@ -23,9 +23,6 @@ namespace Emby.Server.Implementations.Localization
|
|||
private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly;
|
||||
private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated" };
|
||||
|
||||
/// <summary>
|
||||
/// The _configuration manager.
|
||||
/// </summary>
|
||||
private readonly IServerConfigurationManager _configurationManager;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly ILogger _logger;
|
||||
|
|
|
@ -32,22 +32,8 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
|||
private readonly ConcurrentQueue<Tuple<Type, TaskOptions>> _taskQueue =
|
||||
new ConcurrentQueue<Tuple<Type, TaskOptions>>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the json serializer.
|
||||
/// </summary>
|
||||
/// <value>The json serializer.</value>
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the application paths.
|
||||
/// </summary>
|
||||
/// <value>The application paths.</value>
|
||||
private readonly IApplicationPaths _applicationPaths;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the logger.
|
||||
/// </summary>
|
||||
/// <value>The logger.</value>
|
||||
private readonly ILogger _logger;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
|
@ -56,17 +42,17 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
|||
/// </summary>
|
||||
/// <param name="applicationPaths">The application paths.</param>
|
||||
/// <param name="jsonSerializer">The json serializer.</param>
|
||||
/// <param name="loggerFactory">The logger factory.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="fileSystem">The filesystem manager.</param>
|
||||
public TaskManager(
|
||||
IApplicationPaths applicationPaths,
|
||||
IJsonSerializer jsonSerializer,
|
||||
ILoggerFactory loggerFactory,
|
||||
ILogger<TaskManager> logger,
|
||||
IFileSystem fileSystem)
|
||||
{
|
||||
_applicationPaths = applicationPaths;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_logger = loggerFactory.CreateLogger(nameof(TaskManager));
|
||||
_logger = logger;
|
||||
_fileSystem = fileSystem;
|
||||
|
||||
ScheduledTasks = Array.Empty<IScheduledTaskWorker>();
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace Emby.Server.Implementations.Security
|
|||
{
|
||||
public class AuthenticationRepository : BaseSqliteRepository, IAuthenticationRepository
|
||||
{
|
||||
public AuthenticationRepository(ILoggerFactory loggerFactory, IServerConfigurationManager config)
|
||||
: base(loggerFactory.CreateLogger(nameof(AuthenticationRepository)))
|
||||
public AuthenticationRepository(ILogger<AuthenticationRepository> logger, IServerConfigurationManager config)
|
||||
: base(logger)
|
||||
{
|
||||
DbFilePath = Path.Combine(config.ApplicationPaths.DataPath, "authentication.db");
|
||||
}
|
||||
|
|
|
@ -1414,7 +1414,7 @@ namespace Emby.Server.Implementations.Session
|
|||
if (user == null)
|
||||
{
|
||||
AuthenticationFailed?.Invoke(this, new GenericEventArgs<AuthenticationRequest>(request));
|
||||
throw new SecurityException("Invalid username or password entered.");
|
||||
throw new AuthenticationException("Invalid username or password entered.");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.DeviceId)
|
||||
|
|
|
@ -26,7 +26,7 @@ using Microsoft.Extensions.Logging;
|
|||
namespace Emby.Server.Implementations.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages all install, uninstall and update operations (both plugins and system).
|
||||
/// Manages all install, uninstall, and update operations for the system and individual plugins.
|
||||
/// </summary>
|
||||
public class InstallationManager : IInstallationManager
|
||||
{
|
||||
|
@ -36,7 +36,7 @@ namespace Emby.Server.Implementations.Updates
|
|||
public const string PluginManifestUrlKey = "InstallationManager:PluginManifestUrl";
|
||||
|
||||
/// <summary>
|
||||
/// The _logger.
|
||||
/// The logger.
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
|
@ -112,10 +112,10 @@ namespace Emby.Server.Implementations.Updates
|
|||
public event EventHandler<GenericEventArgs<IPlugin>> PluginUninstalled;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<GenericEventArgs<(IPlugin, PackageVersionInfo)>> PluginUpdated;
|
||||
public event EventHandler<GenericEventArgs<(IPlugin, VersionInfo)>> PluginUpdated;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled;
|
||||
public event EventHandler<GenericEventArgs<VersionInfo>> PluginInstalled;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<InstallationInfo> CompletedInstallations => _completedInstallationsInternal;
|
||||
|
@ -183,61 +183,56 @@ namespace Emby.Server.Implementations.Updates
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<PackageVersionInfo> GetCompatibleVersions(
|
||||
IEnumerable<PackageVersionInfo> availableVersions,
|
||||
Version minVersion = null,
|
||||
PackageVersionClass classification = PackageVersionClass.Release)
|
||||
public IEnumerable<VersionInfo> GetCompatibleVersions(
|
||||
IEnumerable<VersionInfo> availableVersions,
|
||||
Version minVersion = null)
|
||||
{
|
||||
var appVer = _applicationHost.ApplicationVersion;
|
||||
availableVersions = availableVersions
|
||||
.Where(x => x.classification == classification
|
||||
&& Version.Parse(x.requiredVersionStr) <= appVer);
|
||||
.Where(x => Version.Parse(x.targetAbi) <= appVer);
|
||||
|
||||
if (minVersion != null)
|
||||
{
|
||||
availableVersions = availableVersions.Where(x => x.Version >= minVersion);
|
||||
availableVersions = availableVersions.Where(x => x.version >= minVersion);
|
||||
}
|
||||
|
||||
return availableVersions.OrderByDescending(x => x.Version);
|
||||
return availableVersions.OrderByDescending(x => x.version);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<PackageVersionInfo> GetCompatibleVersions(
|
||||
public IEnumerable<VersionInfo> GetCompatibleVersions(
|
||||
IEnumerable<PackageInfo> availablePackages,
|
||||
string name = null,
|
||||
Guid guid = default,
|
||||
Version minVersion = null,
|
||||
PackageVersionClass classification = PackageVersionClass.Release)
|
||||
Version minVersion = null)
|
||||
{
|
||||
var package = FilterPackages(availablePackages, name, guid).FirstOrDefault();
|
||||
|
||||
// Package not found.
|
||||
// Package not found in repository
|
||||
if (package == null)
|
||||
{
|
||||
return Enumerable.Empty<PackageVersionInfo>();
|
||||
return Enumerable.Empty<VersionInfo>();
|
||||
}
|
||||
|
||||
return GetCompatibleVersions(
|
||||
package.versions,
|
||||
minVersion,
|
||||
classification);
|
||||
minVersion);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(CancellationToken cancellationToken = default)
|
||||
public async Task<IEnumerable<VersionInfo>> GetAvailablePluginUpdates(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var catalog = await GetAvailablePackages(cancellationToken).ConfigureAwait(false);
|
||||
return GetAvailablePluginUpdates(catalog);
|
||||
}
|
||||
|
||||
private IEnumerable<PackageVersionInfo> GetAvailablePluginUpdates(IReadOnlyList<PackageInfo> pluginCatalog)
|
||||
private IEnumerable<VersionInfo> GetAvailablePluginUpdates(IReadOnlyList<PackageInfo> pluginCatalog)
|
||||
{
|
||||
foreach (var plugin in _applicationHost.Plugins)
|
||||
{
|
||||
var compatibleversions = GetCompatibleVersions(pluginCatalog, plugin.Name, plugin.Id, plugin.Version, _applicationHost.SystemUpdateLevel);
|
||||
var version = compatibleversions.FirstOrDefault(y => y.Version > plugin.Version);
|
||||
if (version != null
|
||||
&& !CompletedInstallations.Any(x => string.Equals(x.AssemblyGuid, version.guid, StringComparison.OrdinalIgnoreCase)))
|
||||
var compatibleversions = GetCompatibleVersions(pluginCatalog, plugin.Name, plugin.Id, plugin.Version);
|
||||
var version = compatibleversions.FirstOrDefault(y => y.version > plugin.Version);
|
||||
if (version != null && !CompletedInstallations.Any(x => string.Equals(x.Guid, version.guid, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
yield return version;
|
||||
}
|
||||
|
@ -245,7 +240,7 @@ namespace Emby.Server.Implementations.Updates
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task InstallPackage(PackageVersionInfo package, CancellationToken cancellationToken)
|
||||
public async Task InstallPackage(VersionInfo package, CancellationToken cancellationToken)
|
||||
{
|
||||
if (package == null)
|
||||
{
|
||||
|
@ -254,11 +249,9 @@ namespace Emby.Server.Implementations.Updates
|
|||
|
||||
var installationInfo = new InstallationInfo
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Guid = package.guid,
|
||||
Name = package.name,
|
||||
AssemblyGuid = package.guid,
|
||||
UpdateClass = package.classification,
|
||||
Version = package.versionStr
|
||||
Version = package.version.ToString()
|
||||
};
|
||||
|
||||
var innerCancellationTokenSource = new CancellationTokenSource();
|
||||
|
@ -276,7 +269,7 @@ namespace Emby.Server.Implementations.Updates
|
|||
var installationEventArgs = new InstallationEventArgs
|
||||
{
|
||||
InstallationInfo = installationInfo,
|
||||
PackageVersionInfo = package
|
||||
VersionInfo = package
|
||||
};
|
||||
|
||||
PackageInstalling?.Invoke(this, installationEventArgs);
|
||||
|
@ -301,7 +294,7 @@ namespace Emby.Server.Implementations.Updates
|
|||
_currentInstallations.Remove(tuple);
|
||||
}
|
||||
|
||||
_logger.LogInformation("Package installation cancelled: {0} {1}", package.name, package.versionStr);
|
||||
_logger.LogInformation("Package installation cancelled: {0} {1}", package.name, package.version);
|
||||
|
||||
PackageInstallationCancelled?.Invoke(this, installationEventArgs);
|
||||
|
||||
|
@ -337,7 +330,7 @@ namespace Emby.Server.Implementations.Updates
|
|||
/// <param name="package">The package.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns><see cref="Task" />.</returns>
|
||||
private async Task InstallPackageInternal(PackageVersionInfo package, CancellationToken cancellationToken)
|
||||
private async Task InstallPackageInternal(VersionInfo package, CancellationToken cancellationToken)
|
||||
{
|
||||
// Set last update time if we were installed before
|
||||
IPlugin plugin = _applicationHost.Plugins.FirstOrDefault(p => string.Equals(p.Id.ToString(), package.guid, StringComparison.OrdinalIgnoreCase))
|
||||
|
@ -349,26 +342,26 @@ namespace Emby.Server.Implementations.Updates
|
|||
// Do plugin-specific processing
|
||||
if (plugin == null)
|
||||
{
|
||||
_logger.LogInformation("New plugin installed: {0} {1} {2}", package.name, package.versionStr ?? string.Empty, package.classification);
|
||||
_logger.LogInformation("New plugin installed: {0} {1} {2}", package.name, package.version);
|
||||
|
||||
PluginInstalled?.Invoke(this, new GenericEventArgs<PackageVersionInfo>(package));
|
||||
PluginInstalled?.Invoke(this, new GenericEventArgs<VersionInfo>(package));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("Plugin updated: {0} {1} {2}", package.name, package.versionStr ?? string.Empty, package.classification);
|
||||
_logger.LogInformation("Plugin updated: {0} {1} {2}", package.name, package.version);
|
||||
|
||||
PluginUpdated?.Invoke(this, new GenericEventArgs<(IPlugin, PackageVersionInfo)>((plugin, package)));
|
||||
PluginUpdated?.Invoke(this, new GenericEventArgs<(IPlugin, VersionInfo)>((plugin, package)));
|
||||
}
|
||||
|
||||
_applicationHost.NotifyPendingRestart();
|
||||
}
|
||||
|
||||
private async Task PerformPackageInstallation(PackageVersionInfo package, CancellationToken cancellationToken)
|
||||
private async Task PerformPackageInstallation(VersionInfo package, CancellationToken cancellationToken)
|
||||
{
|
||||
var extension = Path.GetExtension(package.targetFilename);
|
||||
var extension = Path.GetExtension(package.filename);
|
||||
if (!string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_logger.LogError("Only zip packages are supported. {Filename} is not a zip archive.", package.targetFilename);
|
||||
_logger.LogError("Only zip packages are supported. {Filename} is not a zip archive.", package.filename);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -415,7 +408,7 @@ namespace Emby.Server.Implementations.Updates
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uninstalls a plugin
|
||||
/// Uninstalls a plugin.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The plugin.</param>
|
||||
public void UninstallPlugin(IPlugin plugin)
|
||||
|
@ -473,7 +466,7 @@ namespace Emby.Server.Implementations.Updates
|
|||
{
|
||||
lock (_currentInstallationsLock)
|
||||
{
|
||||
var install = _currentInstallations.Find(x => x.info.Id == id);
|
||||
var install = _currentInstallations.Find(x => x.info.Guid == id.ToString());
|
||||
if (install == default((InstallationInfo, CancellationTokenSource)))
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{DFBEFB4C-DA19-4143-98B7-27320C7F7163}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{154872D9-6C12-4007-96E3-8F70A58386CE}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace Jellyfin.Drawing.Skia
|
|||
{
|
||||
paint.Color = SKColor.Parse("#CC00A4DC");
|
||||
paint.Style = SKPaintStyle.Fill;
|
||||
canvas.DrawCircle((float)x, OffsetFromTopRightCorner, 20, paint);
|
||||
canvas.DrawCircle(x, OffsetFromTopRightCorner, 20, paint);
|
||||
}
|
||||
|
||||
using (var paint = new SKPaint())
|
||||
|
@ -39,16 +39,13 @@ namespace Jellyfin.Drawing.Skia
|
|||
|
||||
// or:
|
||||
// var emojiChar = 0x1F680;
|
||||
var text = "✔️";
|
||||
var emojiChar = StringUtilities.GetUnicodeCharacterCode(text, SKTextEncoding.Utf32);
|
||||
const string Text = "✔️";
|
||||
var emojiChar = StringUtilities.GetUnicodeCharacterCode(Text, SKTextEncoding.Utf32);
|
||||
|
||||
// ask the font manager for a font with that character
|
||||
var fontManager = SKFontManager.Default;
|
||||
var emojiTypeface = fontManager.MatchCharacter(emojiChar);
|
||||
paint.Typeface = SKFontManager.Default.MatchCharacter(emojiChar);
|
||||
|
||||
paint.Typeface = emojiTypeface;
|
||||
|
||||
canvas.DrawText(text, (float)x - 20, OffsetFromTopRightCorner + 12, paint);
|
||||
canvas.DrawText(Text, (float)x - 20, OffsetFromTopRightCorner + 12, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,12 +78,21 @@ namespace Jellyfin.Drawing.Skia
|
|||
=> new HashSet<ImageFormat>() { ImageFormat.Webp, ImageFormat.Jpg, ImageFormat.Png };
|
||||
|
||||
/// <summary>
|
||||
/// Test to determine if the native lib is available.
|
||||
/// Check if the native lib is available.
|
||||
/// </summary>
|
||||
public static void TestSkia()
|
||||
/// <returns>True if the native lib is available, otherwise false.</returns>
|
||||
public static bool IsNativeLibAvailable()
|
||||
{
|
||||
// test an operation that requires the native library
|
||||
SKPMColor.PreMultiply(SKColors.Black);
|
||||
try
|
||||
{
|
||||
// test an operation that requires the native library
|
||||
SKPMColor.PreMultiply(SKColors.Black);
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsTransparent(SKColor color)
|
||||
|
@ -205,11 +214,6 @@ namespace Jellyfin.Drawing.Skia
|
|||
/// <exception cref="SkiaCodecException">The file at the specified path could not be used to generate a codec.</exception>
|
||||
public ImageDimensions GetImageSize(string path)
|
||||
{
|
||||
if (path == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
}
|
||||
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
throw new FileNotFoundException("File not found", path);
|
||||
|
@ -297,7 +301,7 @@ namespace Jellyfin.Drawing.Skia
|
|||
/// <param name="orientation">The orientation of the image.</param>
|
||||
/// <param name="origin">The detected origin of the image.</param>
|
||||
/// <returns>The resulting bitmap of the image.</returns>
|
||||
internal SKBitmap Decode(string path, bool forceCleanBitmap, ImageOrientation? orientation, out SKEncodedOrigin origin)
|
||||
internal SKBitmap? Decode(string path, bool forceCleanBitmap, ImageOrientation? orientation, out SKEncodedOrigin origin)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
|
@ -348,12 +352,17 @@ namespace Jellyfin.Drawing.Skia
|
|||
return resultBitmap;
|
||||
}
|
||||
|
||||
private SKBitmap GetBitmap(string path, bool cropWhitespace, bool forceAnalyzeBitmap, ImageOrientation? orientation, out SKEncodedOrigin origin)
|
||||
private SKBitmap? GetBitmap(string path, bool cropWhitespace, bool forceAnalyzeBitmap, ImageOrientation? orientation, out SKEncodedOrigin origin)
|
||||
{
|
||||
if (cropWhitespace)
|
||||
{
|
||||
using (var bitmap = Decode(path, forceAnalyzeBitmap, orientation, out origin))
|
||||
{
|
||||
if (bitmap == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return CropWhiteSpace(bitmap);
|
||||
}
|
||||
}
|
||||
|
@ -361,13 +370,11 @@ namespace Jellyfin.Drawing.Skia
|
|||
return Decode(path, forceAnalyzeBitmap, orientation, out origin);
|
||||
}
|
||||
|
||||
private SKBitmap GetBitmap(string path, bool cropWhitespace, bool autoOrient, ImageOrientation? orientation)
|
||||
private SKBitmap? GetBitmap(string path, bool cropWhitespace, bool autoOrient, ImageOrientation? orientation)
|
||||
{
|
||||
SKEncodedOrigin origin;
|
||||
|
||||
if (autoOrient)
|
||||
{
|
||||
var bitmap = GetBitmap(path, cropWhitespace, true, orientation, out origin);
|
||||
var bitmap = GetBitmap(path, cropWhitespace, true, orientation, out var origin);
|
||||
|
||||
if (bitmap != null && origin != SKEncodedOrigin.TopLeft)
|
||||
{
|
||||
|
@ -380,7 +387,7 @@ namespace Jellyfin.Drawing.Skia
|
|||
return bitmap;
|
||||
}
|
||||
|
||||
return GetBitmap(path, cropWhitespace, false, orientation, out origin);
|
||||
return GetBitmap(path, cropWhitespace, false, orientation, out _);
|
||||
}
|
||||
|
||||
private SKBitmap OrientImage(SKBitmap bitmap, SKEncodedOrigin origin)
|
||||
|
@ -517,14 +524,14 @@ namespace Jellyfin.Drawing.Skia
|
|||
/// <inheritdoc/>
|
||||
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(inputPath))
|
||||
if (inputPath.Length == 0)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(inputPath));
|
||||
throw new ArgumentException("String can't be empty.", nameof(inputPath));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(inputPath))
|
||||
if (outputPath.Length == 0)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(outputPath));
|
||||
throw new ArgumentException("String can't be empty.", nameof(outputPath));
|
||||
}
|
||||
|
||||
var skiaOutputFormat = GetImageFormat(selectedOutputFormat);
|
||||
|
@ -538,7 +545,7 @@ namespace Jellyfin.Drawing.Skia
|
|||
{
|
||||
if (bitmap == null)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException($"Skia unable to read image {inputPath}");
|
||||
throw new InvalidDataException($"Skia unable to read image {inputPath}");
|
||||
}
|
||||
|
||||
var originalImageSize = new ImageDimensions(bitmap.Width, bitmap.Height);
|
||||
|
|
|
@ -120,13 +120,13 @@ namespace Jellyfin.Drawing.Skia
|
|||
}
|
||||
|
||||
// resize to the same aspect as the original
|
||||
int iWidth = (int)Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height);
|
||||
int iWidth = Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height);
|
||||
using (var resizeBitmap = new SKBitmap(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType))
|
||||
{
|
||||
currentBitmap.ScalePixels(resizeBitmap, SKFilterQuality.High);
|
||||
|
||||
// crop image
|
||||
int ix = (int)Math.Abs((iWidth - iSlice) / 2);
|
||||
int ix = Math.Abs((iWidth - iSlice) / 2);
|
||||
using (var image = SKImage.FromBitmap(resizeBitmap))
|
||||
using (var subset = image.Subset(SKRectI.Create(ix, 0, iSlice, iHeight)))
|
||||
{
|
||||
|
@ -141,10 +141,10 @@ namespace Jellyfin.Drawing.Skia
|
|||
return bitmap;
|
||||
}
|
||||
|
||||
private SKBitmap GetNextValidImage(string[] paths, int currentIndex, out int newIndex)
|
||||
private SKBitmap? GetNextValidImage(string[] paths, int currentIndex, out int newIndex)
|
||||
{
|
||||
var imagesTested = new Dictionary<int, int>();
|
||||
SKBitmap bitmap = null;
|
||||
SKBitmap? bitmap = null;
|
||||
|
||||
while (imagesTested.Count < paths.Length)
|
||||
{
|
||||
|
@ -153,7 +153,7 @@ namespace Jellyfin.Drawing.Skia
|
|||
currentIndex = 0;
|
||||
}
|
||||
|
||||
bitmap = _skiaEncoder.Decode(paths[currentIndex], false, null, out var origin);
|
||||
bitmap = _skiaEncoder.Decode(paths[currentIndex], false, null, out _);
|
||||
|
||||
imagesTested[currentIndex] = 0;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Jellyfin.Drawing.Skia
|
|||
{
|
||||
paint.Color = SKColor.Parse("#CC00A4DC");
|
||||
paint.Style = SKPaintStyle.Fill;
|
||||
canvas.DrawCircle((float)x, OffsetFromTopRightCorner, 20, paint);
|
||||
canvas.DrawCircle(x, OffsetFromTopRightCorner, 20, paint);
|
||||
}
|
||||
|
||||
using (var paint = new SKPaint())
|
||||
|
@ -61,7 +61,7 @@ namespace Jellyfin.Drawing.Skia
|
|||
paint.TextSize = 18;
|
||||
}
|
||||
|
||||
canvas.DrawText(text, (float)x, y, paint);
|
||||
canvas.DrawText(text, x, y, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Emby.Drawing;
|
||||
using Emby.Server.Implementations;
|
||||
using Jellyfin.Drawing.Skia;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Model.IO;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Server
|
||||
|
@ -20,27 +24,40 @@ namespace Jellyfin.Server
|
|||
/// <param name="loggerFactory">The <see cref="ILoggerFactory" /> to be used by the <see cref="CoreAppHost" />.</param>
|
||||
/// <param name="options">The <see cref="StartupOptions" /> to be used by the <see cref="CoreAppHost" />.</param>
|
||||
/// <param name="fileSystem">The <see cref="IFileSystem" /> to be used by the <see cref="CoreAppHost" />.</param>
|
||||
/// <param name="imageEncoder">The <see cref="IImageEncoder" /> to be used by the <see cref="CoreAppHost" />.</param>
|
||||
/// <param name="networkManager">The <see cref="INetworkManager" /> to be used by the <see cref="CoreAppHost" />.</param>
|
||||
public CoreAppHost(
|
||||
ServerApplicationPaths applicationPaths,
|
||||
ILoggerFactory loggerFactory,
|
||||
StartupOptions options,
|
||||
IFileSystem fileSystem,
|
||||
IImageEncoder imageEncoder,
|
||||
INetworkManager networkManager)
|
||||
: base(
|
||||
applicationPaths,
|
||||
loggerFactory,
|
||||
options,
|
||||
fileSystem,
|
||||
imageEncoder,
|
||||
networkManager)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanSelfRestart => StartupOptions.RestartPath != null;
|
||||
/// <inheritdoc/>
|
||||
protected override void RegisterServices(IServiceCollection serviceCollection)
|
||||
{
|
||||
// Register an image encoder
|
||||
bool useSkiaEncoder = SkiaEncoder.IsNativeLibAvailable();
|
||||
Type imageEncoderType = useSkiaEncoder
|
||||
? typeof(SkiaEncoder)
|
||||
: typeof(NullImageEncoder);
|
||||
serviceCollection.AddSingleton(typeof(IImageEncoder), imageEncoderType);
|
||||
|
||||
// Log a warning if the Skia encoder could not be used
|
||||
if (!useSkiaEncoder)
|
||||
{
|
||||
Logger.LogWarning($"Skia not available. Will fallback to {nameof(NullImageEncoder)}.");
|
||||
}
|
||||
|
||||
base.RegisterServices(serviceCollection);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void RestartInternal() => Program.Restart();
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{07E39F42-A2C6-4B32-AF8C-725F957A73FF}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>jellyfin</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
|
|
|
@ -168,7 +168,6 @@ namespace Jellyfin.Server
|
|||
_loggerFactory,
|
||||
options,
|
||||
new ManagedFileSystem(_loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths),
|
||||
GetImageEncoder(appPaths),
|
||||
new NetworkManager(_loggerFactory.CreateLogger<NetworkManager>()));
|
||||
|
||||
try
|
||||
|
@ -188,14 +187,13 @@ namespace Jellyfin.Server
|
|||
}
|
||||
|
||||
ServiceCollection serviceCollection = new ServiceCollection();
|
||||
await appHost.InitAsync(serviceCollection, startupConfig).ConfigureAwait(false);
|
||||
appHost.Init(serviceCollection);
|
||||
|
||||
var webHost = new WebHostBuilder().ConfigureWebHostBuilder(appHost, serviceCollection, options, startupConfig, appPaths).Build();
|
||||
|
||||
// Re-use the web host service provider in the app host since ASP.NET doesn't allow a custom service collection.
|
||||
appHost.ServiceProvider = webHost.Services;
|
||||
appHost.InitializeServices();
|
||||
appHost.FindParts();
|
||||
await appHost.InitializeServices().ConfigureAwait(false);
|
||||
Migrations.MigrationRunner.Run(appHost, _loggerFactory);
|
||||
|
||||
try
|
||||
|
@ -598,25 +596,6 @@ namespace Jellyfin.Server
|
|||
}
|
||||
}
|
||||
|
||||
private static IImageEncoder GetImageEncoder(IApplicationPaths appPaths)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Test if the native lib is available
|
||||
SkiaEncoder.TestSkia();
|
||||
|
||||
return new SkiaEncoder(
|
||||
_loggerFactory.CreateLogger<SkiaEncoder>(),
|
||||
appPaths);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, $"Skia not available. Will fallback to {nameof(NullImageEncoder)}.");
|
||||
}
|
||||
|
||||
return new NullImageEncoder();
|
||||
}
|
||||
|
||||
private static void StartNewInstance(StartupOptions options)
|
||||
{
|
||||
_logger.LogInformation("Starting new instance");
|
||||
|
|
|
@ -332,7 +332,8 @@ namespace MediaBrowser.Api.Images
|
|||
var fileInfo = _fileSystem.GetFileInfo(info.Path);
|
||||
length = fileInfo.Length;
|
||||
|
||||
ImageDimensions size = _imageProcessor.GetImageDimensions(item, info, true);
|
||||
ImageDimensions size = _imageProcessor.GetImageDimensions(item, info);
|
||||
_libraryManager.UpdateImages(item);
|
||||
width = size.Width;
|
||||
height = size.Height;
|
||||
|
||||
|
@ -606,6 +607,12 @@ namespace MediaBrowser.Api.Images
|
|||
IDictionary<string, string> headers,
|
||||
bool isHeadRequest)
|
||||
{
|
||||
if (!image.IsLocalFile)
|
||||
{
|
||||
item ??= _libraryManager.GetItemById(itemId);
|
||||
image = await _libraryManager.ConvertImageToLocal(item, image, request.Index ?? 0).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var options = new ImageProcessingOptions
|
||||
{
|
||||
CropWhiteSpace = cropwhitespace,
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{4FD51AC5-2C16-4308-A993-C3A84F3B4582}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
||||
|
|
|
@ -42,23 +42,6 @@ namespace MediaBrowser.Api
|
|||
[Authenticated]
|
||||
public class GetPackages : IReturn<PackageInfo[]>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[ApiMember(Name = "PackageType", Description = "Optional package type filter (System/UserInstalled)", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string PackageType { get; set; }
|
||||
|
||||
[ApiMember(Name = "TargetSystems", Description = "Optional. Filter by target system type. Allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string TargetSystems { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsPremium", Description = "Optional. Filter by premium status", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsPremium { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsAdult", Description = "Optional. Filter by package that contain adult content.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsAdult { get; set; }
|
||||
|
||||
public bool? IsAppStoreEnabled { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -88,13 +71,6 @@ namespace MediaBrowser.Api
|
|||
/// <value>The version.</value>
|
||||
[ApiMember(Name = "Version", Description = "Optional version. Defaults to latest version.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string Version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the update class.
|
||||
/// </summary>
|
||||
/// <value>The update class.</value>
|
||||
[ApiMember(Name = "UpdateClass", Description = "Optional update class (Dev, Beta, Release). Defaults to Release.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public PackageVersionClass UpdateClass { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -154,23 +130,6 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
IEnumerable<PackageInfo> packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false);
|
||||
|
||||
if (!string.IsNullOrEmpty(request.TargetSystems))
|
||||
{
|
||||
var apps = request.TargetSystems.Split(',').Select(i => (PackageTargetSystem)Enum.Parse(typeof(PackageTargetSystem), i, true));
|
||||
|
||||
packages = packages.Where(p => apps.Contains(p.targetSystem));
|
||||
}
|
||||
|
||||
if (request.IsAdult.HasValue)
|
||||
{
|
||||
packages = packages.Where(p => p.adult == request.IsAdult.Value);
|
||||
}
|
||||
|
||||
if (request.IsAppStoreEnabled.HasValue)
|
||||
{
|
||||
packages = packages.Where(p => p.enableInAppStore == request.IsAppStoreEnabled.Value);
|
||||
}
|
||||
|
||||
return ToOptimizedResult(packages.ToArray());
|
||||
}
|
||||
|
||||
|
@ -186,8 +145,7 @@ namespace MediaBrowser.Api
|
|||
packages,
|
||||
request.Name,
|
||||
string.IsNullOrEmpty(request.AssemblyGuid) ? Guid.Empty : Guid.Parse(request.AssemblyGuid),
|
||||
string.IsNullOrEmpty(request.Version) ? null : Version.Parse(request.Version),
|
||||
request.UpdateClass).FirstOrDefault();
|
||||
string.IsNullOrEmpty(request.Version) ? null : Version.Parse(request.Version)).FirstOrDefault();
|
||||
|
||||
if (package == null)
|
||||
{
|
||||
|
|
|
@ -426,7 +426,7 @@ namespace MediaBrowser.Api
|
|||
catch (SecurityException e)
|
||||
{
|
||||
// rethrow adding IP address to message
|
||||
throw new SecurityException($"[{Request.RemoteIp}] {e.Message}");
|
||||
throw new SecurityException($"[{Request.RemoteIp}] {e.Message}", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Model.Updates;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace MediaBrowser.Common
|
||||
|
@ -48,12 +46,6 @@ namespace MediaBrowser.Common
|
|||
/// <value><c>true</c> if this instance can self restart; otherwise, <c>false</c>.</value>
|
||||
bool CanSelfRestart { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version class of the system.
|
||||
/// </summary>
|
||||
/// <value><see cref="PackageVersionClass.Release" /> or <see cref="PackageVersionClass.Beta" />.</value>
|
||||
PackageVersionClass SystemUpdateLevel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the application version.
|
||||
/// </summary>
|
||||
|
@ -125,9 +117,7 @@ namespace MediaBrowser.Common
|
|||
/// Initializes this instance.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The service collection.</param>
|
||||
/// <param name="startupConfig">The configuration to use for initialization.</param>
|
||||
/// <returns>A task.</returns>
|
||||
Task InitAsync(IServiceCollection serviceCollection, IConfiguration startupConfig);
|
||||
void Init(IServiceCollection serviceCollection);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the instance.
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{9142EEFA-7570-41E1-BFCC-468BB571AF2F}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Authors>Jellyfin Contributors</Authors>
|
||||
<PackageId>Jellyfin.Common</PackageId>
|
||||
|
|
|
@ -67,7 +67,7 @@ namespace MediaBrowser.Common.Plugins
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when just before the plugin is uninstalled from the server.
|
||||
/// Called just before the plugin is uninstalled from the server.
|
||||
/// </summary>
|
||||
public virtual void OnUninstalling()
|
||||
{
|
||||
|
@ -101,7 +101,7 @@ namespace MediaBrowser.Common.Plugins
|
|||
private readonly object _configurationSyncLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// The save lock.
|
||||
/// The configuration save lock.
|
||||
/// </summary>
|
||||
private readonly object _configurationSaveLock = new object();
|
||||
|
||||
|
@ -148,7 +148,7 @@ namespace MediaBrowser.Common.Plugins
|
|||
protected string AssemblyFileName => Path.GetFileName(AssemblyFilePath);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the plugin's configuration.
|
||||
/// Gets or sets the plugin configuration.
|
||||
/// </summary>
|
||||
/// <value>The configuration.</value>
|
||||
public TConfigurationType Configuration
|
||||
|
@ -186,7 +186,7 @@ namespace MediaBrowser.Common.Plugins
|
|||
public string ConfigurationFilePath => Path.Combine(ApplicationPaths.PluginConfigurationsPath, ConfigurationFileName);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin's configuration.
|
||||
/// Gets the plugin configuration.
|
||||
/// </summary>
|
||||
/// <value>The configuration.</value>
|
||||
BasePluginConfiguration IHasPluginConfiguration.Configuration => Configuration;
|
||||
|
|
|
@ -28,12 +28,12 @@ namespace MediaBrowser.Common.Updates
|
|||
/// <summary>
|
||||
/// Occurs when a plugin is updated.
|
||||
/// </summary>
|
||||
event EventHandler<GenericEventArgs<(IPlugin, PackageVersionInfo)>> PluginUpdated;
|
||||
event EventHandler<GenericEventArgs<(IPlugin, VersionInfo)>> PluginUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a plugin is installed.
|
||||
/// </summary>
|
||||
event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled;
|
||||
event EventHandler<GenericEventArgs<VersionInfo>> PluginInstalled;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the completed installations.
|
||||
|
@ -64,12 +64,10 @@ namespace MediaBrowser.Common.Updates
|
|||
/// </summary>
|
||||
/// <param name="availableVersions">The available version of the plugin.</param>
|
||||
/// <param name="minVersion">The minimum required version of the plugin.</param>
|
||||
/// <param name="classification">The classification of updates.</param>
|
||||
/// <returns>All compatible versions ordered from newest to oldest.</returns>
|
||||
IEnumerable<PackageVersionInfo> GetCompatibleVersions(
|
||||
IEnumerable<PackageVersionInfo> availableVersions,
|
||||
Version minVersion = null,
|
||||
PackageVersionClass classification = PackageVersionClass.Release);
|
||||
IEnumerable<VersionInfo> GetCompatibleVersions(
|
||||
IEnumerable<VersionInfo> availableVersions,
|
||||
Version minVersion = null);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all compatible versions ordered from newest to oldest.
|
||||
|
@ -78,21 +76,19 @@ namespace MediaBrowser.Common.Updates
|
|||
/// <param name="name">The name.</param>
|
||||
/// <param name="guid">The guid of the plugin.</param>
|
||||
/// <param name="minVersion">The minimum required version of the plugin.</param>
|
||||
/// <param name="classification">The classification.</param>
|
||||
/// <returns>All compatible versions ordered from newest to oldest.</returns>
|
||||
IEnumerable<PackageVersionInfo> GetCompatibleVersions(
|
||||
IEnumerable<VersionInfo> GetCompatibleVersions(
|
||||
IEnumerable<PackageInfo> availablePackages,
|
||||
string name = null,
|
||||
Guid guid = default,
|
||||
Version minVersion = null,
|
||||
PackageVersionClass classification = PackageVersionClass.Release);
|
||||
Version minVersion = null);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the available plugin updates.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The available plugin updates.</returns>
|
||||
Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(CancellationToken cancellationToken = default);
|
||||
Task<IEnumerable<VersionInfo>> GetAvailablePluginUpdates(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Installs the package.
|
||||
|
@ -100,7 +96,7 @@ namespace MediaBrowser.Common.Updates
|
|||
/// <param name="package">The package.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns><see cref="Task" />.</returns>
|
||||
Task InstallPackage(PackageVersionInfo package, CancellationToken cancellationToken = default);
|
||||
Task InstallPackage(VersionInfo package, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Uninstalls a plugin.
|
||||
|
|
|
@ -8,6 +8,6 @@ namespace MediaBrowser.Common.Updates
|
|||
{
|
||||
public InstallationInfo InstallationInfo { get; set; }
|
||||
|
||||
public PackageVersionInfo PackageVersionInfo { get; set; }
|
||||
public VersionInfo VersionInfo { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,23 +7,29 @@ namespace MediaBrowser.Controller.Authentication
|
|||
/// </summary>
|
||||
public class AuthenticationException : Exception
|
||||
{
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthenticationException"/> class.
|
||||
/// </summary>
|
||||
public AuthenticationException() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthenticationException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public AuthenticationException(string message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthenticationException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public AuthenticationException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,15 +40,6 @@ namespace MediaBrowser.Controller.Drawing
|
|||
/// <returns>ImageDimensions</returns>
|
||||
ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dimensions of the image.
|
||||
/// </summary>
|
||||
/// <param name="item">The base item.</param>
|
||||
/// <param name="info">The information.</param>
|
||||
/// <param name="updateItem">Whether or not the item info should be updated.</param>
|
||||
/// <returns>ImageDimensions</returns>
|
||||
ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image cache tag.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Authors>Jellyfin Contributors</Authors>
|
||||
<PackageId>Jellyfin.Controller</PackageId>
|
||||
|
|
|
@ -459,7 +459,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
{
|
||||
var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions);
|
||||
var outputVideoCodec = GetVideoEncoder(state, encodingOptions);
|
||||
|
||||
|
||||
var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
||||
|
||||
if (!hasTextSubs)
|
||||
|
|
|
@ -2,20 +2,36 @@ using System;
|
|||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when a user is authenticated, but not authorized to access a requested resource.
|
||||
/// </summary>
|
||||
public class SecurityException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SecurityException"/> class.
|
||||
/// </summary>
|
||||
public SecurityException()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SecurityException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public SecurityException(string message)
|
||||
: base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SecurityExceptionType SecurityExceptionType { get; set; }
|
||||
}
|
||||
|
||||
public enum SecurityExceptionType
|
||||
{
|
||||
Unauthenticated = 0,
|
||||
ParentalControl = 1
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SecurityException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public SecurityException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{7EF9F3E0-697D-42F3-A08F-19DEB5F84392}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||
|
|
|
@ -19,7 +19,6 @@ using MediaBrowser.Model.Globalization;
|
|||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using MediaBrowser.Model.System;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics;
|
||||
|
||||
|
@ -39,8 +38,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
private readonly IServerConfigurationManager _configurationManager;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ILocalizationManager _localization;
|
||||
private readonly Func<ISubtitleEncoder> _subtitleEncoder;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly Lazy<EncodingHelper> _encodingHelperFactory;
|
||||
private readonly string _startupOptionFFmpegPath;
|
||||
|
||||
private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(2, 2);
|
||||
|
@ -48,8 +46,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
private readonly object _runningProcessesLock = new object();
|
||||
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
|
||||
|
||||
private EncodingHelper _encodingHelper;
|
||||
|
||||
private string _ffmpegPath;
|
||||
private string _ffprobePath;
|
||||
|
||||
|
@ -58,23 +54,18 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
IServerConfigurationManager configurationManager,
|
||||
IFileSystem fileSystem,
|
||||
ILocalizationManager localization,
|
||||
Func<ISubtitleEncoder> subtitleEncoder,
|
||||
IConfiguration configuration,
|
||||
Lazy<EncodingHelper> encodingHelperFactory,
|
||||
string startupOptionsFFmpegPath)
|
||||
{
|
||||
_logger = logger;
|
||||
_configurationManager = configurationManager;
|
||||
_fileSystem = fileSystem;
|
||||
_localization = localization;
|
||||
_encodingHelperFactory = encodingHelperFactory;
|
||||
_startupOptionFFmpegPath = startupOptionsFFmpegPath;
|
||||
_subtitleEncoder = subtitleEncoder;
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
private EncodingHelper EncodingHelper
|
||||
=> LazyInitializer.EnsureInitialized(
|
||||
ref _encodingHelper,
|
||||
() => new EncodingHelper(this, _fileSystem, _subtitleEncoder(), _configuration));
|
||||
private EncodingHelper EncodingHelper => _encodingHelperFactory.Value;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string EncoderPath => _ffmpegPath;
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{960295EE-4AF4-4440-A525-B4C295B01A61}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Authors>Jellyfin Contributors</Authors>
|
||||
<PackageId>Jellyfin.Model</PackageId>
|
||||
|
|
|
@ -8,17 +8,17 @@ namespace MediaBrowser.Model.Services
|
|||
{
|
||||
/// <summary>
|
||||
/// Order in which Request Filters are executed.
|
||||
/// <0 Executed before global request filters
|
||||
/// >0 Executed after global request filters
|
||||
/// <0 Executed before global request filters.
|
||||
/// >0 Executed after global request filters.
|
||||
/// </summary>
|
||||
int Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The request filter is executed before the service.
|
||||
/// </summary>
|
||||
/// <param name="req">The http request wrapper</param>
|
||||
/// <param name="res">The http response wrapper</param>
|
||||
/// <param name="requestDto">The request DTO</param>
|
||||
/// <param name="req">The http request wrapper.</param>
|
||||
/// <param name="res">The http response wrapper.</param>
|
||||
/// <param name="requestDto">The request DTO.</param>
|
||||
void RequestFilter(IRequest req, HttpResponse res, object requestDto);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,6 @@ namespace MediaBrowser.Model.System
|
|||
/// </summary>
|
||||
public class SystemInfo : PublicSystemInfo
|
||||
{
|
||||
public PackageVersionClass SystemUpdateLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the display name of the operating system.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
namespace MediaBrowser.Model.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Class CheckForUpdateResult.
|
||||
/// </summary>
|
||||
public class CheckForUpdateResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is update available.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is update available; otherwise, <c>false</c>.</value>
|
||||
public bool IsUpdateAvailable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the available version.
|
||||
/// </summary>
|
||||
/// <value>The available version.</value>
|
||||
public string AvailableVersion
|
||||
{
|
||||
get => Package != null ? Package.versionStr : "0.0.0.1";
|
||||
set { } // need this for the serializer
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or sets package information for an available update
|
||||
/// </summary>
|
||||
public PackageVersionInfo Package { get; set; }
|
||||
}
|
||||
}
|
|
@ -8,10 +8,10 @@ namespace MediaBrowser.Model.Updates
|
|||
public class InstallationInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// Gets or sets the guid.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
public Guid Id { get; set; }
|
||||
/// <value>The guid.</value>
|
||||
public string Guid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
|
@ -19,22 +19,10 @@ namespace MediaBrowser.Model.Updates
|
|||
/// <value>The name.</value>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the assembly guid.
|
||||
/// </summary>
|
||||
/// <value>The guid of the assembly.</value>
|
||||
public string AssemblyGuid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the version.
|
||||
/// </summary>
|
||||
/// <value>The version.</value>
|
||||
public string Version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the update class.
|
||||
/// </summary>
|
||||
/// <value>The update class.</value>
|
||||
public PackageVersionClass UpdateClass { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,6 @@ namespace MediaBrowser.Model.Updates
|
|||
/// </summary>
|
||||
public class PackageInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The internal id of this package.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
public string id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
|
@ -21,59 +15,17 @@ namespace MediaBrowser.Model.Updates
|
|||
public string name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the short description.
|
||||
/// Gets or sets a long description of the plugin containing features or helpful explanations.
|
||||
/// </summary>
|
||||
/// <value>The short description.</value>
|
||||
public string shortDescription { get; set; }
|
||||
/// <value>The description.</value>
|
||||
public string description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the overview.
|
||||
/// Gets or sets a short overview of what the plugin does.
|
||||
/// </summary>
|
||||
/// <value>The overview.</value>
|
||||
public string overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is premium.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is premium; otherwise, <c>false</c>.</value>
|
||||
public bool isPremium { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is adult only content.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is adult; otherwise, <c>false</c>.</value>
|
||||
public bool adult { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the rich desc URL.
|
||||
/// </summary>
|
||||
/// <value>The rich desc URL.</value>
|
||||
public string richDescUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the thumb image.
|
||||
/// </summary>
|
||||
/// <value>The thumb image.</value>
|
||||
public string thumbImage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the preview image.
|
||||
/// </summary>
|
||||
/// <value>The preview image.</value>
|
||||
public string previewImage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type.
|
||||
/// </summary>
|
||||
/// <value>The type.</value>
|
||||
public string type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the target filename.
|
||||
/// </summary>
|
||||
/// <value>The target filename.</value>
|
||||
public string targetFilename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the owner.
|
||||
/// </summary>
|
||||
|
@ -87,90 +39,24 @@ namespace MediaBrowser.Model.Updates
|
|||
public string category { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the catalog tile color.
|
||||
/// </summary>
|
||||
/// <value>The owner.</value>
|
||||
public string tileColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the feature id of this package (if premium).
|
||||
/// </summary>
|
||||
/// <value>The feature id.</value>
|
||||
public string featureId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the registration info for this package (if premium).
|
||||
/// </summary>
|
||||
/// <value>The registration info.</value>
|
||||
public string regInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the price for this package (if premium).
|
||||
/// </summary>
|
||||
/// <value>The price.</value>
|
||||
public float price { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the target system for this plug-in (Server, MBTheater, MBClassic).
|
||||
/// </summary>
|
||||
/// <value>The target system.</value>
|
||||
public PackageTargetSystem targetSystem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The guid of the assembly associated with this package (if a plug-in).
|
||||
/// The guid of the assembly associated with this plugin.
|
||||
/// This is used to identify the proper item for automatic updates.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string guid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the total number of ratings for this package.
|
||||
/// </summary>
|
||||
/// <value>The total ratings.</value>
|
||||
public int? totalRatings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the average rating for this package .
|
||||
/// </summary>
|
||||
/// <value>The rating.</value>
|
||||
public float avgRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether or not this package is registered.
|
||||
/// </summary>
|
||||
/// <value>True if registered.</value>
|
||||
public bool isRegistered { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the expiration date for this package.
|
||||
/// </summary>
|
||||
/// <value>Expiration Date.</value>
|
||||
public DateTime expDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the versions.
|
||||
/// </summary>
|
||||
/// <value>The versions.</value>
|
||||
public IReadOnlyList<PackageVersionInfo> versions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [enable in application store].
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [enable in application store]; otherwise, <c>false</c>.</value>
|
||||
public bool enableInAppStore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the installs.
|
||||
/// </summary>
|
||||
/// <value>The installs.</value>
|
||||
public int installs { get; set; }
|
||||
public IReadOnlyList<VersionInfo> versions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PackageInfo"/> class.
|
||||
/// </summary>
|
||||
public PackageInfo()
|
||||
{
|
||||
versions = Array.Empty<PackageVersionInfo>();
|
||||
versions = Array.Empty<VersionInfo>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
namespace MediaBrowser.Model.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum PackageType.
|
||||
/// </summary>
|
||||
public enum PackageTargetSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Server.
|
||||
/// </summary>
|
||||
Server,
|
||||
|
||||
/// <summary>
|
||||
/// MB Theater.
|
||||
/// </summary>
|
||||
MBTheater,
|
||||
|
||||
/// <summary>
|
||||
/// MB Classic.
|
||||
/// </summary>
|
||||
MBClassic
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
namespace MediaBrowser.Model.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum PackageVersionClass.
|
||||
/// </summary>
|
||||
public enum PackageVersionClass
|
||||
{
|
||||
/// <summary>
|
||||
/// The release.
|
||||
/// </summary>
|
||||
Release = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The beta.
|
||||
/// </summary>
|
||||
Beta = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The dev.
|
||||
/// </summary>
|
||||
Dev = 2
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MediaBrowser.Model.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Class PackageVersionInfo.
|
||||
/// </summary>
|
||||
public class PackageVersionInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the guid.
|
||||
/// </summary>
|
||||
/// <value>The guid.</value>
|
||||
public string guid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the version STR.
|
||||
/// </summary>
|
||||
/// <value>The version STR.</value>
|
||||
public string versionStr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The _version
|
||||
/// </summary>
|
||||
private Version _version;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the version.
|
||||
/// Had to make this an interpreted property since Protobuf can't handle Version
|
||||
/// </summary>
|
||||
/// <value>The version.</value>
|
||||
[JsonIgnore]
|
||||
public Version Version
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_version == null)
|
||||
{
|
||||
var ver = versionStr;
|
||||
_version = new Version(string.IsNullOrEmpty(ver) ? "0.0.0.1" : ver);
|
||||
}
|
||||
|
||||
return _version;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the classification.
|
||||
/// </summary>
|
||||
/// <value>The classification.</value>
|
||||
public PackageVersionClass classification { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the description.
|
||||
/// </summary>
|
||||
/// <value>The description.</value>
|
||||
public string description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the required version STR.
|
||||
/// </summary>
|
||||
/// <value>The required version STR.</value>
|
||||
public string requiredVersionStr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the source URL.
|
||||
/// </summary>
|
||||
/// <value>The source URL.</value>
|
||||
public string sourceUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the source URL.
|
||||
/// </summary>
|
||||
/// <value>The source URL.</value>
|
||||
public string checksum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the target filename.
|
||||
/// </summary>
|
||||
/// <value>The target filename.</value>
|
||||
public string targetFilename { get; set; }
|
||||
|
||||
public string infoUrl { get; set; }
|
||||
|
||||
public string runtimes { get; set; }
|
||||
}
|
||||
}
|
58
MediaBrowser.Model/Updates/VersionInfo.cs
Normal file
58
MediaBrowser.Model/Updates/VersionInfo.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
|
||||
namespace MediaBrowser.Model.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Class PackageVersionInfo.
|
||||
/// </summary>
|
||||
public class VersionInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the guid.
|
||||
/// </summary>
|
||||
/// <value>The guid.</value>
|
||||
public string guid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the version.
|
||||
/// </summary>
|
||||
/// <value>The version.</value>
|
||||
public Version version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the changelog for this version.
|
||||
/// </summary>
|
||||
/// <value>The changelog.</value>
|
||||
public string changelog { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ABI that this version was built against.
|
||||
/// </summary>
|
||||
/// <value>The target ABI version.</value>
|
||||
public string targetAbi { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the source URL.
|
||||
/// </summary>
|
||||
/// <value>The source URL.</value>
|
||||
public string sourceUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a checksum for the binary.
|
||||
/// </summary>
|
||||
/// <value>The checksum.</value>
|
||||
public string checksum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the target filename for the downloaded binary.
|
||||
/// </summary>
|
||||
/// <value>The target filename.</value>
|
||||
public string filename { get; set; }
|
||||
}
|
||||
}
|
|
@ -36,60 +36,51 @@ namespace MediaBrowser.Providers.Manager
|
|||
/// </summary>
|
||||
public class ProviderManager : IProviderManager, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The _logger
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// The _HTTP client
|
||||
/// </summary>
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
||||
/// <summary>
|
||||
/// The _directory watchers
|
||||
/// </summary>
|
||||
private readonly ILibraryMonitor _libraryMonitor;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the configuration manager.
|
||||
/// </summary>
|
||||
/// <value>The configuration manager.</value>
|
||||
private IServerConfigurationManager ConfigurationManager { get; set; }
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IServerApplicationPaths _appPaths;
|
||||
private readonly IJsonSerializer _json;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly ISubtitleManager _subtitleManager;
|
||||
private readonly IServerConfigurationManager _configurationManager;
|
||||
|
||||
private IImageProvider[] ImageProviders { get; set; }
|
||||
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
private IMetadataService[] _metadataServices = { };
|
||||
private IMetadataProvider[] _metadataProviders = { };
|
||||
private IEnumerable<IMetadataSaver> _savers;
|
||||
private readonly IServerApplicationPaths _appPaths;
|
||||
private readonly IJsonSerializer _json;
|
||||
|
||||
private IExternalId[] _externalIds;
|
||||
|
||||
private readonly Func<ILibraryManager> _libraryManagerFactory;
|
||||
private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
public event EventHandler<GenericEventArgs<BaseItem>> RefreshStarted;
|
||||
public event EventHandler<GenericEventArgs<BaseItem>> RefreshCompleted;
|
||||
public event EventHandler<GenericEventArgs<Tuple<BaseItem, double>>> RefreshProgress;
|
||||
|
||||
private ISubtitleManager _subtitleManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProviderManager" /> class.
|
||||
/// </summary>
|
||||
public ProviderManager(IHttpClient httpClient, ISubtitleManager subtitleManager, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILoggerFactory loggerFactory, IFileSystem fileSystem, IServerApplicationPaths appPaths, Func<ILibraryManager> libraryManagerFactory, IJsonSerializer json)
|
||||
public ProviderManager(
|
||||
IHttpClient httpClient,
|
||||
ISubtitleManager subtitleManager,
|
||||
IServerConfigurationManager configurationManager,
|
||||
ILibraryMonitor libraryMonitor,
|
||||
ILogger<ProviderManager> logger,
|
||||
IFileSystem fileSystem,
|
||||
IServerApplicationPaths appPaths,
|
||||
ILibraryManager libraryManager,
|
||||
IJsonSerializer json)
|
||||
{
|
||||
_logger = loggerFactory.CreateLogger("ProviderManager");
|
||||
_logger = logger;
|
||||
_httpClient = httpClient;
|
||||
ConfigurationManager = configurationManager;
|
||||
_configurationManager = configurationManager;
|
||||
_libraryMonitor = libraryMonitor;
|
||||
_fileSystem = fileSystem;
|
||||
_appPaths = appPaths;
|
||||
_libraryManagerFactory = libraryManagerFactory;
|
||||
_libraryManager = libraryManager;
|
||||
_json = json;
|
||||
_subtitleManager = subtitleManager;
|
||||
}
|
||||
|
@ -176,7 +167,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken)
|
||||
{
|
||||
return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken);
|
||||
return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken);
|
||||
}
|
||||
|
||||
public Task SaveImage(BaseItem item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken)
|
||||
|
@ -188,7 +179,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
var fileStream = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, true);
|
||||
|
||||
return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken);
|
||||
return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(BaseItem item, RemoteImageQuery query, CancellationToken cancellationToken)
|
||||
|
@ -273,7 +264,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
public IEnumerable<IImageProvider> GetImageProviders(BaseItem item, ImageRefreshOptions refreshOptions)
|
||||
{
|
||||
return GetImageProviders(item, _libraryManagerFactory().GetLibraryOptions(item), GetMetadataOptions(item), refreshOptions, false);
|
||||
return GetImageProviders(item, _libraryManager.GetLibraryOptions(item), GetMetadataOptions(item), refreshOptions, false);
|
||||
}
|
||||
|
||||
private IEnumerable<IImageProvider> GetImageProviders(BaseItem item, LibraryOptions libraryOptions, MetadataOptions options, ImageRefreshOptions refreshOptions, bool includeDisabled)
|
||||
|
@ -328,7 +319,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
private IEnumerable<IRemoteImageProvider> GetRemoteImageProviders(BaseItem item, bool includeDisabled)
|
||||
{
|
||||
var options = GetMetadataOptions(item);
|
||||
var libraryOptions = _libraryManagerFactory().GetLibraryOptions(item);
|
||||
var libraryOptions = _libraryManager.GetLibraryOptions(item);
|
||||
|
||||
return GetImageProviders(item, libraryOptions, options,
|
||||
new ImageRefreshOptions(
|
||||
|
@ -593,7 +584,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
{
|
||||
var type = item.GetType().Name;
|
||||
|
||||
return ConfigurationManager.Configuration.MetadataOptions
|
||||
return _configurationManager.Configuration.MetadataOptions
|
||||
.FirstOrDefault(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase)) ??
|
||||
new MetadataOptions();
|
||||
}
|
||||
|
@ -623,7 +614,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
/// <returns>Task.</returns>
|
||||
private void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable<IMetadataSaver> savers)
|
||||
{
|
||||
var libraryOptions = _libraryManagerFactory().GetLibraryOptions(item);
|
||||
var libraryOptions = _libraryManager.GetLibraryOptions(item);
|
||||
|
||||
foreach (var saver in savers.Where(i => IsSaverEnabledForItem(i, item, libraryOptions, updateType, false)))
|
||||
{
|
||||
|
@ -743,7 +734,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
if (!searchInfo.ItemId.Equals(Guid.Empty))
|
||||
{
|
||||
referenceItem = _libraryManagerFactory().GetItemById(searchInfo.ItemId);
|
||||
referenceItem = _libraryManager.GetItemById(searchInfo.ItemId);
|
||||
}
|
||||
|
||||
return GetRemoteSearchResults<TItemType, TLookupType>(searchInfo, referenceItem, cancellationToken);
|
||||
|
@ -771,7 +762,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
}
|
||||
else
|
||||
{
|
||||
libraryOptions = _libraryManagerFactory().GetLibraryOptions(referenceItem);
|
||||
libraryOptions = _libraryManager.GetLibraryOptions(referenceItem);
|
||||
}
|
||||
|
||||
var options = GetMetadataOptions(referenceItem);
|
||||
|
@ -786,11 +777,11 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataLanguage))
|
||||
{
|
||||
searchInfo.SearchInfo.MetadataLanguage = ConfigurationManager.Configuration.PreferredMetadataLanguage;
|
||||
searchInfo.SearchInfo.MetadataLanguage = _configurationManager.Configuration.PreferredMetadataLanguage;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataCountryCode))
|
||||
{
|
||||
searchInfo.SearchInfo.MetadataCountryCode = ConfigurationManager.Configuration.MetadataCountryCode;
|
||||
searchInfo.SearchInfo.MetadataCountryCode = _configurationManager.Configuration.MetadataCountryCode;
|
||||
}
|
||||
|
||||
var resultList = new List<RemoteSearchResult>();
|
||||
|
@ -967,7 +958,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
public void OnRefreshProgress(BaseItem item, double progress)
|
||||
{
|
||||
var id = item.Id;
|
||||
_logger.LogInformation("OnRefreshProgress {0} {1}", id.ToString("N", CultureInfo.InvariantCulture), progress);
|
||||
_logger.LogDebug("OnRefreshProgress {0} {1}", id.ToString("N", CultureInfo.InvariantCulture), progress);
|
||||
|
||||
// TODO: Need to hunt down the conditions for this happening
|
||||
_activeRefreshes.AddOrUpdate(
|
||||
|
@ -1010,7 +1001,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
private async Task StartProcessingRefreshQueue()
|
||||
{
|
||||
var libraryManager = _libraryManagerFactory();
|
||||
var libraryManager = _libraryManager;
|
||||
|
||||
if (_disposed)
|
||||
{
|
||||
|
@ -1088,7 +1079,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
private async Task RefreshArtist(MusicArtist item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||
{
|
||||
var albums = _libraryManagerFactory()
|
||||
var albums = _libraryManager
|
||||
.GetItemList(new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { nameof(MusicAlbum) },
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{442B5058-DCAF-4263-BB6A-F21E31120A1B}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||
|
|
|
@ -25,22 +25,22 @@ namespace MediaBrowser.Providers.Subtitles
|
|||
{
|
||||
public class SubtitleManager : ISubtitleManager
|
||||
{
|
||||
private ISubtitleProvider[] _subtitleProviders;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ILibraryMonitor _monitor;
|
||||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
private readonly ILocalizationManager _localization;
|
||||
|
||||
private ILocalizationManager _localization;
|
||||
private ISubtitleProvider[] _subtitleProviders;
|
||||
|
||||
public SubtitleManager(
|
||||
ILoggerFactory loggerFactory,
|
||||
ILogger<SubtitleManager> logger,
|
||||
IFileSystem fileSystem,
|
||||
ILibraryMonitor monitor,
|
||||
IMediaSourceManager mediaSourceManager,
|
||||
ILocalizationManager localizationManager)
|
||||
{
|
||||
_logger = loggerFactory.CreateLogger(nameof(SubtitleManager));
|
||||
_logger = logger;
|
||||
_fileSystem = fileSystem;
|
||||
_monitor = monitor;
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{5624B7B5-B5A7-41D8-9F10-CC5611109619}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{23499896-B135-4527-8574-C26E926EA99E}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{21002819-C39A-4D3E-BE83-2A276A77FB1F}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{DF194677-DFD3-42AF-9F75-D44D5A416478}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{462584F7-5023-4019-9EAC-B98CA458C0A0}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{28464062-0939-4AA7-9F7B-24DDDA61A7C0}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{3998657B-1CCC-49DD-A19F-275DC8495F57}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{2E3A1B4B-4225-4AAA-8B29-0181A84E7AEE}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
|
|
@ -82,11 +82,10 @@ namespace MediaBrowser.Api.Tests
|
|||
loggerFactory,
|
||||
commandLineOpts,
|
||||
new ManagedFileSystem(loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths),
|
||||
new SkiaEncoder(loggerFactory.CreateLogger<SkiaEncoder>(), appPaths),
|
||||
new NetworkManager(loggerFactory.CreateLogger<NetworkManager>()));
|
||||
_appHosts.Add(appHost);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
appHost.InitAsync(serviceCollection, startupConfig).Wait();
|
||||
appHost.Init(serviceCollection);
|
||||
|
||||
// Configure the web host builder
|
||||
Program.ConfigureWebHostBuilder(builder, appHost, serviceCollection, commandLineOpts, startupConfig, appPaths);
|
||||
|
@ -101,8 +100,7 @@ namespace MediaBrowser.Api.Tests
|
|||
// Finish initializing the app host
|
||||
var appHost = (CoreAppHost)testServer.Services.GetRequiredService<IApplicationHost>();
|
||||
appHost.ServiceProvider = testServer.Services;
|
||||
appHost.InitializeServices();
|
||||
appHost.FindParts();
|
||||
appHost.InitializeServices().Wait();
|
||||
appHost.RunStartupTasksAsync().Wait();
|
||||
|
||||
return testServer;
|
||||
|
|
Loading…
Reference in New Issue
Block a user