aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Monteiro <marknr.monteiro@protonmail.com>2020-04-13 17:06:24 -0400
committerMark Monteiro <marknr.monteiro@protonmail.com>2020-04-13 17:06:24 -0400
commit9728aa8b0abc7785f8c9f3d62c2adff1920cfab9 (patch)
tree111975663193ef2dfab67380e6d5a2f4f9d554f6
parent17e8813378c2fe1a83d1eddb829dae68f8c71bfe (diff)
parent9a0a4575adbba04b6b7f3294e70175a98b864a90 (diff)
Merge branch 'master' into register-services-correctly
-rw-r--r--CONTRIBUTORS.md1
-rw-r--r--Dockerfile.arm2
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs27
-rw-r--r--Emby.Server.Implementations/Diagnostics/CommonProcess.cs152
-rw-r--r--Emby.Server.Implementations/Diagnostics/ProcessFactory.cs14
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpListenerHost.cs14
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs34
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs72
-rw-r--r--Emby.Server.Implementations/Localization/Core/da.json6
-rw-r--r--Emby.Server.Implementations/Localization/Core/en-GB.json24
-rw-r--r--Emby.Server.Implementations/Localization/Core/es_DO.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/fa.json26
-rw-r--r--Emby.Server.Implementations/Localization/Core/fi.json58
-rw-r--r--Emby.Server.Implementations/Localization/Core/fr.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/hu.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/pt.json6
-rw-r--r--Emby.Server.Implementations/Localization/Core/ur_PK.json118
-rw-r--r--MediaBrowser.Api/ApiEntryPoint.cs29
-rw-r--r--MediaBrowser.Api/BaseApiService.cs58
-rw-r--r--MediaBrowser.Api/ChannelService.cs22
-rw-r--r--MediaBrowser.Api/Devices/DeviceService.cs16
-rw-r--r--MediaBrowser.Api/EnvironmentService.cs7
-rw-r--r--MediaBrowser.Api/FilterService.cs4
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs26
-rw-r--r--MediaBrowser.Api/Images/RemoteImageService.cs26
-rw-r--r--MediaBrowser.Api/ItemLookupService.cs11
-rw-r--r--MediaBrowser.Api/ItemUpdateService.cs28
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs195
-rw-r--r--MediaBrowser.Api/Library/LibraryStructureService.cs12
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs12
-rw-r--r--MediaBrowser.Api/Movies/MoviesService.cs2
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs406
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs73
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs10
-rw-r--r--MediaBrowser.Api/Playback/MediaInfoService.cs23
-rw-r--r--MediaBrowser.Api/Playback/UniversalAudioService.cs4
-rw-r--r--MediaBrowser.Api/PluginService.cs4
-rw-r--r--MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs8
-rw-r--r--MediaBrowser.Api/SearchService.cs98
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs15
-rw-r--r--MediaBrowser.Api/System/SystemService.cs7
-rw-r--r--MediaBrowser.Api/TranscodingJob.cs5
-rw-r--r--MediaBrowser.Api/TvShowsService.cs13
-rw-r--r--MediaBrowser.Api/UserLibrary/ArtistsService.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs34
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs33
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs6
-rw-r--r--MediaBrowser.Api/VideosService.cs13
-rw-r--r--MediaBrowser.Common/Extensions/ProcessExtensions.cs80
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs62
-rw-r--r--MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs65
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs1
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs81
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs147
-rw-r--r--MediaBrowser.Model/Diagnostics/IProcess.cs23
-rw-r--r--MediaBrowser.Model/Diagnostics/IProcessFactory.cs24
-rw-r--r--nuget.config6
-rw-r--r--tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs66
58 files changed, 1060 insertions, 1262 deletions
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index f195c125f..3d6023b82 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -128,6 +128,7 @@
- [xosdy](https://github.com/xosdy)
- [XVicarious](https://github.com/XVicarious)
- [YouKnowBlom](https://github.com/YouKnowBlom)
+ - [KristupasSavickas](https://github.com/KristupasSavickas)
# Emby Contributors
diff --git a/Dockerfile.arm b/Dockerfile.arm
index c5189d6aa..39beaa479 100644
--- a/Dockerfile.arm
+++ b/Dockerfile.arm
@@ -74,4 +74,4 @@ VOLUME /cache /config /media
ENTRYPOINT ["./jellyfin/jellyfin", \
"--datadir", "/config", \
"--cachedir", "/cache", \
- "--ffmpeg", "/usr/lib/jellyfin-ffmpeg"]
+ "--ffmpeg", "/usr/lib/jellyfin-ffmpeg/ffmpeg"]
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index ad0a69b19..03ce9a9a9 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -30,7 +30,6 @@ using Emby.Server.Implementations.Configuration;
using Emby.Server.Implementations.Cryptography;
using Emby.Server.Implementations.Data;
using Emby.Server.Implementations.Devices;
-using Emby.Server.Implementations.Diagnostics;
using Emby.Server.Implementations.Dto;
using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.HttpServer.Security;
@@ -86,7 +85,6 @@ using MediaBrowser.MediaEncoding.BdInfo;
using MediaBrowser.Model.Activity;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
@@ -574,8 +572,6 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton(_xmlSerializer);
- serviceCollection.AddSingleton<IProcessFactory, ProcessFactory>();
-
serviceCollection.AddSingleton<IStreamHelper, StreamHelper>();
serviceCollection.AddSingleton<ICryptoProvider, CryptographyProvider>();
@@ -1462,15 +1458,17 @@ namespace Emby.Server.Implementations
throw new NotSupportedException();
}
- var process = Resolve<IProcessFactory>().Create(new ProcessOptions
+ var process = new Process
{
- FileName = url,
- EnableRaisingEvents = true,
- UseShellExecute = true,
- ErrorDialog = false
- });
-
- process.Exited += ProcessExited;
+ StartInfo = new ProcessStartInfo
+ {
+ FileName = url,
+ UseShellExecute = true,
+ ErrorDialog = false
+ },
+ EnableRaisingEvents = true
+ };
+ process.Exited += (sender, args) => ((Process)sender).Dispose();
try
{
@@ -1483,11 +1481,6 @@ namespace Emby.Server.Implementations
}
}
- private static void ProcessExited(object sender, EventArgs e)
- {
- ((IProcess)sender).Dispose();
- }
-
public virtual void EnableLoopback(string appName)
{
}
diff --git a/Emby.Server.Implementations/Diagnostics/CommonProcess.cs b/Emby.Server.Implementations/Diagnostics/CommonProcess.cs
deleted file mode 100644
index bfa49ac5f..000000000
--- a/Emby.Server.Implementations/Diagnostics/CommonProcess.cs
+++ /dev/null
@@ -1,152 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Diagnostics;
-
-namespace Emby.Server.Implementations.Diagnostics
-{
- public class CommonProcess : IProcess
- {
- private readonly Process _process;
-
- private bool _disposed = false;
- private bool _hasExited;
-
- public CommonProcess(ProcessOptions options)
- {
- StartInfo = options;
-
- var startInfo = new ProcessStartInfo
- {
- Arguments = options.Arguments,
- FileName = options.FileName,
- WorkingDirectory = options.WorkingDirectory,
- UseShellExecute = options.UseShellExecute,
- CreateNoWindow = options.CreateNoWindow,
- RedirectStandardError = options.RedirectStandardError,
- RedirectStandardInput = options.RedirectStandardInput,
- RedirectStandardOutput = options.RedirectStandardOutput,
- ErrorDialog = options.ErrorDialog
- };
-
-
- if (options.IsHidden)
- {
- startInfo.WindowStyle = ProcessWindowStyle.Hidden;
- }
-
- _process = new Process
- {
- StartInfo = startInfo
- };
-
- if (options.EnableRaisingEvents)
- {
- _process.EnableRaisingEvents = true;
- _process.Exited += OnProcessExited;
- }
- }
-
- public event EventHandler Exited;
-
- public ProcessOptions StartInfo { get; }
-
- public StreamWriter StandardInput => _process.StandardInput;
-
- public StreamReader StandardError => _process.StandardError;
-
- public StreamReader StandardOutput => _process.StandardOutput;
-
- public int ExitCode => _process.ExitCode;
-
- private bool HasExited
- {
- get
- {
- if (_hasExited)
- {
- return true;
- }
-
- try
- {
- _hasExited = _process.HasExited;
- }
- catch (InvalidOperationException)
- {
- _hasExited = true;
- }
-
- return _hasExited;
- }
- }
-
- public void Start()
- {
- _process.Start();
- }
-
- public void Kill()
- {
- _process.Kill();
- }
-
- public bool WaitForExit(int timeMs)
- {
- return _process.WaitForExit(timeMs);
- }
-
- public Task<bool> WaitForExitAsync(int timeMs)
- {
- // Note: For this function to work correctly, the option EnableRisingEvents needs to be set to true.
-
- if (HasExited)
- {
- return Task.FromResult(true);
- }
-
- timeMs = Math.Max(0, timeMs);
-
- var tcs = new TaskCompletionSource<bool>();
-
- var cancellationToken = new CancellationTokenSource(timeMs).Token;
-
- _process.Exited += (sender, args) => tcs.TrySetResult(true);
-
- cancellationToken.Register(() => tcs.TrySetResult(HasExited));
-
- return tcs.Task;
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (_disposed)
- {
- return;
- }
-
- if (disposing)
- {
- _process?.Dispose();
- }
-
- _disposed = true;
- }
-
- private void OnProcessExited(object sender, EventArgs e)
- {
- _hasExited = true;
- Exited?.Invoke(this, e);
- }
- }
-}
diff --git a/Emby.Server.Implementations/Diagnostics/ProcessFactory.cs b/Emby.Server.Implementations/Diagnostics/ProcessFactory.cs
deleted file mode 100644
index 02ad3c1a8..000000000
--- a/Emby.Server.Implementations/Diagnostics/ProcessFactory.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma warning disable CS1591
-
-using MediaBrowser.Model.Diagnostics;
-
-namespace Emby.Server.Implementations.Diagnostics
-{
- public class ProcessFactory : IProcessFactory
- {
- public IProcess Create(ProcessOptions options)
- {
- return new CommonProcess(options);
- }
- }
-}
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index 72667a314..5ae65a4e3 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -239,7 +239,7 @@ namespace Emby.Server.Implementations.HttpServer
}
}
- private async Task ErrorHandler(Exception ex, IRequest httpReq, bool logExceptionStackTrace)
+ private async Task ErrorHandler(Exception ex, IRequest httpReq, bool logExceptionStackTrace, string urlToLog)
{
try
{
@@ -247,11 +247,11 @@ namespace Emby.Server.Implementations.HttpServer
if (logExceptionStackTrace)
{
- _logger.LogError(ex, "Error processing request");
+ _logger.LogError(ex, "Error processing request. URL: {Url}", urlToLog);
}
else
{
- _logger.LogError("Error processing request: {Message}", ex.Message);
+ _logger.LogError("Error processing request: {Message}. URL: {Url}", ex.Message.TrimEnd('.'), urlToLog);
}
var httpRes = httpReq.Response;
@@ -271,7 +271,7 @@ namespace Emby.Server.Implementations.HttpServer
}
catch (Exception errorEx)
{
- _logger.LogError(errorEx, "Error this.ProcessRequest(context)(Exception while writing error to the response)");
+ _logger.LogError(errorEx, "Error this.ProcessRequest(context)(Exception while writing error to the response). URL: {Url}", urlToLog);
}
}
@@ -456,7 +456,7 @@ namespace Emby.Server.Implementations.HttpServer
var stopWatch = new Stopwatch();
stopWatch.Start();
var httpRes = httpReq.Response;
- string urlToLog = null;
+ string urlToLog = GetUrlToLog(urlString);
string remoteIp = httpReq.RemoteIp;
try
@@ -502,8 +502,6 @@ namespace Emby.Server.Implementations.HttpServer
return;
}
- urlToLog = GetUrlToLog(urlString);
-
if (string.Equals(localPath, _baseUrlPrefix + "/", StringComparison.OrdinalIgnoreCase)
|| string.Equals(localPath, _baseUrlPrefix, StringComparison.OrdinalIgnoreCase)
|| string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase)
@@ -553,7 +551,7 @@ namespace Emby.Server.Implementations.HttpServer
|| ex is OperationCanceledException
|| ex is SecurityException
|| ex is FileNotFoundException;
- await ErrorHandler(ex, httpReq, ignoreStackTrace).ConfigureAwait(false);
+ await ErrorHandler(ex, httpReq, !ignoreStackTrace, urlToLog).ConfigureAwait(false);
}
finally
{
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 139aa19a4..900f12062 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -25,7 +26,6 @@ using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events;
@@ -61,7 +61,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private readonly ILibraryManager _libraryManager;
private readonly IProviderManager _providerManager;
private readonly IMediaEncoder _mediaEncoder;
- private readonly IProcessFactory _processFactory;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IStreamHelper _streamHelper;
@@ -88,8 +87,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
ILibraryManager libraryManager,
ILibraryMonitor libraryMonitor,
IProviderManager providerManager,
- IMediaEncoder mediaEncoder,
- IProcessFactory processFactory)
+ IMediaEncoder mediaEncoder)
{
Current = this;
@@ -102,7 +100,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_libraryMonitor = libraryMonitor;
_providerManager = providerManager;
_mediaEncoder = mediaEncoder;
- _processFactory = processFactory;
_liveTvManager = (LiveTvManager)liveTvManager;
_jsonSerializer = jsonSerializer;
_mediaSourceManager = mediaSourceManager;
@@ -1662,7 +1659,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
if (mediaSource.RequiresLooping || !(mediaSource.Container ?? string.Empty).EndsWith("ts", StringComparison.OrdinalIgnoreCase) || (mediaSource.Protocol != MediaProtocol.File && mediaSource.Protocol != MediaProtocol.Http))
{
- return new EncodedRecorder(_logger, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer, _processFactory, _config);
+ return new EncodedRecorder(_logger, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer, _config);
}
return new DirectRecorder(_logger, _httpClient, _streamHelper);
@@ -1683,16 +1680,19 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
try
{
- var process = _processFactory.Create(new ProcessOptions
+ var process = new Process
{
- Arguments = GetPostProcessArguments(path, options.RecordingPostProcessorArguments),
- CreateNoWindow = true,
- EnableRaisingEvents = true,
- ErrorDialog = false,
- FileName = options.RecordingPostProcessor,
- IsHidden = true,
- UseShellExecute = false
- });
+ StartInfo = new ProcessStartInfo
+ {
+ Arguments = GetPostProcessArguments(path, options.RecordingPostProcessorArguments),
+ CreateNoWindow = true,
+ ErrorDialog = false,
+ FileName = options.RecordingPostProcessor,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ UseShellExecute = false
+ },
+ EnableRaisingEvents = true
+ };
_logger.LogInformation("Running recording post processor {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
@@ -1712,11 +1712,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private void Process_Exited(object sender, EventArgs e)
{
- using (var process = (IProcess)sender)
+ using (var process = (Process)sender)
{
_logger.LogInformation("Recording post-processing script completed with exit code {ExitCode}", process.ExitCode);
-
- process.Dispose();
}
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index d24fc6792..bc86cc59a 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
@@ -13,7 +14,6 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
@@ -29,8 +29,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private bool _hasExited;
private Stream _logFileStream;
private string _targetPath;
- private IProcess _process;
- private readonly IProcessFactory _processFactory;
+ private Process _process;
private readonly IJsonSerializer _json;
private readonly TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>();
private readonly IServerConfigurationManager _config;
@@ -40,14 +39,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
IMediaEncoder mediaEncoder,
IServerApplicationPaths appPaths,
IJsonSerializer json,
- IProcessFactory processFactory,
IServerConfigurationManager config)
{
_logger = logger;
_mediaEncoder = mediaEncoder;
_appPaths = appPaths;
_json = json;
- _processFactory = processFactory;
_config = config;
}
@@ -79,7 +76,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_targetPath = targetFile;
Directory.CreateDirectory(Path.GetDirectoryName(targetFile));
- var process = _processFactory.Create(new ProcessOptions
+ var processStartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
UseShellExecute = false,
@@ -90,14 +87,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
FileName = _mediaEncoder.EncoderPath,
Arguments = GetCommandLineArgs(mediaSource, inputFile, targetFile, duration),
- IsHidden = true,
- ErrorDialog = false,
- EnableRaisingEvents = true
- });
-
- _process = process;
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false
+ };
- var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments;
+ var commandLineLogMessage = processStartInfo.FileName + " " + processStartInfo.Arguments;
_logger.LogInformation(commandLineLogMessage);
var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "record-transcode-" + Guid.NewGuid() + ".txt");
@@ -109,16 +103,21 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(_json.SerializeToString(mediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
_logFileStream.Write(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length);
- process.Exited += (sender, args) => OnFfMpegProcessExited(process, inputFile);
+ _process = new Process
+ {
+ StartInfo = processStartInfo,
+ EnableRaisingEvents = true
+ };
+ _process.Exited += (sender, args) => OnFfMpegProcessExited(_process, inputFile);
- process.Start();
+ _process.Start();
cancellationToken.Register(Stop);
onStarted();
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
- StartStreamingLog(process.StandardError.BaseStream, _logFileStream);
+ StartStreamingLog(_process.StandardError.BaseStream, _logFileStream);
_logger.LogInformation("ffmpeg recording process started for {0}", _targetPath);
@@ -292,30 +291,33 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
/// <summary>
/// Processes the exited.
/// </summary>
- private void OnFfMpegProcessExited(IProcess process, string inputFile)
+ private void OnFfMpegProcessExited(Process process, string inputFile)
{
- _hasExited = true;
+ using (process)
+ {
+ _hasExited = true;
- _logFileStream?.Dispose();
- _logFileStream = null;
+ _logFileStream?.Dispose();
+ _logFileStream = null;
- var exitCode = process.ExitCode;
+ var exitCode = process.ExitCode;
- _logger.LogInformation("FFMpeg recording exited with code {ExitCode} for {Path}", exitCode, _targetPath);
+ _logger.LogInformation("FFMpeg recording exited with code {ExitCode} for {Path}", exitCode, _targetPath);
- if (exitCode == 0)
- {
- _taskCompletionSource.TrySetResult(true);
- }
- else
- {
- _taskCompletionSource.TrySetException(
- new Exception(
- string.Format(
- CultureInfo.InvariantCulture,
- "Recording for {0} failed. Exit code {1}",
- _targetPath,
- exitCode)));
+ if (exitCode == 0)
+ {
+ _taskCompletionSource.TrySetResult(true);
+ }
+ else
+ {
+ _taskCompletionSource.TrySetException(
+ new Exception(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "Recording for {0} failed. Exit code {1}",
+ _targetPath,
+ exitCode)));
+ }
}
}
diff --git a/Emby.Server.Implementations/Localization/Core/da.json b/Emby.Server.Implementations/Localization/Core/da.json
index 92719a9fd..93b8052d3 100644
--- a/Emby.Server.Implementations/Localization/Core/da.json
+++ b/Emby.Server.Implementations/Localization/Core/da.json
@@ -1,5 +1,5 @@
{
- "Albums": "Album",
+ "Albums": "Albums",
"AppDeviceValues": "App: {0}, Enhed: {1}",
"Application": "Applikation",
"Artists": "Kunstnere",
@@ -106,5 +106,7 @@
"TasksChannelsCategory": "Internet Kanaler",
"TasksApplicationCategory": "Applikation",
"TasksLibraryCategory": "Bibliotek",
- "TasksMaintenanceCategory": "Vedligeholdelse"
+ "TasksMaintenanceCategory": "Vedligeholdelse",
+ "TaskRefreshChapterImages": "Udtræk Kapitel billeder",
+ "TaskRefreshChapterImagesDescription": "Lav miniaturebilleder for videoer der har kapitler."
}
diff --git a/Emby.Server.Implementations/Localization/Core/en-GB.json b/Emby.Server.Implementations/Localization/Core/en-GB.json
index dc4f0b212..544c38cfa 100644
--- a/Emby.Server.Implementations/Localization/Core/en-GB.json
+++ b/Emby.Server.Implementations/Localization/Core/en-GB.json
@@ -92,5 +92,27 @@
"UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}",
"ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
"ValueSpecialEpisodeName": "Special - {0}",
- "VersionNumber": "Version {0}"
+ "VersionNumber": "Version {0}",
+ "TaskDownloadMissingSubtitlesDescription": "Searches the internet for missing subtitles based on metadata configuration.",
+ "TaskDownloadMissingSubtitles": "Download missing subtitles",
+ "TaskRefreshChannelsDescription": "Refreshes internet channel information.",
+ "TaskRefreshChannels": "Refresh Channels",
+ "TaskCleanTranscodeDescription": "Deletes transcode files more than one day old.",
+ "TaskCleanTranscode": "Clean Transcode Directory",
+ "TaskUpdatePluginsDescription": "Downloads and installs updates for plugins that are configured to update automatically.",
+ "TaskUpdatePlugins": "Update Plugins",
+ "TaskRefreshPeopleDescription": "Updates metadata for actors and directors in your media library.",
+ "TaskRefreshPeople": "Refresh People",
+ "TaskCleanLogsDescription": "Deletes log files that are more than {0} days old.",
+ "TaskCleanLogs": "Clean Log Directory",
+ "TaskRefreshLibraryDescription": "Scans your media library for new files and refreshes metadata.",
+ "TaskRefreshLibrary": "Scan Media Library",
+ "TaskRefreshChapterImagesDescription": "Creates thumbnails for videos that have chapters.",
+ "TaskRefreshChapterImages": "Extract Chapter Images",
+ "TaskCleanCacheDescription": "Deletes cache files no longer needed by the system.",
+ "TaskCleanCache": "Clean Cache Directory",
+ "TasksChannelsCategory": "Internet Channels",
+ "TasksApplicationCategory": "Application",
+ "TasksLibraryCategory": "Library",
+ "TasksMaintenanceCategory": "Maintenance"
}
diff --git a/Emby.Server.Implementations/Localization/Core/es_DO.json b/Emby.Server.Implementations/Localization/Core/es_DO.json
index 1a7b57c53..0ef16542f 100644
--- a/Emby.Server.Implementations/Localization/Core/es_DO.json
+++ b/Emby.Server.Implementations/Localization/Core/es_DO.json
@@ -5,7 +5,7 @@
"Collections": "Colecciones",
"Artists": "Artistas",
"DeviceOnlineWithName": "{0} está conectado",
- "DeviceOfflineWithName": "{0} ha desconectado",
+ "DeviceOfflineWithName": "{0} se ha desconectado",
"ChapterNameValue": "Capítulo {0}",
"CameraImageUploadedFrom": "Se ha subido una nueva imagen de cámara desde {0}",
"AuthenticationSucceededWithUserName": "{0} autenticado con éxito",
diff --git a/Emby.Server.Implementations/Localization/Core/fa.json b/Emby.Server.Implementations/Localization/Core/fa.json
index 45e74b8eb..be6f87ee3 100644
--- a/Emby.Server.Implementations/Localization/Core/fa.json
+++ b/Emby.Server.Implementations/Localization/Core/fa.json
@@ -23,7 +23,7 @@
"HeaderFavoriteEpisodes": "قسمت‌های مورد علاقه",
"HeaderFavoriteShows": "سریال‌های مورد علاقه",
"HeaderFavoriteSongs": "آهنگ‌های مورد علاقه",
- "HeaderLiveTV": "پخش زنده تلویزیون",
+ "HeaderLiveTV": "تلویزیون زنده",
"HeaderNextUp": "قسمت بعدی",
"HeaderRecordingGroups": "گروه‌های ضبط",
"HomeVideos": "ویدیوهای خانگی",
@@ -92,5 +92,27 @@
"UserStoppedPlayingItemWithValues": "{0} پخش {1} را بر روی {2} به پایان رساند",
"ValueHasBeenAddedToLibrary": "{0} به کتابخانه‌ی رسانه‌ی شما افزوده شد",
"ValueSpecialEpisodeName": "ویژه - {0}",
- "VersionNumber": "نسخه {0}"
+ "VersionNumber": "نسخه {0}",
+ "TaskCleanTranscodeDescription": "فایل‌های کدگذاری که قدیمی‌تر از یک روز هستند را حذف می‌کند.",
+ "TaskCleanTranscode": "پاکسازی مسیر کد گذاری",
+ "TaskUpdatePluginsDescription": "دانلود و نصب به روز رسانی افزونه‌هایی که برای به روز رسانی خودکار پیکربندی شده‌اند.",
+ "TaskDownloadMissingSubtitlesDescription": "جستجوی زیرنویس‌های ناموجود در اینترنت بر اساس پیکربندی ابرداده‌ها.",
+ "TaskDownloadMissingSubtitles": "دانلود زیرنویس‌های ناموجود",
+ "TaskRefreshChannelsDescription": "اطلاعات کانال اینترنتی را تازه سازی می‌کند.",
+ "TaskRefreshChannels": "تازه سازی کانال‌ها",
+ "TaskUpdatePlugins": "به روز رسانی افزونه‌ها",
+ "TaskRefreshPeopleDescription": "ابرداده‌ها برای بازیگران و کارگردانان در کتابخانه رسانه شما به روزرسانی می شوند.",
+ "TaskRefreshPeople": "تازه سازی افراد",
+ "TaskCleanLogsDescription": "واقعه نگارهایی را که قدیمی تر {0} روز هستند را حذف می کند.",
+ "TaskCleanLogs": "پاکسازی مسیر واقعه نگار",
+ "TaskRefreshLibraryDescription": "کتابخانه رسانه شما را اسکن می‌کند و ابرداده‌ها را تازه سازی می‌کند.",
+ "TaskRefreshLibrary": "اسکن کتابخانه رسانه",
+ "TaskRefreshChapterImagesDescription": "عکس‌های کوچک برای ویدیوهایی که سکانس دارند ایجاد می‌کند.",
+ "TaskRefreshChapterImages": "استخراج عکس‌های سکانس",
+ "TaskCleanCacheDescription": "فایل‌های حافظه موقت که توسط سیستم دیگر مورد نیاز نیستند حذف می‌شوند.",
+ "TaskCleanCache": "پاکسازی مسیر حافظه موقت",
+ "TasksChannelsCategory": "کانال‌های داخلی",
+ "TasksApplicationCategory": "برنامه",
+ "TasksLibraryCategory": "کتابخانه",
+ "TasksMaintenanceCategory": "تعمیر"
}
diff --git a/Emby.Server.Implementations/Localization/Core/fi.json b/Emby.Server.Implementations/Localization/Core/fi.json
index bf5fc05c4..b39adefe7 100644
--- a/Emby.Server.Implementations/Localization/Core/fi.json
+++ b/Emby.Server.Implementations/Localization/Core/fi.json
@@ -1,5 +1,5 @@
{
- "HeaderLiveTV": "TV-lähetykset",
+ "HeaderLiveTV": "Suorat lähetykset",
"NewVersionIsAvailable": "Uusi versio Jellyfin palvelimesta on ladattavissa.",
"NameSeasonUnknown": "Tuntematon Kausi",
"NameSeasonNumber": "Kausi {0}",
@@ -19,12 +19,12 @@
"ItemAddedWithName": "{0} lisättiin kirjastoon",
"Inherit": "Periytyä",
"HomeVideos": "Kotivideot",
- "HeaderRecordingGroups": "Nauhoitusryhmät",
+ "HeaderRecordingGroups": "Nauhoiteryhmät",
"HeaderNextUp": "Seuraavaksi",
"HeaderFavoriteSongs": "Lempikappaleet",
"HeaderFavoriteShows": "Lempisarjat",
"HeaderFavoriteEpisodes": "Lempijaksot",
- "HeaderCameraUploads": "Kameralataukset",
+ "HeaderCameraUploads": "Kamerasta Lähetetyt",
"HeaderFavoriteArtists": "Lempiartistit",
"HeaderFavoriteAlbums": "Lempialbumit",
"HeaderContinueWatching": "Jatka katsomista",
@@ -63,10 +63,10 @@
"UserPasswordChangedWithName": "Salasana vaihdettu käyttäjälle {0}",
"UserOnlineFromDevice": "{0} on paikalla osoitteesta {1}",
"UserOfflineFromDevice": "{0} yhteys katkaistu {1}",
- "UserLockedOutWithName": "Käyttäjä {0} kirjautui ulos",
- "UserDownloadingItemWithValues": "{0} latautumassa {1}",
- "UserDeletedWithName": "Poistettiin käyttäjä {0}",
- "UserCreatedWithName": "Luotiin käyttäjä {0}",
+ "UserLockedOutWithName": "Käyttäjä {0} lukittu",
+ "UserDownloadingItemWithValues": "{0} lataa {1}",
+ "UserDeletedWithName": "Käyttäjä {0} poistettu",
+ "UserCreatedWithName": "Käyttäjä {0} luotu",
"TvShows": "TV-Ohjelmat",
"Sync": "Synkronoi",
"SubtitleDownloadFailureFromForItem": "Tekstityksen lataaminen epäonnistui {0} - {1}",
@@ -74,22 +74,44 @@
"Songs": "Kappaleet",
"Shows": "Ohjelmat",
"ServerNameNeedsToBeRestarted": "{0} vaatii uudelleenkäynnistyksen",
- "ProviderValue": "Palveluntarjoaja: {0}",
+ "ProviderValue": "Tarjoaja: {0}",
"Plugin": "Liitännäinen",
- "NotificationOptionVideoPlaybackStopped": "Videon toistaminen pysäytetty",
- "NotificationOptionVideoPlayback": "Videon toistaminen aloitettu",
- "NotificationOptionUserLockedOut": "Käyttäjä kirjautui ulos",
- "NotificationOptionTaskFailed": "Ajastetun tehtävän ongelma",
+ "NotificationOptionVideoPlaybackStopped": "Videon toisto pysäytetty",
+ "NotificationOptionVideoPlayback": "Videon toisto aloitettu",
+ "NotificationOptionUserLockedOut": "Käyttäjä lukittu",
+ "NotificationOptionTaskFailed": "Ajastettu tehtävä epäonnistui",
"NotificationOptionServerRestartRequired": "Palvelimen uudelleenkäynnistys vaaditaan",
- "NotificationOptionPluginUpdateInstalled": "Liitännäinen päivitetty",
+ "NotificationOptionPluginUpdateInstalled": "Lisäosan päivitys asennettu",
"NotificationOptionPluginUninstalled": "Liitännäinen poistettu",
"NotificationOptionPluginInstalled": "Liitännäinen asennettu",
"NotificationOptionPluginError": "Ongelma liitännäisessä",
"NotificationOptionNewLibraryContent": "Uutta sisältöä lisätty",
"NotificationOptionInstallationFailed": "Asennus epäonnistui",
- "NotificationOptionCameraImageUploaded": "Kuva ladattu kamerasta",
- "NotificationOptionAudioPlaybackStopped": "Audion toisto pysäytetty",
- "NotificationOptionAudioPlayback": "Audion toisto aloitettu",
- "NotificationOptionApplicationUpdateInstalled": "Ohjelmistopäivitys asennettu",
- "NotificationOptionApplicationUpdateAvailable": "Ohjelmistopäivitys saatavilla"
+ "NotificationOptionCameraImageUploaded": "Kameran kuva ladattu",
+ "NotificationOptionAudioPlaybackStopped": "Äänen toisto lopetettu",
+ "NotificationOptionAudioPlayback": "Toistetaan ääntä",
+ "NotificationOptionApplicationUpdateInstalled": "Uusi sovellusversio asennettu",
+ "NotificationOptionApplicationUpdateAvailable": "Sovelluksesta on uusi versio saatavilla",
+ "TasksMaintenanceCategory": "Ylläpito",
+ "TaskDownloadMissingSubtitlesDescription": "Etsii puuttuvia tekstityksiä videon metadatatietojen pohjalta.",
+ "TaskDownloadMissingSubtitles": "Lataa puuttuvat tekstitykset",
+ "TaskRefreshChannelsDescription": "Päivittää internet-kanavien tiedot.",
+ "TaskRefreshChannels": "Päivitä kanavat",
+ "TaskCleanTranscodeDescription": "Poistaa transkoodatut tiedostot jotka ovat yli päivän vanhoja.",
+ "TaskCleanTranscode": "Puhdista transkoodaushakemisto",
+ "TaskUpdatePluginsDescription": "Lataa ja asentaa päivitykset liitännäisille jotka on asetettu päivittymään automaattisesti.",
+ "TaskUpdatePlugins": "Päivitä liitännäiset",
+ "TaskRefreshPeopleDescription": "Päivittää näyttelijöiden ja ohjaajien mediatiedot kirjastossasi.",
+ "TaskRefreshPeople": "Päivitä henkilöt",
+ "TaskCleanLogsDescription": "Poistaa lokitiedostot jotka ovat yli {0} päivää vanhoja.",
+ "TaskCleanLogs": "Puhdista lokihakemisto",
+ "TaskRefreshLibraryDescription": "Skannaa mediakirjastosi uusien tiedostojen varalle, sekä virkistää metatiedot.",
+ "TaskRefreshLibrary": "Skannaa mediakirjasto",
+ "TaskRefreshChapterImagesDescription": "Luo pienoiskuvat videoille joissa on lukuja.",
+ "TaskRefreshChapterImages": "Eristä lukujen kuvat",
+ "TaskCleanCacheDescription": "Poistaa järjestelmälle tarpeettomat väliaikaistiedostot.",
+ "TaskCleanCache": "Tyhjennä välimuisti-hakemisto",
+ "TasksChannelsCategory": "Internet kanavat",
+ "TasksApplicationCategory": "Sovellus",
+ "TasksLibraryCategory": "Kirjasto"
}
diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json
index 88a7ac190..d1403c494 100644
--- a/Emby.Server.Implementations/Localization/Core/fr.json
+++ b/Emby.Server.Implementations/Localization/Core/fr.json
@@ -5,7 +5,7 @@
"Artists": "Artistes",
"AuthenticationSucceededWithUserName": "{0} authentifié avec succès",
"Books": "Livres",
- "CameraImageUploadedFrom": "Une nouvelle photo a été chargée depuis {0}",
+ "CameraImageUploadedFrom": "Une nouvelle photographie a été chargée depuis {0}",
"Channels": "Chaînes",
"ChapterNameValue": "Chapitre {0}",
"Collections": "Collections",
diff --git a/Emby.Server.Implementations/Localization/Core/hu.json b/Emby.Server.Implementations/Localization/Core/hu.json
index 6f226fe99..c5c3844e3 100644
--- a/Emby.Server.Implementations/Localization/Core/hu.json
+++ b/Emby.Server.Implementations/Localization/Core/hu.json
@@ -71,7 +71,7 @@
"ScheduledTaskFailedWithName": "{0} sikertelen",
"ScheduledTaskStartedWithName": "{0} elkezdve",
"ServerNameNeedsToBeRestarted": "{0}-t újra kell indítani",
- "Shows": "Műsorok",
+ "Shows": "Sorozatok",
"Songs": "Dalok",
"StartupEmbyServerIsLoading": "A Jellyfin Szerver betöltődik. Kérlek, próbáld újra hamarosan.",
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
diff --git a/Emby.Server.Implementations/Localization/Core/pt.json b/Emby.Server.Implementations/Localization/Core/pt.json
index 3d5f7cab2..661ee8603 100644
--- a/Emby.Server.Implementations/Localization/Core/pt.json
+++ b/Emby.Server.Implementations/Localization/Core/pt.json
@@ -91,5 +91,9 @@
"CameraImageUploadedFrom": "Uma nova imagem da câmara foi enviada a partir de {0}",
"AuthenticationSucceededWithUserName": "{0} autenticado com sucesso",
"Application": "Aplicação",
- "AppDeviceValues": "Aplicação {0}, Dispositivo: {1}"
+ "AppDeviceValues": "Aplicação {0}, Dispositivo: {1}",
+ "TaskCleanCache": "Limpar Diretório de Cache",
+ "TasksApplicationCategory": "Aplicação",
+ "TasksLibraryCategory": "Biblioteca",
+ "TasksMaintenanceCategory": "Manutenção"
}
diff --git a/Emby.Server.Implementations/Localization/Core/ur_PK.json b/Emby.Server.Implementations/Localization/Core/ur_PK.json
index 0967ef424..9a5874e29 100644
--- a/Emby.Server.Implementations/Localization/Core/ur_PK.json
+++ b/Emby.Server.Implementations/Localization/Core/ur_PK.json
@@ -1 +1,117 @@
-{}
+{
+ "HeaderFavoriteAlbums": "پسندیدہ البمز",
+ "HeaderNextUp": "اگلا",
+ "HeaderFavoriteArtists": "پسندیدہ فنکار",
+ "HeaderAlbumArtists": "البم کے فنکار",
+ "Movies": "فلمیں",
+ "HeaderFavoriteEpisodes": "پسندیدہ اقساط",
+ "Collections": "مجموعہ",
+ "Folders": "فولڈرز",
+ "HeaderLiveTV": "براہ راست ٹی وی",
+ "Channels": "چینل",
+ "HeaderContinueWatching": "دیکھنا جاری رکھیں",
+ "Playlists": "پلے لسٹس",
+ "ValueSpecialEpisodeName": "خاص - {0}",
+ "Shows": "شوز",
+ "Genres": "انواع",
+ "Artists": "فنکار",
+ "Sync": "مطابقت",
+ "Photos": "تصوریں",
+ "Albums": "البم",
+ "Favorites": "پسندیدہ",
+ "Songs": "گانے",
+ "Books": "کتابیں",
+ "HeaderFavoriteSongs": "پسندیدہ گانے",
+ "HeaderFavoriteShows": "پسندیدہ شوز",
+ "TaskDownloadMissingSubtitlesDescription": "میٹا ڈیٹا کی تشکیل پر مبنی ذیلی عنوانات کے غائب عنوانات انٹرنیٹ پے تلاش کرتا ہے۔",
+ "TaskDownloadMissingSubtitles": "غائب سب ٹائٹلز ڈاؤن لوڈ کریں",
+ "TaskRefreshChannelsDescription": "انٹرنیٹ چینل کی معلومات کو تازہ دم کرتا ہے۔",
+ "TaskRefreshChannels": "چینلز ریفریش کریں",
+ "TaskCleanTranscodeDescription": "ایک دن سے زیادہ پرانی ٹرانسکوڈ فائلوں کو حذف کرتا ہے۔",
+ "TaskCleanTranscode": "ٹرانس کوڈ ڈائرکٹری صاف کریں",
+ "TaskUpdatePluginsDescription": "پلگ انز کے لئے اپ ڈیٹس ڈاؤن لوڈ اور انسٹال کرتے ہیں جو خود بخود اپ ڈیٹ کرنے کیلئے تشکیل شدہ ہیں۔",
+ "TaskUpdatePlugins": "پلگ انز کو اپ ڈیٹ کریں",
+ "TaskRefreshPeopleDescription": "آپ کی میڈیا لائبریری میں اداکاروں اور ہدایت کاروں کے لئے میٹا ڈیٹا کی تازہ کاری۔",
+ "TaskRefreshPeople": "لوگوں کو تروتازہ کریں",
+ "TaskCleanLogsDescription": "لاگ فائلوں کو حذف کریں جو {0} دن سے زیادہ پرانی ہیں۔",
+ "TaskCleanLogs": "لاگ ڈائرکٹری کو صاف کریں",
+ "TaskRefreshLibraryDescription": "میڈیا لائبریری کو اسکین کرتا ھے ہر میٹا دیٹا کہ تازہ دم کرتا ھے.",
+ "TaskRefreshLibrary": "اسکین میڈیا لائبریری",
+ "TaskRefreshChapterImagesDescription": "بابوں والی ویڈیوز کے لئے تمبنیل بنایں۔",
+ "TaskRefreshChapterImages": "باب کی تصاویر نکالیں",
+ "TaskCleanCacheDescription": "فائلوں کو حذف کریں جنکی ضرورت نھیں ھے۔",
+ "TaskCleanCache": "کیش ڈائرکٹری کلیر کریں",
+ "TasksChannelsCategory": "انٹرنیٹ چینلز",
+ "TasksApplicationCategory": "پروگرام",
+ "TasksLibraryCategory": "لآیبریری",
+ "TasksMaintenanceCategory": "مرمت",
+ "VersionNumber": "ورژن {0}",
+ "ValueHasBeenAddedToLibrary": "{0} آپ کی میڈیا لائبریری میں شامل کر دیا گیا ہے",
+ "UserStoppedPlayingItemWithValues": "{0} نے {1} چلانا ختم کر دیا ھے {2} پے",
+ "UserStartedPlayingItemWithValues": "{0} چلا رہا ہے {1} {2} پے",
+ "UserPolicyUpdatedWithName": "صارف {0} کی پالیسی کیلئے تازہ کاری کی گئی ہے",
+ "UserPasswordChangedWithName": "صارف {0} کے لئے پاس ورڈ تبدیل کر دیا گیا ہے",
+ "UserOnlineFromDevice": "{0} آن لائن ہے {1} سے",
+ "UserOfflineFromDevice": "{0} سے منقطع ہوگیا ہے {1}",
+ "UserLockedOutWithName": "صارف {0} کو لاک آؤٹ کردیا گیا ہے",
+ "UserDownloadingItemWithValues": "{0} ڈاؤن لوڈ کر رھا ھے {1}",
+ "UserDeletedWithName": "صارف {0} کو ہٹا دیا گیا ہے",
+ "UserCreatedWithName": "صارف {0} تشکیل دیا گیا ہے",
+ "User": "صارف",
+ "TvShows": "ٹی وی کے پروگرام",
+ "System": "نظام",
+ "SubtitleDownloadFailureFromForItem": "ذیلی عنوانات {0} سے ڈاؤن لوڈ کرنے میں ناکام {1} کے لیے",
+ "StartupEmbyServerIsLoading": "جیلیفن سرور لوڈ ہورہا ہے۔ براہ کرم جلد ہی دوبارہ کوشش کریں۔",
+ "ServerNameNeedsToBeRestarted": "{0} دوبارہ چلانے کرنے کی ضرورت ہے",
+ "ScheduledTaskStartedWithName": "{0} شروع",
+ "ScheduledTaskFailedWithName": "{0} ناکام",
+ "ProviderValue": "فراہم کرنے والا: {0}",
+ "PluginUpdatedWithName": "{0} تازہ کاری کی گئی تھی",
+ "PluginUninstalledWithName": "[0} ہٹا دیا گیا تھا",
+ "PluginInstalledWithName": "{0} انسٹال کیا گیا تھا",
+ "Plugin": "پلگن",
+ "NotificationOptionVideoPlaybackStopped": "ویڈیو پلے بیک رک گیا",
+ "NotificationOptionVideoPlayback": "ویڈیو پلے بیک شروع ہوا",
+ "NotificationOptionUserLockedOut": "صارف کو لاک آؤٹ کیا گیا",
+ "NotificationOptionTaskFailed": "طے شدہ کام کی ناکامی",
+ "NotificationOptionServerRestartRequired": "سرور دوبارہ چلانے کرنے کی ضرورت ہے",
+ "NotificationOptionPluginUpdateInstalled": "پلگ ان اپ ڈیٹ انسٹال",
+ "NotificationOptionPluginUninstalled": "پلگ ان ہٹا دیا گیا",
+ "NotificationOptionPluginInstalled": "پلگ ان انسٹال ہوا",
+ "NotificationOptionPluginError": "پلگ ان کی ناکامی",
+ "NotificationOptionNewLibraryContent": "نیا مواد شامل کیا گیا",
+ "NotificationOptionInstallationFailed": "تنصیب کی ناکامی",
+ "NotificationOptionCameraImageUploaded": "کیمرے کی تصویر اپ لوڈ ہوگئی",
+ "NotificationOptionAudioPlaybackStopped": "آڈیو پلے بیک رک گیا",
+ "NotificationOptionAudioPlayback": "آڈیو پلے بیک شروع ہوا",
+ "NotificationOptionApplicationUpdateInstalled": "پروگرام اپ ڈیٹ انسٹال ہوچکا ھے",
+ "NotificationOptionApplicationUpdateAvailable": "پروگرام کی تازہ کاری دستیاب ہے",
+ "NewVersionIsAvailable": "جیلیفن سرور کا ایک نیا ورژن ڈاؤن لوڈ کے لئے دستیاب ہے۔",
+ "NameSeasonUnknown": "نامعلوم باب",
+ "NameSeasonNumber": "باب {0}",
+ "NameInstallFailed": "{0} تنصیب ناکام ہوگئی",
+ "MusicVideos": "موسیقی ویڈیو",
+ "Music": "موسیقی",
+ "MixedContent": "مخلوط مواد",
+ "MessageServerConfigurationUpdated": "سرور کو اپ ڈیٹ کر دیا گیا ہے",
+ "MessageNamedServerConfigurationUpdatedWithValue": "سرور ضمن {0} کو ترتیب دے دیا گیا ھے",
+ "MessageApplicationUpdatedTo": "جیلیفن سرور کو اپ ڈیٹ کیا ہے {0}",
+ "MessageApplicationUpdated": "جیلیفن سرور کو اپ ڈیٹ کر دیا گیا ہے",
+ "Latest": "تازہ ترین",
+ "LabelRunningTimeValue": "چلانے کی مدت",
+ "LabelIpAddressValue": "ای پی پتے {0}",
+ "ItemRemovedWithName": "لائبریری سے ہٹا دیا گیا ھے",
+ "ItemAddedWithName": "[0} لائبریری میں شامل کیا گیا ھے",
+ "Inherit": "وراثت میں",
+ "HomeVideos": "ہوم ویڈیو",
+ "HeaderRecordingGroups": "ریکارڈنگ گروپس",
+ "HeaderCameraUploads": "کیمرہ اپلوڈز",
+ "FailedLoginAttemptWithUserName": "لاگن کئ کوشش ناکام {0}",
+ "DeviceOnlineWithName": "{0} متصل ھو چکا ھے",
+ "DeviceOfflineWithName": "{0} منقطع ھو چکا ھے",
+ "ChapterNameValue": "باب",
+ "AuthenticationSucceededWithUserName": "{0} کامیابی کے ساتھ تصدیق ھوچکی ھے",
+ "CameraImageUploadedFrom": "ایک نئی کیمرہ تصویر اپ لوڈ کی گئی ہے {0}",
+ "Application": "پروگرام",
+ "AppDeviceValues": "پروگرام:{0}, آلہ:{1}"
+}
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index 4bd13df00..6691080bc 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -86,12 +86,9 @@ namespace MediaBrowser.Api
return Array.Empty<string>();
}
- if (removeEmpty)
- {
- return value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);
- }
-
- return value.Split(separator);
+ return removeEmpty
+ ? value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries)
+ : value.Split(separator);
}
public SemaphoreSlim GetTranscodingLock(string outputPath)
@@ -258,7 +255,7 @@ namespace MediaBrowser.Api
public void ReportTranscodingProgress(TranscodingJob job, StreamState state, TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
{
- var ticks = transcodingPosition.HasValue ? transcodingPosition.Value.Ticks : (long?)null;
+ var ticks = transcodingPosition?.Ticks;
if (job != null)
{
@@ -487,16 +484,9 @@ namespace MediaBrowser.Api
/// <returns>Task.</returns>
internal Task KillTranscodingJobs(string deviceId, string playSessionId, Func<string, bool> deleteFiles)
{
- return KillTranscodingJobs(j =>
- {
- if (!string.IsNullOrWhiteSpace(playSessionId))
- {
- return string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase);
- }
-
- return string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase);
-
- }, deleteFiles);
+ return KillTranscodingJobs(j => string.IsNullOrWhiteSpace(playSessionId)
+ ? string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase)
+ : string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase), deleteFiles);
}
/// <summary>
@@ -561,10 +551,7 @@ namespace MediaBrowser.Api
lock (job.ProcessLock)
{
- if (job.TranscodingThrottler != null)
- {
- job.TranscodingThrottler.Stop().GetAwaiter().GetResult();
- }
+ job.TranscodingThrottler?.Stop().GetAwaiter().GetResult();
var process = job.Process;
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index 112ee8f79..1a1d86362 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -58,12 +58,9 @@ namespace MediaBrowser.Api
public static string[] SplitValue(string value, char delim)
{
- if (value == null)
- {
- return Array.Empty<string>();
- }
-
- return value.Split(new[] { delim }, StringSplitOptions.RemoveEmptyEntries);
+ return value == null
+ ? Array.Empty<string>()
+ : value.Split(new[] { delim }, StringSplitOptions.RemoveEmptyEntries);
}
public static Guid[] GetGuids(string value)
@@ -97,19 +94,10 @@ namespace MediaBrowser.Api
var authenticatedUser = auth.User;
// If they're going to update the record of another user, they must be an administrator
- if (!userId.Equals(auth.UserId))
- {
- if (!authenticatedUser.Policy.IsAdministrator)
- {
- throw new SecurityException("Unauthorized access.");
- }
- }
- else if (restrictUserPreferences)
+ if ((!userId.Equals(auth.UserId) && !authenticatedUser.Policy.IsAdministrator)
+ || (restrictUserPreferences && !authenticatedUser.Policy.EnableUserPreferenceAccess))
{
- if (!authenticatedUser.Policy.EnableUserPreferenceAccess)
- {
- throw new SecurityException("Unauthorized access.");
- }
+ throw new SecurityException("Unauthorized access.");
}
}
@@ -138,8 +126,8 @@ namespace MediaBrowser.Api
options.Fields = hasFields.GetItemFields();
}
- if (!options.ContainsField(Model.Querying.ItemFields.RecursiveItemCount)
- || !options.ContainsField(Model.Querying.ItemFields.ChildCount))
+ if (!options.ContainsField(ItemFields.RecursiveItemCount)
+ || !options.ContainsField(ItemFields.ChildCount))
{
var client = authContext.GetAuthorizationInfo(Request).Client ?? string.Empty;
if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 ||
@@ -150,7 +138,7 @@ namespace MediaBrowser.Api
int oldLen = options.Fields.Length;
var arr = new ItemFields[oldLen + 1];
options.Fields.CopyTo(arr, 0);
- arr[oldLen] = Model.Querying.ItemFields.RecursiveItemCount;
+ arr[oldLen] = ItemFields.RecursiveItemCount;
options.Fields = arr;
}
@@ -166,7 +154,7 @@ namespace MediaBrowser.Api
int oldLen = options.Fields.Length;
var arr = new ItemFields[oldLen + 1];
options.Fields.CopyTo(arr, 0);
- arr[oldLen] = Model.Querying.ItemFields.ChildCount;
+ arr[oldLen] = ItemFields.ChildCount;
options.Fields = arr;
}
}
@@ -282,27 +270,21 @@ namespace MediaBrowser.Api
}).OfType<T>().FirstOrDefault();
- if (result == null)
+ result ??= libraryManager.GetItemList(new InternalItemsQuery
{
- result = libraryManager.GetItemList(new InternalItemsQuery
- {
- Name = name.Replace(BaseItem.SlugChar, '/'),
- IncludeItemTypes = new[] { typeof(T).Name },
- DtoOptions = dtoOptions
+ Name = name.Replace(BaseItem.SlugChar, '/'),
+ IncludeItemTypes = new[] { typeof(T).Name },
+ DtoOptions = dtoOptions
- }).OfType<T>().FirstOrDefault();
- }
+ }).OfType<T>().FirstOrDefault();
- if (result == null)
+ result ??= libraryManager.GetItemList(new InternalItemsQuery
{
- result = libraryManager.GetItemList(new InternalItemsQuery
- {
- Name = name.Replace(BaseItem.SlugChar, '?'),
- IncludeItemTypes = new[] { typeof(T).Name },
- DtoOptions = dtoOptions
+ Name = name.Replace(BaseItem.SlugChar, '?'),
+ IncludeItemTypes = new[] { typeof(T).Name },
+ DtoOptions = dtoOptions
- }).OfType<T>().FirstOrDefault();
- }
+ }).OfType<T>().FirstOrDefault();
return result;
}
diff --git a/MediaBrowser.Api/ChannelService.cs b/MediaBrowser.Api/ChannelService.cs
index 6139ba156..fd9b8c396 100644
--- a/MediaBrowser.Api/ChannelService.cs
+++ b/MediaBrowser.Api/ChannelService.cs
@@ -116,12 +116,9 @@ namespace MediaBrowser.Api
{
var val = Filters;
- if (string.IsNullOrEmpty(val))
- {
- return new ItemFilter[] { };
- }
-
- return val.Split(',').Select(v => (ItemFilter)Enum.Parse(typeof(ItemFilter), v, true));
+ return string.IsNullOrEmpty(val)
+ ? Array.Empty<ItemFilter>()
+ : val.Split(',').Select(v => Enum.Parse<ItemFilter>(v, true));
}
/// <summary>
@@ -173,14 +170,9 @@ namespace MediaBrowser.Api
/// <returns>IEnumerable{ItemFilter}.</returns>
public IEnumerable<ItemFilter> GetFilters()
{
- var val = Filters;
-
- if (string.IsNullOrEmpty(val))
- {
- return new ItemFilter[] { };
- }
-
- return val.Split(',').Select(v => (ItemFilter)Enum.Parse(typeof(ItemFilter), v, true));
+ return string.IsNullOrEmpty(Filters)
+ ? Array.Empty<ItemFilter>()
+ : Filters.Split(',').Select(v => Enum.Parse<ItemFilter>(v, true));
}
}
@@ -241,7 +233,7 @@ namespace MediaBrowser.Api
{
Limit = request.Limit,
StartIndex = request.StartIndex,
- ChannelIds = new Guid[] { new Guid(request.Id) },
+ ChannelIds = new[] { new Guid(request.Id) },
ParentId = string.IsNullOrWhiteSpace(request.FolderId) ? Guid.Empty : new Guid(request.FolderId),
OrderBy = request.GetOrderBy(),
DtoOptions = new Controller.Dto.DtoOptions
diff --git a/MediaBrowser.Api/Devices/DeviceService.cs b/MediaBrowser.Api/Devices/DeviceService.cs
index 8b63decd2..7004a2559 100644
--- a/MediaBrowser.Api/Devices/DeviceService.cs
+++ b/MediaBrowser.Api/Devices/DeviceService.cs
@@ -155,16 +155,14 @@ namespace MediaBrowser.Api.Devices
Id = id
});
}
- else
+
+ return _deviceManager.AcceptCameraUpload(deviceId, request.RequestStream, new LocalFileInfo
{
- return _deviceManager.AcceptCameraUpload(deviceId, request.RequestStream, new LocalFileInfo
- {
- MimeType = Request.ContentType,
- Album = album,
- Name = name,
- Id = id
- });
- }
+ MimeType = Request.ContentType,
+ Album = album,
+ Name = name,
+ Id = id
+ });
}
}
}
diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs
index 36b03f09c..d199ce154 100644
--- a/MediaBrowser.Api/EnvironmentService.cs
+++ b/MediaBrowser.Api/EnvironmentService.cs
@@ -258,12 +258,7 @@ namespace MediaBrowser.Api
return false;
}
- if (!request.IncludeDirectories && isDirectory)
- {
- return false;
- }
-
- return true;
+ return request.IncludeDirectories || !isDirectory;
});
return entries.Select(f => new FileSystemEntryInfo
diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs
index 25f23bcd1..5eb72cdb1 100644
--- a/MediaBrowser.Api/FilterService.cs
+++ b/MediaBrowser.Api/FilterService.cs
@@ -133,7 +133,7 @@ namespace MediaBrowser.Api
// Non recursive not yet supported for library folders
if ((request.Recursive ?? true) || parentItem is UserView || parentItem is ICollectionFolder)
{
- genreQuery.AncestorIds = parentItem == null ? Array.Empty<Guid>() : new Guid[] { parentItem.Id };
+ genreQuery.AncestorIds = parentItem == null ? Array.Empty<Guid>() : new[] { parentItem.Id };
}
else
{
@@ -231,7 +231,7 @@ namespace MediaBrowser.Api
EnableTotalRecordCount = false,
DtoOptions = new Controller.Dto.DtoOptions
{
- Fields = new ItemFields[] { ItemFields.Genres, ItemFields.Tags },
+ Fields = new[] { ItemFields.Genres, ItemFields.Tags },
EnableImages = false,
EnableUserData = false
}
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index c11e0c1b7..2e9b3e6cb 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -657,7 +657,7 @@ namespace MediaBrowser.Api.Images
if (!string.IsNullOrWhiteSpace(request.Format)
&& Enum.TryParse(request.Format, true, out ImageFormat format))
{
- return new ImageFormat[] { format };
+ return new[] { format };
}
return GetClientSupportedFormats();
@@ -750,24 +750,22 @@ namespace MediaBrowser.Api.Images
/// <returns>Task.</returns>
public async Task PostImage(BaseItem entity, Stream inputStream, ImageType imageType, string mimeType)
{
- using (var reader = new StreamReader(inputStream))
- {
- var text = await reader.ReadToEndAsync().ConfigureAwait(false);
+ using var reader = new StreamReader(inputStream);
+ var text = await reader.ReadToEndAsync().ConfigureAwait(false);
- var bytes = Convert.FromBase64String(text);
+ var bytes = Convert.FromBase64String(text);
- var memoryStream = new MemoryStream(bytes)
- {
- Position = 0
- };
+ var memoryStream = new MemoryStream(bytes)
+ {
+ Position = 0
+ };
- // Handle image/png; charset=utf-8
- mimeType = mimeType.Split(';').FirstOrDefault();
+ // Handle image/png; charset=utf-8
+ mimeType = mimeType.Split(';').FirstOrDefault();
- await _providerManager.SaveImage(entity, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false);
+ await _providerManager.SaveImage(entity, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false);
- entity.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
- }
+ entity.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
}
}
}
diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs
index f03f5efd8..222bb34d3 100644
--- a/MediaBrowser.Api/Images/RemoteImageService.cs
+++ b/MediaBrowser.Api/Images/RemoteImageService.cs
@@ -261,27 +261,25 @@ namespace MediaBrowser.Api.Images
/// <returns>Task.</returns>
private async Task DownloadImage(string url, Guid urlHash, string pointerCachePath)
{
- using (var result = await _httpClient.GetResponse(new HttpRequestOptions
+ using var result = await _httpClient.GetResponse(new HttpRequestOptions
{
Url = url,
BufferContent = false
- }).ConfigureAwait(false))
- {
- var ext = result.ContentType.Split('/').Last();
-
- var fullCachePath = GetFullCachePath(urlHash + "." + ext);
+ }).ConfigureAwait(false);
+ var ext = result.ContentType.Split('/').Last();
- Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
- using (var stream = result.Content)
- using (var filestream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true))
- {
- await stream.CopyToAsync(filestream).ConfigureAwait(false);
- }
+ var fullCachePath = GetFullCachePath(urlHash + "." + ext);
- Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
- File.WriteAllText(pointerCachePath, fullCachePath);
+ Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
+ using (var stream = result.Content)
+ {
+ using var filestream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true);
+ await stream.CopyToAsync(filestream).ConfigureAwait(false);
}
+
+ Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
+ File.WriteAllText(pointerCachePath, fullCachePath);
}
/// <summary>
diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs
index a76369a15..0bbe7e1cf 100644
--- a/MediaBrowser.Api/ItemLookupService.cs
+++ b/MediaBrowser.Api/ItemLookupService.cs
@@ -305,9 +305,16 @@ namespace MediaBrowser.Api
Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
using (var stream = result.Content)
- using (var filestream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true))
{
- await stream.CopyToAsync(filestream).ConfigureAwait(false);
+ using var fileStream = new FileStream(
+ fullCachePath,
+ FileMode.Create,
+ FileAccess.Write,
+ FileShare.Read,
+ IODefaults.FileStreamBufferSize,
+ true);
+
+ await stream.CopyToAsync(fileStream).ConfigureAwait(false);
}
Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index c81e89ca3..2db6d717a 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -263,8 +263,7 @@ namespace MediaBrowser.Api
item.Overview = request.Overview;
item.Genres = request.Genres;
- var episode = item as Episode;
- if (episode != null)
+ if (item is Episode episode)
{
episode.AirsAfterSeasonNumber = request.AirsAfterSeasonNumber;
episode.AirsBeforeEpisodeNumber = request.AirsBeforeEpisodeNumber;
@@ -302,14 +301,12 @@ namespace MediaBrowser.Api
item.PreferredMetadataCountryCode = request.PreferredMetadataCountryCode;
item.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
- var hasDisplayOrder = item as IHasDisplayOrder;
- if (hasDisplayOrder != null)
+ if (item is IHasDisplayOrder hasDisplayOrder)
{
hasDisplayOrder.DisplayOrder = request.DisplayOrder;
}
- var hasAspectRatio = item as IHasAspectRatio;
- if (hasAspectRatio != null)
+ if (item is IHasAspectRatio hasAspectRatio)
{
hasAspectRatio.AspectRatio = request.AspectRatio;
}
@@ -337,16 +334,14 @@ namespace MediaBrowser.Api
item.ProviderIds = request.ProviderIds;
- var video = item as Video;
- if (video != null)
+ if (item is Video video)
{
video.Video3DFormat = request.Video3DFormat;
}
if (request.AlbumArtists != null)
{
- var hasAlbumArtists = item as IHasAlbumArtist;
- if (hasAlbumArtists != null)
+ if (item is IHasAlbumArtist hasAlbumArtists)
{
hasAlbumArtists.AlbumArtists = request
.AlbumArtists
@@ -357,8 +352,7 @@ namespace MediaBrowser.Api
if (request.ArtistItems != null)
{
- var hasArtists = item as IHasArtist;
- if (hasArtists != null)
+ if (item is IHasArtist hasArtists)
{
hasArtists.Artists = request
.ArtistItems
@@ -367,20 +361,17 @@ namespace MediaBrowser.Api
}
}
- var song = item as Audio;
- if (song != null)
+ if (item is Audio song)
{
song.Album = request.Album;
}
- var musicVideo = item as MusicVideo;
- if (musicVideo != null)
+ if (item is MusicVideo musicVideo)
{
musicVideo.Album = request.Album;
}
- var series = item as Series;
- if (series != null)
+ if (item is Series series)
{
series.Status = GetSeriesStatus(request);
@@ -400,7 +391,6 @@ namespace MediaBrowser.Api
}
return (SeriesStatus)Enum.Parse(typeof(SeriesStatus), item.Status, true);
-
}
}
}
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 15284958d..a54640b2f 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -348,28 +348,19 @@ namespace MediaBrowser.Api.Library
private string[] GetRepresentativeItemTypes(string contentType)
{
- switch (contentType)
+ return contentType switch
{
- case CollectionType.BoxSets:
- return new string[] { "BoxSet" };
- case CollectionType.Playlists:
- return new string[] { "Playlist" };
- case CollectionType.Movies:
- return new string[] { "Movie" };
- case CollectionType.TvShows:
- return new string[] { "Series", "Season", "Episode" };
- case CollectionType.Books:
- return new string[] { "Book" };
- case CollectionType.Music:
- return new string[] { "MusicAlbum", "MusicArtist", "Audio", "MusicVideo" };
- case CollectionType.HomeVideos:
- case CollectionType.Photos:
- return new string[] { "Video", "Photo" };
- case CollectionType.MusicVideos:
- return new string[] { "MusicVideo" };
- default:
- return new string[] { "Series", "Season", "Episode", "Movie" };
- }
+ CollectionType.BoxSets => new[] {"BoxSet"},
+ CollectionType.Playlists => new[] {"Playlist"},
+ CollectionType.Movies => new[] {"Movie"},
+ CollectionType.TvShows => new[] {"Series", "Season", "Episode"},
+ CollectionType.Books => new[] {"Book"},
+ CollectionType.Music => new[] {"MusicAlbum", "MusicArtist", "Audio", "MusicVideo"},
+ CollectionType.HomeVideos => new[] {"Video", "Photo"},
+ CollectionType.Photos => new[] {"Video", "Photo"},
+ CollectionType.MusicVideos => new[] {"MusicVideo"},
+ _ => new[] {"Series", "Season", "Episode", "Movie"}
+ };
}
private bool IsSaverEnabledByDefault(string name, string[] itemTypes, bool isNewLibrary)
@@ -397,54 +388,22 @@ namespace MediaBrowser.Api.Library
{
if (string.Equals(name, "TheMovieDb", StringComparison.OrdinalIgnoreCase))
{
- if (string.Equals(type, "Series", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- if (string.Equals(type, "Season", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- if (string.Equals(type, "Episode", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- if (string.Equals(type, "MusicVideo", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- return true;
- }
- else if (string.Equals(name, "TheTVDB", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- else if (string.Equals(name, "The Open Movie Database", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- else if (string.Equals(name, "TheAudioDB", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- else if (string.Equals(name, "MusicBrainz", StringComparison.OrdinalIgnoreCase))
- {
- return true;
+ return !(string.Equals(type, "Season", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(type, "Episode", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(type, "MusicVideo", StringComparison.OrdinalIgnoreCase));
}
- return false;
+ return string.Equals(name, "TheTVDB", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(name, "TheAudioDB", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(name, "MusicBrainz", StringComparison.OrdinalIgnoreCase);
}
var metadataOptions = ServerConfigurationManager.Configuration.MetadataOptions
.Where(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase))
.ToArray();
- if (metadataOptions.Length == 0)
- {
- return true;
- }
-
- return metadataOptions.Any(i => !i.DisabledMetadataFetchers.Contains(name, StringComparer.OrdinalIgnoreCase));
+ return metadataOptions.Length == 0
+ || metadataOptions.Any(i => !i.DisabledMetadataFetchers.Contains(name, StringComparer.OrdinalIgnoreCase));
}
private bool IsImageFetcherEnabledByDefault(string name, string type, bool isNewLibrary)
@@ -453,50 +412,17 @@ namespace MediaBrowser.Api.Library
{
if (string.Equals(name, "TheMovieDb", StringComparison.OrdinalIgnoreCase))
{
- if (string.Equals(type, "Series", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- if (string.Equals(type, "Season", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- if (string.Equals(type, "Episode", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- if (string.Equals(type, "MusicVideo", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- return true;
- }
- else if (string.Equals(name, "TheTVDB", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- else if (string.Equals(name, "The Open Movie Database", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- else if (string.Equals(name, "TheAudioDB", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- else if (string.Equals(name, "Emby Designs", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- else if (string.Equals(name, "Screen Grabber", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- else if (string.Equals(name, "Image Extractor", StringComparison.OrdinalIgnoreCase))
- {
- return true;
+ return !string.Equals(type, "Series", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(type, "Season", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(type, "Episode", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(type, "MusicVideo", StringComparison.OrdinalIgnoreCase);
}
- return false;
+ return string.Equals(name, "TheTVDB", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(name, "Screen Grabber", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(name, "TheAudioDB", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(name, "Emby Designs", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(name, "Image Extractor", StringComparison.OrdinalIgnoreCase);
}
var metadataOptions = ServerConfigurationManager.Configuration.MetadataOptions
@@ -561,8 +487,7 @@ namespace MediaBrowser.Api.Library
foreach (var type in types)
{
- ImageOption[] defaultImageOptions = null;
- TypeOptions.DefaultImageOptions.TryGetValue(type, out defaultImageOptions);
+ TypeOptions.DefaultImageOptions.TryGetValue(type, out var defaultImageOptions);
typeOptions.Add(new LibraryTypeOptions
{
@@ -609,8 +534,6 @@ namespace MediaBrowser.Api.Library
public object Get(GetSimilarItems request)
{
- var user = !request.UserId.Equals(Guid.Empty) ? _userManager.GetUserById(request.UserId) : null;
-
var item = string.IsNullOrEmpty(request.Id) ?
(!request.UserId.Equals(Guid.Empty) ? _libraryManager.GetUserRootFolder() :
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
@@ -668,7 +591,7 @@ namespace MediaBrowser.Api.Library
// ExcludeArtistIds
if (!string.IsNullOrEmpty(request.ExcludeArtistIds))
{
- query.ExcludeArtistIds = BaseApiService.GetGuids(request.ExcludeArtistIds);
+ query.ExcludeArtistIds = GetGuids(request.ExcludeArtistIds);
}
List<BaseItem> itemsResult;
@@ -689,7 +612,6 @@ namespace MediaBrowser.Api.Library
var result = new QueryResult<BaseItemDto>
{
Items = returnList,
-
TotalRecordCount = itemsResult.Count
};
@@ -919,12 +841,10 @@ namespace MediaBrowser.Api.Library
private BaseItem TranslateParentItem(BaseItem item, User user)
{
- if (item.GetParent() is AggregateFolder)
- {
- return _libraryManager.GetUserRootFolder().GetChildren(user, true).FirstOrDefault(i => i.PhysicalLocations.Contains(item.Path));
- }
-
- return item;
+ return item.GetParent() is AggregateFolder
+ ? _libraryManager.GetUserRootFolder().GetChildren(user, true)
+ .FirstOrDefault(i => i.PhysicalLocations.Contains(item.Path))
+ : item;
}
/// <summary>
@@ -1086,7 +1006,7 @@ namespace MediaBrowser.Api.Library
var item = string.IsNullOrEmpty(request.Id)
? (!request.UserId.Equals(Guid.Empty)
? _libraryManager.GetUserRootFolder()
- : (Folder)_libraryManager.RootFolder)
+ : _libraryManager.RootFolder)
: _libraryManager.GetItemById(request.Id);
if (item == null)
@@ -1094,18 +1014,13 @@ namespace MediaBrowser.Api.Library
throw new ResourceNotFoundException("Item not found.");
}
- BaseItem[] themeItems = Array.Empty<BaseItem>();
+ IEnumerable<BaseItem> themeItems;
while (true)
{
- themeItems = item.GetThemeSongs().ToArray();
-
- if (themeItems.Length > 0)
- {
- break;
- }
+ themeItems = item.GetThemeSongs();
- if (!request.InheritFromParent)
+ if (themeItems.Any() || !request.InheritFromParent)
{
break;
}
@@ -1119,11 +1034,9 @@ namespace MediaBrowser.Api.Library
}
var dtoOptions = GetDtoOptions(_authContext, request);
-
- var dtos = themeItems
- .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
-
- var items = dtos.ToArray();
+ var items = themeItems
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item))
+ .ToArray();
return new ThemeMediaResult
{
@@ -1140,9 +1053,7 @@ namespace MediaBrowser.Api.Library
/// <returns>System.Object.</returns>
public object Get(GetThemeVideos request)
{
- var result = GetThemeVideos(request);
-
- return ToOptimizedResult(result);
+ return ToOptimizedResult(GetThemeVideos(request));
}
public ThemeMediaResult GetThemeVideos(GetThemeVideos request)
@@ -1152,7 +1063,7 @@ namespace MediaBrowser.Api.Library
var item = string.IsNullOrEmpty(request.Id)
? (!request.UserId.Equals(Guid.Empty)
? _libraryManager.GetUserRootFolder()
- : (Folder)_libraryManager.RootFolder)
+ : _libraryManager.RootFolder)
: _libraryManager.GetItemById(request.Id);
if (item == null)
@@ -1160,18 +1071,13 @@ namespace MediaBrowser.Api.Library
throw new ResourceNotFoundException("Item not found.");
}
- BaseItem[] themeItems = Array.Empty<BaseItem>();
+ IEnumerable<BaseItem> themeItems;
while (true)
{
- themeItems = item.GetThemeVideos().ToArray();
-
- if (themeItems.Length > 0)
- {
- break;
- }
+ themeItems = item.GetThemeVideos();
- if (!request.InheritFromParent)
+ if (themeItems.Any() || !request.InheritFromParent)
{
break;
}
@@ -1186,10 +1092,9 @@ namespace MediaBrowser.Api.Library
var dtoOptions = GetDtoOptions(_authContext, request);
- var dtos = themeItems
- .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
-
- var items = dtos.ToArray();
+ var items = themeItems
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item))
+ .ToArray();
return new ThemeMediaResult
{
diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs
index c071b42f7..1e300814f 100644
--- a/MediaBrowser.Api/Library/LibraryStructureService.cs
+++ b/MediaBrowser.Api/Library/LibraryStructureService.cs
@@ -327,15 +327,11 @@ namespace MediaBrowser.Api.Library
try
{
- var mediaPath = request.PathInfo;
-
- if (mediaPath == null)
+ var mediaPath = request.PathInfo ?? new MediaPathInfo
{
- mediaPath = new MediaPathInfo
- {
- Path = request.Path
- };
- }
+ Path = request.Path
+ };
+
_libraryManager.AddMediaPath(request.Name, mediaPath);
}
finally
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 4b4496139..5fe4c0cca 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -885,11 +885,10 @@ namespace MediaBrowser.Api.LiveTv
{
// SchedulesDirect requires a SHA1 hash of the user's password
// https://github.com/SchedulesDirect/JSON-Service/wiki/API-20141201#obtain-a-token
- using (SHA1 sha = SHA1.Create())
- {
- return Hex.Encode(
- sha.ComputeHash(Encoding.UTF8.GetBytes(str)));
- }
+ using SHA1 sha = SHA1.Create();
+
+ return Hex.Encode(
+ sha.ComputeHash(Encoding.UTF8.GetBytes(str)));
}
public void Delete(DeleteListingProvider request)
@@ -1050,8 +1049,7 @@ namespace MediaBrowser.Api.LiveTv
{
query.IsSeries = true;
- var series = _libraryManager.GetItemById(request.LibrarySeriesId) as Series;
- if (series != null)
+ if (_libraryManager.GetItemById(request.LibrarySeriesId) is Series series)
{
query.Name = series.Name;
}
diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
index 889ebc928..46da8b909 100644
--- a/MediaBrowser.Api/Movies/MoviesService.cs
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -394,7 +394,7 @@ namespace MediaBrowser.Api.Movies
{
var people = _libraryManager.GetPeople(new InternalPeopleQuery
{
- PersonTypes = new string[]
+ PersonTypes = new[]
{
PersonType.Director
}
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 5029ce0bb..eb44cb426 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -137,12 +137,9 @@ namespace MediaBrowser.Api.Playback
var ext = outputFileExtension.ToLowerInvariant();
var folder = ServerConfigurationManager.GetTranscodePath();
- if (EnableOutputInSubFolder)
- {
- return Path.Combine(folder, filename, filename + ext);
- }
-
- return Path.Combine(folder, filename + ext);
+ return EnableOutputInSubFolder
+ ? Path.Combine(folder, filename, filename + ext)
+ : Path.Combine(folder, filename + ext);
}
protected virtual string GetDefaultEncoderPreset()
@@ -248,14 +245,8 @@ namespace MediaBrowser.Api.Playback
if (state.VideoRequest != null
&& string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- if (string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- logFilePrefix = "ffmpeg-remux";
- }
- else
- {
- logFilePrefix = "ffmpeg-directstream";
- }
+ logFilePrefix = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase)
+ ? "ffmpeg-remux" : "ffmpeg-directstream";
}
var logFilePath = Path.Combine(ServerConfigurationManager.ApplicationPaths.LogDirectoryPath, logFilePrefix + "-" + Guid.NewGuid() + ".txt");
@@ -389,195 +380,181 @@ namespace MediaBrowser.Api.Playback
continue;
}
- if (i == 0)
- {
- request.DeviceProfileId = val;
- }
- else if (i == 1)
- {
- request.DeviceId = val;
- }
- else if (i == 2)
- {
- request.MediaSourceId = val;
- }
- else if (i == 3)
- {
- request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
- }
- else if (i == 4)
- {
- if (videoRequest != null)
- {
- videoRequest.VideoCodec = val;
- }
- }
- else if (i == 5)
- {
- request.AudioCodec = val;
- }
- else if (i == 6)
- {
- if (videoRequest != null)
- {
- videoRequest.AudioStreamIndex = int.Parse(val, CultureInfo.InvariantCulture);
- }
- }
- else if (i == 7)
- {
- if (videoRequest != null)
- {
- videoRequest.SubtitleStreamIndex = int.Parse(val, CultureInfo.InvariantCulture);
- }
- }
- else if (i == 8)
- {
- if (videoRequest != null)
- {
- videoRequest.VideoBitRate = int.Parse(val, CultureInfo.InvariantCulture);
- }
- }
- else if (i == 9)
- {
- request.AudioBitRate = int.Parse(val, CultureInfo.InvariantCulture);
- }
- else if (i == 10)
- {
- request.MaxAudioChannels = int.Parse(val, CultureInfo.InvariantCulture);
- }
- else if (i == 11)
- {
- if (videoRequest != null)
- {
- videoRequest.MaxFramerate = float.Parse(val, CultureInfo.InvariantCulture);
- }
- }
- else if (i == 12)
- {
- if (videoRequest != null)
- {
- videoRequest.MaxWidth = int.Parse(val, CultureInfo.InvariantCulture);
- }
- }
- else if (i == 13)
- {
- if (videoRequest != null)
- {
- videoRequest.MaxHeight = int.Parse(val, CultureInfo.InvariantCulture);
- }
- }
- else if (i == 14)
- {
- request.StartTimeTicks = long.Parse(val, CultureInfo.InvariantCulture);
- }
- else if (i == 15)
- {
- if (videoRequest != null)
- {
- videoRequest.Level = val;
- }
- }
- else if (i == 16)
- {
- if (videoRequest != null)
- {
- videoRequest.MaxRefFrames = int.Parse(val, CultureInfo.InvariantCulture);
- }
- }
- else if (i == 17)
- {
- if (videoRequest != null)
- {
- videoRequest.MaxVideoBitDepth = int.Parse(val, CultureInfo.InvariantCulture);
- }
- }
- else if (i == 18)
- {
- if (videoRequest != null)
- {
- videoRequest.Profile = val;
- }
- }
- else if (i == 19)
- {
- // cabac no longer used
- }
- else if (i == 20)
- {
- request.PlaySessionId = val;
- }
- else if (i == 21)
- {
- // api_key
- }
- else if (i == 22)
- {
- request.LiveStreamId = val;
- }
- else if (i == 23)
- {
- // Duplicating ItemId because of MediaMonkey
- }
- else if (i == 24)
- {
- if (videoRequest != null)
- {
- videoRequest.CopyTimestamps = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
- }
- }
- else if (i == 25)
- {
- if (!string.IsNullOrWhiteSpace(val) && videoRequest != null)
- {
- if (Enum.TryParse(val, out SubtitleDeliveryMethod method))
+ switch (i)
+ {
+ case 0:
+ request.DeviceProfileId = val;
+ break;
+ case 1:
+ request.DeviceId = val;
+ break;
+ case 2:
+ request.MediaSourceId = val;
+ break;
+ case 3:
+ request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
+ break;
+ case 4:
+ if (videoRequest != null)
{
- videoRequest.SubtitleMethod = method;
+ videoRequest.VideoCodec = val;
}
- }
- }
- else if (i == 26)
- {
- request.TranscodingMaxAudioChannels = int.Parse(val, CultureInfo.InvariantCulture);
- }
- else if (i == 27)
- {
- if (videoRequest != null)
- {
- videoRequest.EnableSubtitlesInManifest = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
- }
- }
- else if (i == 28)
- {
- request.Tag = val;
- }
- else if (i == 29)
- {
- if (videoRequest != null)
- {
- videoRequest.RequireAvc = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
- }
- }
- else if (i == 30)
- {
- request.SubtitleCodec = val;
- }
- else if (i == 31)
- {
- if (videoRequest != null)
- {
- videoRequest.RequireNonAnamorphic = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
- }
- }
- else if (i == 32)
- {
- if (videoRequest != null)
- {
- videoRequest.DeInterlace = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
- }
- }
- else if (i == 33)
- {
- request.TranscodeReasons = val;
+
+ break;
+ case 5:
+ request.AudioCodec = val;
+ break;
+ case 6:
+ if (videoRequest != null)
+ {
+ videoRequest.AudioStreamIndex = int.Parse(val, CultureInfo.InvariantCulture);
+ }
+
+ break;
+ case 7:
+ if (videoRequest != null)
+ {
+ videoRequest.SubtitleStreamIndex = int.Parse(val, CultureInfo.InvariantCulture);
+ }
+
+ break;
+ case 8:
+ if (videoRequest != null)
+ {
+ videoRequest.VideoBitRate = int.Parse(val, CultureInfo.InvariantCulture);
+ }
+
+ break;
+ case 9:
+ request.AudioBitRate = int.Parse(val, CultureInfo.InvariantCulture);
+ break;
+ case 10:
+ request.MaxAudioChannels = int.Parse(val, CultureInfo.InvariantCulture);
+ break;
+ case 11:
+ if (videoRequest != null)
+ {
+ videoRequest.MaxFramerate = float.Parse(val, CultureInfo.InvariantCulture);
+ }
+
+ break;
+ case 12:
+ if (videoRequest != null)
+ {
+ videoRequest.MaxWidth = int.Parse(val, CultureInfo.InvariantCulture);
+ }
+
+ break;
+ case 13:
+ if (videoRequest != null)
+ {
+ videoRequest.MaxHeight = int.Parse(val, CultureInfo.InvariantCulture);
+ }
+
+ break;
+ case 14:
+ request.StartTimeTicks = long.Parse(val, CultureInfo.InvariantCulture);
+ break;
+ case 15:
+ if (videoRequest != null)
+ {
+ videoRequest.Level = val;
+ }
+
+ break;
+ case 16:
+ if (videoRequest != null)
+ {
+ videoRequest.MaxRefFrames = int.Parse(val, CultureInfo.InvariantCulture);
+ }
+
+ break;
+ case 17:
+ if (videoRequest != null)
+ {
+ videoRequest.MaxVideoBitDepth = int.Parse(val, CultureInfo.InvariantCulture);
+ }
+
+ break;
+ case 18:
+ if (videoRequest != null)
+ {
+ videoRequest.Profile = val;
+ }
+
+ break;
+ case 19:
+ // cabac no longer used
+ break;
+ case 20:
+ request.PlaySessionId = val;
+ break;
+ case 21:
+ // api_key
+ break;
+ case 22:
+ request.LiveStreamId = val;
+ break;
+ case 23:
+ // Duplicating ItemId because of MediaMonkey
+ break;
+ case 24:
+ if (videoRequest != null)
+ {
+ videoRequest.CopyTimestamps = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
+ }
+
+ break;
+ case 25:
+ if (!string.IsNullOrWhiteSpace(val) && videoRequest != null)
+ {
+ if (Enum.TryParse(val, out SubtitleDeliveryMethod method))
+ {
+ videoRequest.SubtitleMethod = method;
+ }
+ }
+
+ break;
+ case 26:
+ request.TranscodingMaxAudioChannels = int.Parse(val, CultureInfo.InvariantCulture);
+ break;
+ case 27:
+ if (videoRequest != null)
+ {
+ videoRequest.EnableSubtitlesInManifest = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
+ }
+
+ break;
+ case 28:
+ request.Tag = val;
+ break;
+ case 29:
+ if (videoRequest != null)
+ {
+ videoRequest.RequireAvc = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
+ }
+
+ break;
+ case 30:
+ request.SubtitleCodec = val;
+ break;
+ case 31:
+ if (videoRequest != null)
+ {
+ videoRequest.RequireNonAnamorphic = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
+ }
+
+ break;
+ case 32:
+ if (videoRequest != null)
+ {
+ videoRequest.DeInterlace = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
+ }
+
+ break;
+ case 33:
+ request.TranscodeReasons = val;
+ break;
}
}
}
@@ -630,14 +607,9 @@ namespace MediaBrowser.Api.Playback
throw new ArgumentException("Invalid timeseek header");
}
int index = value.IndexOf('-');
- if (index == -1)
- {
- value = value.Substring(Npt.Length);
- }
- else
- {
- value = value.Substring(Npt.Length, index - Npt.Length);
- }
+ value = index == -1
+ ? value.Substring(Npt.Length)
+ : value.Substring(Npt.Length, index - Npt.Length);
if (value.IndexOf(':') == -1)
{
@@ -856,21 +828,11 @@ namespace MediaBrowser.Api.Playback
{
state.DeviceProfile = DlnaManager.GetProfile(state.Request.DeviceProfileId);
}
- else
+ else if (!string.IsNullOrWhiteSpace(state.Request.DeviceId))
{
- if (!string.IsNullOrWhiteSpace(state.Request.DeviceId))
- {
- var caps = DeviceManager.GetCapabilities(state.Request.DeviceId);
+ var caps = DeviceManager.GetCapabilities(state.Request.DeviceId);
- if (caps != null)
- {
- state.DeviceProfile = caps.DeviceProfile;
- }
- else
- {
- state.DeviceProfile = DlnaManager.GetProfile(headers);
- }
- }
+ state.DeviceProfile = caps == null ? DlnaManager.GetProfile(headers) : caps.DeviceProfile;
}
var profile = state.DeviceProfile;
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index 0cbfe4bdf..52962366c 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -140,7 +140,7 @@ namespace MediaBrowser.Api.Playback.Hls
if (isLive)
{
- job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType);
+ job ??= ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType);
if (job != null)
{
@@ -156,7 +156,7 @@ namespace MediaBrowser.Api.Playback.Hls
var playlistText = GetMasterPlaylistFileText(playlist, videoBitrate + audioBitrate, baselineStreamBitrate);
- job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType);
+ job ??= ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType);
if (job != null)
{
@@ -168,22 +168,19 @@ namespace MediaBrowser.Api.Playback.Hls
private string GetLivePlaylistText(string path, int segmentLength)
{
- using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
- {
- using (var reader = new StreamReader(stream))
- {
- var text = reader.ReadToEnd();
+ using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+ using var reader = new StreamReader(stream);
- text = text.Replace("#EXTM3U", "#EXTM3U\n#EXT-X-PLAYLIST-TYPE:EVENT");
+ var text = reader.ReadToEnd();
- var newDuration = "#EXT-X-TARGETDURATION:" + segmentLength.ToString(CultureInfo.InvariantCulture);
+ text = text.Replace("#EXTM3U", "#EXTM3U\n#EXT-X-PLAYLIST-TYPE:EVENT");
- text = text.Replace("#EXT-X-TARGETDURATION:" + (segmentLength - 1).ToString(CultureInfo.InvariantCulture), newDuration, StringComparison.OrdinalIgnoreCase);
- //text = text.Replace("#EXT-X-TARGETDURATION:" + (segmentLength + 1).ToString(CultureInfo.InvariantCulture), newDuration, StringComparison.OrdinalIgnoreCase);
+ var newDuration = "#EXT-X-TARGETDURATION:" + segmentLength.ToString(CultureInfo.InvariantCulture);
- return text;
- }
- }
+ text = text.Replace("#EXT-X-TARGETDURATION:" + (segmentLength - 1).ToString(CultureInfo.InvariantCulture), newDuration, StringComparison.OrdinalIgnoreCase);
+ //text = text.Replace("#EXT-X-TARGETDURATION:" + (segmentLength + 1).ToString(CultureInfo.InvariantCulture), newDuration, StringComparison.OrdinalIgnoreCase);
+
+ return text;
}
private string GetMasterPlaylistFileText(string firstPlaylist, int bitrate, int baselineStreamBitrate)
@@ -212,29 +209,25 @@ namespace MediaBrowser.Api.Playback.Hls
try
{
// Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written
- using (var fileStream = GetPlaylistFileStream(playlist))
+ using var fileStream = GetPlaylistFileStream(playlist);
+ using var reader = new StreamReader(fileStream);
+ var count = 0;
+
+ while (!reader.EndOfStream)
{
- using (var reader = new StreamReader(fileStream))
- {
- var count = 0;
+ var line = reader.ReadLine();
- while (!reader.EndOfStream)
+ if (line.IndexOf("#EXTINF:", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ count++;
+ if (count >= segmentCount)
{
- var line = reader.ReadLine();
-
- if (line.IndexOf("#EXTINF:", StringComparison.OrdinalIgnoreCase) != -1)
- {
- count++;
- if (count >= segmentCount)
- {
- Logger.LogDebug("Finished waiting for {0} segments in {1}", segmentCount, playlist);
- return;
- }
- }
+ Logger.LogDebug("Finished waiting for {0} segments in {1}", segmentCount, playlist);
+ return;
}
- await Task.Delay(100, cancellationToken).ConfigureAwait(false);
}
}
+ await Task.Delay(100, cancellationToken).ConfigureAwait(false);
}
catch (IOException)
{
@@ -247,17 +240,13 @@ namespace MediaBrowser.Api.Playback.Hls
protected Stream GetPlaylistFileStream(string path)
{
- var tmpPath = path + ".tmp";
- tmpPath = path;
-
- try
- {
- return new FileStream(tmpPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, FileOptions.SequentialScan);
- }
- catch (IOException)
- {
- return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, FileOptions.SequentialScan);
- }
+ return new FileStream(
+ path,
+ FileMode.Open,
+ FileAccess.Read,
+ FileShare.ReadWrite,
+ IODefaults.FileStreamBufferSize,
+ FileOptions.SequentialScan);
}
protected override string GetCommandLineArguments(string outputPath, EncodingOptions encodingOptions, StreamState state, bool isEncoding)
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index 3348a3187..20e18cc26 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -284,7 +284,7 @@ namespace MediaBrowser.Api.Playback.Hls
//}
Logger.LogDebug("returning {0} [general case]", segmentPath);
- job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
+ job ??= ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false);
}
@@ -438,8 +438,7 @@ namespace MediaBrowser.Api.Playback.Hls
{
var segmentId = "0";
- var segmentRequest = request as GetHlsVideoSegment;
- if (segmentRequest != null)
+ if (request is GetHlsVideoSegment segmentRequest)
{
segmentId = segmentRequest.SegmentId;
}
@@ -690,8 +689,7 @@ namespace MediaBrowser.Api.Playback.Hls
return false;
}
- var request = state.Request as IMasterHlsRequest;
- if (request != null && !request.EnableAdaptiveBitrateStreaming)
+ if (state.Request is IMasterHlsRequest request && !request.EnableAdaptiveBitrateStreaming)
{
return false;
}
@@ -936,7 +934,7 @@ namespace MediaBrowser.Api.Playback.Hls
var framerate = state.VideoStream?.RealFrameRate;
- if (framerate != null && framerate.HasValue)
+ if (framerate.HasValue)
{
// This is to make sure keyframe interval is limited to our segment,
// as forcing keyframes is not enough.
diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs
index d74ec3ca6..3638feaa3 100644
--- a/MediaBrowser.Api/Playback/MediaInfoService.cs
+++ b/MediaBrowser.Api/Playback/MediaInfoService.cs
@@ -234,7 +234,7 @@ namespace MediaBrowser.Api.Playback
OpenToken = mediaSource.OpenToken
}).ConfigureAwait(false);
- info.MediaSources = new MediaSourceInfo[] { openStreamResult.MediaSource };
+ info.MediaSources = new[] { openStreamResult.MediaSource };
}
}
@@ -289,7 +289,7 @@ namespace MediaBrowser.Api.Playback
{
var mediaSource = await _mediaSourceManager.GetLiveStream(liveStreamId, CancellationToken.None).ConfigureAwait(false);
- mediaSources = new MediaSourceInfo[] { mediaSource };
+ mediaSources = new[] { mediaSource };
}
if (mediaSources.Length == 0)
@@ -366,7 +366,7 @@ namespace MediaBrowser.Api.Playback
var options = new VideoOptions
{
- MediaSources = new MediaSourceInfo[] { mediaSource },
+ MediaSources = new[] { mediaSource },
Context = EncodingContext.Streaming,
DeviceId = auth.DeviceId,
ItemId = item.Id,
@@ -572,8 +572,7 @@ namespace MediaBrowser.Api.Playback
{
attachment.DeliveryUrl = string.Format(
CultureInfo.InvariantCulture,
- "{0}/Videos/{1}/{2}/Attachments/{3}",
- ServerConfigurationManager.Configuration.BaseUrl,
+ "/Videos/{0}/{1}/Attachments/{2}",
item.Id,
mediaSource.Id,
attachment.Index);
@@ -583,7 +582,7 @@ namespace MediaBrowser.Api.Playback
private long? GetMaxBitrate(long? clientMaxBitrate, User user)
{
var maxBitrate = clientMaxBitrate;
- var remoteClientMaxBitrate = user == null ? 0 : user.Policy.RemoteClientBitrateLimit;
+ var remoteClientMaxBitrate = user?.Policy.RemoteClientBitrateLimit ?? 0;
if (remoteClientMaxBitrate <= 0)
{
@@ -662,17 +661,9 @@ namespace MediaBrowser.Api.Playback
};
}).ThenBy(i =>
{
- if (maxBitrate.HasValue)
+ if (maxBitrate.HasValue && i.Bitrate.HasValue)
{
- if (i.Bitrate.HasValue)
- {
- if (i.Bitrate.Value <= maxBitrate.Value)
- {
- return 0;
- }
-
- return 2;
- }
+ return i.Bitrate.Value <= maxBitrate.Value ? 0 : 2;
}
return 1;
diff --git a/MediaBrowser.Api/Playback/UniversalAudioService.cs b/MediaBrowser.Api/Playback/UniversalAudioService.cs
index cbf981dfe..cebd4b49a 100644
--- a/MediaBrowser.Api/Playback/UniversalAudioService.cs
+++ b/MediaBrowser.Api/Playback/UniversalAudioService.cs
@@ -167,7 +167,7 @@ namespace MediaBrowser.Api.Playback
AudioCodec = request.AudioCodec,
Protocol = request.TranscodingProtocol,
BreakOnNonKeyFrames = request.BreakOnNonKeyFrames,
- MaxAudioChannels = request.TranscodingAudioChannels.HasValue ? request.TranscodingAudioChannels.Value.ToString(CultureInfo.InvariantCulture) : null
+ MaxAudioChannels = request.TranscodingAudioChannels?.ToString(CultureInfo.InvariantCulture)
}
};
@@ -300,7 +300,7 @@ namespace MediaBrowser.Api.Playback
// hls segment container can only be mpegts or fmp4 per ffmpeg documentation
// TODO: remove this when we switch back to the segment muxer
- var supportedHLSContainers = new string[] { "mpegts", "fmp4" };
+ var supportedHLSContainers = new[] { "mpegts", "fmp4" };
var newRequest = new GetMasterHlsAudioPlaylist
{
diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs
index 16d3268b9..7f74511ee 100644
--- a/MediaBrowser.Api/PluginService.cs
+++ b/MediaBrowser.Api/PluginService.cs
@@ -243,9 +243,7 @@ namespace MediaBrowser.Api
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
var id = Guid.Parse(GetPathValue(1));
- var plugin = _appHost.Plugins.First(p => p.Id == id) as IHasPluginConfiguration;
-
- if (plugin == null)
+ if (!(_appHost.Plugins.First(p => p.Id == id) is IHasPluginConfiguration plugin))
{
throw new FileNotFoundException();
}
diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
index 2bd387229..e08a8482e 100644
--- a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
+++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
@@ -123,9 +123,7 @@ namespace MediaBrowser.Api.ScheduledTasks
{
var isHidden = false;
- var configurableTask = i.ScheduledTask as IConfigurableScheduledTask;
-
- if (configurableTask != null)
+ if (i.ScheduledTask is IConfigurableScheduledTask configurableTask)
{
isHidden = configurableTask.IsHidden;
}
@@ -142,9 +140,7 @@ namespace MediaBrowser.Api.ScheduledTasks
{
var isEnabled = true;
- var configurableTask = i.ScheduledTask as IConfigurableScheduledTask;
-
- if (configurableTask != null)
+ if (i.ScheduledTask is IConfigurableScheduledTask configurableTask)
{
isEnabled = configurableTask.IsEnabled;
}
diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs
index 0a3dc19dc..e9d339c6e 100644
--- a/MediaBrowser.Api/SearchService.cs
+++ b/MediaBrowser.Api/SearchService.cs
@@ -234,59 +234,48 @@ namespace MediaBrowser.Api
SetThumbImageInfo(result, item);
SetBackdropImageInfo(result, item);
- var program = item as LiveTvProgram;
- if (program != null)
+ switch (item)
{
- result.StartDate = program.StartDate;
- }
-
- var hasSeries = item as IHasSeries;
- if (hasSeries != null)
- {
- result.Series = hasSeries.SeriesName;
- }
-
- var series = item as Series;
- if (series != null)
- {
- if (series.Status.HasValue)
- {
- result.Status = series.Status.Value.ToString();
- }
- }
-
- var album = item as MusicAlbum;
-
- if (album != null)
- {
- result.Artists = album.Artists;
- result.AlbumArtist = album.AlbumArtist;
- }
-
- var song = item as Audio;
-
- if (song != null)
- {
- result.AlbumArtist = song.AlbumArtists.FirstOrDefault();
- result.Artists = song.Artists;
-
- album = song.AlbumEntity;
-
- if (album != null)
- {
- result.Album = album.Name;
- result.AlbumId = album.Id;
- }
- else
- {
- result.Album = song.Album;
- }
+ case IHasSeries hasSeries:
+ result.Series = hasSeries.SeriesName;
+ break;
+ case LiveTvProgram program:
+ result.StartDate = program.StartDate;
+ break;
+ case Series series:
+ if (series.Status.HasValue)
+ {
+ result.Status = series.Status.Value.ToString();
+ }
+
+ break;
+ case MusicAlbum album:
+ result.Artists = album.Artists;
+ result.AlbumArtist = album.AlbumArtist;
+ break;
+ case Audio song:
+ result.AlbumArtist = song.AlbumArtists.FirstOrDefault();
+ result.Artists = song.Artists;
+
+ MusicAlbum musicAlbum = song.AlbumEntity;
+
+ if (musicAlbum != null)
+ {
+ result.Album = musicAlbum.Name;
+ result.AlbumId = musicAlbum.Id;
+ }
+ else
+ {
+ result.Album = song.Album;
+ }
+
+ break;
}
if (!item.ChannelId.Equals(Guid.Empty))
{
var channel = _libraryManager.GetItemById(item.ChannelId);
- result.ChannelName = channel == null ? null : channel.Name;
+ result.ChannelName = channel?.Name;
}
return result;
@@ -296,12 +285,9 @@ namespace MediaBrowser.Api
{
var itemWithImage = item.HasImage(ImageType.Thumb) ? item : null;
- if (itemWithImage == null)
+ if (itemWithImage == null && item is Episode)
{
- if (item is Episode)
- {
- itemWithImage = GetParentWithImage<Series>(item, ImageType.Thumb);
- }
+ itemWithImage = GetParentWithImage<Series>(item, ImageType.Thumb);
}
if (itemWithImage == null)
@@ -323,12 +309,8 @@ namespace MediaBrowser.Api
private void SetBackdropImageInfo(SearchHint hint, BaseItem item)
{
- var itemWithImage = item.HasImage(ImageType.Backdrop) ? item : null;
-
- if (itemWithImage == null)
- {
- itemWithImage = GetParentWithImage<BaseItem>(item, ImageType.Backdrop);
- }
+ var itemWithImage = (item.HasImage(ImageType.Backdrop) ? item : null)
+ ?? GetParentWithImage<BaseItem>(item, ImageType.Backdrop);
if (itemWithImage != null)
{
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index c4a7ae78e..f2968c6b5 100644
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -230,17 +230,14 @@ namespace MediaBrowser.Api.Subtitles
if (string.Equals(request.Format, "vtt", StringComparison.OrdinalIgnoreCase) && request.AddVttTimeMap)
{
- using (var stream = await GetSubtitles(request).ConfigureAwait(false))
- {
- using (var reader = new StreamReader(stream))
- {
- var text = reader.ReadToEnd();
+ using var stream = await GetSubtitles(request).ConfigureAwait(false);
+ using var reader = new StreamReader(stream);
- text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000");
+ var text = reader.ReadToEnd();
- return ResultFactory.GetResult(Request, text, MimeTypes.GetMimeType("file." + request.Format));
- }
- }
+ text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000");
+
+ return ResultFactory.GetResult(Request, text, MimeTypes.GetMimeType("file." + request.Format));
}
return ResultFactory.GetResult(Request, await GetSubtitles(request).ConfigureAwait(false), MimeTypes.GetMimeType("file." + request.Format));
diff --git a/MediaBrowser.Api/System/SystemService.cs b/MediaBrowser.Api/System/SystemService.cs
index 3a3eeb8b8..c57cc93d5 100644
--- a/MediaBrowser.Api/System/SystemService.cs
+++ b/MediaBrowser.Api/System/SystemService.cs
@@ -168,12 +168,9 @@ namespace MediaBrowser.Api.System
.First(i => string.Equals(i.Name, request.Name, StringComparison.OrdinalIgnoreCase));
// For older files, assume fully static
- if (file.LastWriteTimeUtc < DateTime.UtcNow.AddHours(-1))
- {
- return ResultFactory.GetStaticFileResult(Request, file.FullName, FileShare.Read);
- }
+ var fileShare = file.LastWriteTimeUtc < DateTime.UtcNow.AddHours(-1) ? FileShare.Read : FileShare.ReadWrite;
- return ResultFactory.GetStaticFileResult(Request, file.FullName, FileShare.ReadWrite);
+ return ResultFactory.GetStaticFileResult(Request, file.FullName, fileShare);
}
/// <summary>
diff --git a/MediaBrowser.Api/TranscodingJob.cs b/MediaBrowser.Api/TranscodingJob.cs
index 6d944d19e..8c24e3ce1 100644
--- a/MediaBrowser.Api/TranscodingJob.cs
+++ b/MediaBrowser.Api/TranscodingJob.cs
@@ -92,10 +92,7 @@ namespace MediaBrowser.Api
{
lock (_timerLock)
{
- if (KillTimer != null)
- {
- KillTimer.Change(Timeout.Infinite, Timeout.Infinite);
- }
+ KillTimer?.Change(Timeout.Infinite, Timeout.Infinite);
}
}
diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs
index 334d1db51..cd8e8dfbe 100644
--- a/MediaBrowser.Api/TvShowsService.cs
+++ b/MediaBrowser.Api/TvShowsService.cs
@@ -424,9 +424,7 @@ namespace MediaBrowser.Api
if (!string.IsNullOrWhiteSpace(request.SeasonId))
{
- var season = _libraryManager.GetItemById(new Guid(request.SeasonId)) as Season;
-
- if (season == null)
+ if (!(_libraryManager.GetItemById(new Guid(request.SeasonId)) is Season season))
{
throw new ResourceNotFoundException("No season exists with Id " + request.SeasonId);
}
@@ -444,14 +442,7 @@ namespace MediaBrowser.Api
var season = series.GetSeasons(user, dtoOptions).FirstOrDefault(i => i.IndexNumber == request.Season.Value);
- if (season == null)
- {
- episodes = new List<BaseItem>();
- }
- else
- {
- episodes = ((Season)season).GetEpisodes(user, dtoOptions);
- }
+ episodes = season == null ? new List<BaseItem>() : ((Season)season).GetEpisodes(user, dtoOptions);
}
else
{
diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
index adb0a440f..3d08d5437 100644
--- a/MediaBrowser.Api/UserLibrary/ArtistsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
@@ -126,12 +126,7 @@ namespace MediaBrowser.Api.UserLibrary
protected override QueryResult<(BaseItem, ItemCounts)> GetItems(GetItemsByName request, InternalItemsQuery query)
{
- if (request is GetAlbumArtists)
- {
- return LibraryManager.GetAlbumArtists(query);
- }
-
- return LibraryManager.GetArtists(query);
+ return request is GetAlbumArtists ? LibraryManager.GetAlbumArtists(query) : LibraryManager.GetArtists(query);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index 9fa222d32..c4a52d5f5 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -82,8 +82,7 @@ namespace MediaBrowser.Api.UserLibrary
{
var parent = GetParentItem(request);
- var collectionFolder = parent as IHasCollectionType;
- if (collectionFolder != null)
+ if (parent is IHasCollectionType collectionFolder)
{
return collectionFolder.CollectionType;
}
@@ -274,7 +273,7 @@ namespace MediaBrowser.Api.UserLibrary
DtoOptions = dtoOptions
};
- Func<BaseItem, bool> filter = i => FilterItem(request, i, excludeItemTypes, includeItemTypes, mediaTypes);
+ bool Filter(BaseItem i) => FilterItem(request, i, excludeItemTypes, includeItemTypes, mediaTypes);
if (parentItem.IsFolder)
{
@@ -284,18 +283,18 @@ namespace MediaBrowser.Api.UserLibrary
{
items = request.Recursive ?
folder.GetRecursiveChildren(user, query).ToList() :
- folder.GetChildren(user, true).Where(filter).ToList();
+ folder.GetChildren(user, true).Where(Filter).ToList();
}
else
{
items = request.Recursive ?
- folder.GetRecursiveChildren(filter) :
- folder.Children.Where(filter).ToList();
+ folder.GetRecursiveChildren(Filter) :
+ folder.Children.Where(Filter).ToList();
}
}
else
{
- items = new[] { parentItem }.Where(filter).ToList();
+ items = new[] { parentItem }.Where(Filter).ToList();
}
var extractedItems = GetAllItems(request, items);
@@ -346,30 +345,21 @@ namespace MediaBrowser.Api.UserLibrary
private bool FilterItem(GetItemsByName request, BaseItem f, string[] excludeItemTypes, string[] includeItemTypes, string[] mediaTypes)
{
// Exclude item types
- if (excludeItemTypes.Length > 0)
+ if (excludeItemTypes.Length > 0 && excludeItemTypes.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase))
{
- if (excludeItemTypes.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase))
- {
- return false;
- }
+ return false;
}
// Include item types
- if (includeItemTypes.Length > 0)
+ if (includeItemTypes.Length > 0 && !includeItemTypes.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase))
{
- if (!includeItemTypes.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase))
- {
- return false;
- }
+ return false;
}
// Include MediaTypes
- if (mediaTypes.Length > 0)
+ if (mediaTypes.Length > 0 && !mediaTypes.Contains(f.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
{
- if (!mediaTypes.Contains(f.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
- {
- return false;
- }
+ return false;
}
return true;
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
index a26f59573..7561b5c89 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
@@ -396,12 +396,10 @@ namespace MediaBrowser.Api.UserLibrary
public VideoType[] GetVideoTypes()
{
- if (string.IsNullOrEmpty(VideoTypes))
- {
- return Array.Empty<VideoType>();
- }
-
- return VideoTypes.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (VideoType)Enum.Parse(typeof(VideoType), v, true)).ToArray();
+ return string.IsNullOrEmpty(VideoTypes)
+ ? Array.Empty<VideoType>()
+ : VideoTypes.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
+ .Select(v => Enum.Parse<VideoType>(v, true)).ToArray();
}
/// <summary>
@@ -412,12 +410,10 @@ namespace MediaBrowser.Api.UserLibrary
{
var val = Filters;
- if (string.IsNullOrEmpty(val))
- {
- return new ItemFilter[] { };
- }
-
- return val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (ItemFilter)Enum.Parse(typeof(ItemFilter), v, true)).ToArray();
+ return string.IsNullOrEmpty(val)
+ ? Array.Empty<ItemFilter>()
+ : val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
+ .Select(v => Enum.Parse<ItemFilter>(v, true)).ToArray();
}
/// <summary>
@@ -428,12 +424,9 @@ namespace MediaBrowser.Api.UserLibrary
{
var val = ImageTypes;
- if (string.IsNullOrEmpty(val))
- {
- return new ImageType[] { };
- }
-
- return val.Split(',').Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToArray();
+ return string.IsNullOrEmpty(val)
+ ? Array.Empty<ImageType>()
+ : val.Split(',').Select(v => Enum.Parse<ImageType>(v, true)).ToArray();
}
/// <summary>
@@ -469,7 +462,9 @@ namespace MediaBrowser.Api.UserLibrary
var sortOrderIndex = sortOrders.Length > i ? i : 0;
var sortOrderValue = sortOrders.Length > sortOrderIndex ? sortOrders[sortOrderIndex] : null;
- var sortOrder = string.Equals(sortOrderValue, "Descending", StringComparison.OrdinalIgnoreCase) ? MediaBrowser.Model.Entities.SortOrder.Descending : MediaBrowser.Model.Entities.SortOrder.Ascending;
+ var sortOrder = string.Equals(sortOrderValue, "Descending", StringComparison.OrdinalIgnoreCase)
+ ? MediaBrowser.Model.Entities.SortOrder.Descending
+ : MediaBrowser.Model.Entities.SortOrder.Ascending;
result[i] = new ValueTuple<string, SortOrder>(vals[i], sortOrder);
}
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 22e4eea0b..ac59c3030 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -199,14 +199,12 @@ namespace MediaBrowser.Api.UserLibrary
item = _libraryManager.GetUserRootFolder();
}
- Folder folder = item as Folder;
- if (folder == null)
+ if (!(item is Folder folder))
{
folder = _libraryManager.GetUserRootFolder();
}
- var hasCollectionType = folder as IHasCollectionType;
- if (hasCollectionType != null
+ if (folder is IHasCollectionType hasCollectionType
&& string.Equals(hasCollectionType.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
{
request.Recursive = true;
diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs
index 46b6d5a94..b11fd48d3 100644
--- a/MediaBrowser.Api/VideosService.cs
+++ b/MediaBrowser.Api/VideosService.cs
@@ -139,17 +139,11 @@ namespace MediaBrowser.Api
.ToList();
var primaryVersion = videosWithVersions.FirstOrDefault();
-
if (primaryVersion == null)
{
primaryVersion = items.OrderBy(i =>
{
- if (i.Video3DFormat.HasValue)
- {
- return 1;
- }
-
- if (i.VideoType != Model.Entities.VideoType.VideoFile)
+ if (i.Video3DFormat.HasValue || i.VideoType != Model.Entities.VideoType.VideoFile)
{
return 1;
}
@@ -158,10 +152,7 @@ namespace MediaBrowser.Api
})
.ThenByDescending(i =>
{
- var stream = i.GetDefaultVideoStream();
-
- return stream == null || stream.Width == null ? 0 : stream.Width.Value;
-
+ return i.GetDefaultVideoStream()?.Width ?? 0;
}).First();
}
diff --git a/MediaBrowser.Common/Extensions/ProcessExtensions.cs b/MediaBrowser.Common/Extensions/ProcessExtensions.cs
new file mode 100644
index 000000000..c74787122
--- /dev/null
+++ b/MediaBrowser.Common/Extensions/ProcessExtensions.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Common.Extensions
+{
+ /// <summary>
+ /// Extension methods for <see cref="Process"/>.
+ /// </summary>
+ public static class ProcessExtensions
+ {
+ /// <summary>
+ /// Asynchronously wait for the process to exit.
+ /// </summary>
+ /// <param name="process">The process to wait for.</param>
+ /// <param name="timeout">The duration to wait before cancelling waiting for the task.</param>
+ /// <returns>True if the task exited normally, false if the timeout elapsed before the process exited.</returns>
+ /// <exception cref="InvalidOperationException">If <see cref="Process.EnableRaisingEvents"/> is not set to true for the process.</exception>
+ public static async Task<bool> WaitForExitAsync(this Process process, TimeSpan timeout)
+ {
+ using (var cancelTokenSource = new CancellationTokenSource(timeout))
+ {
+ return await WaitForExitAsync(process, cancelTokenSource.Token).ConfigureAwait(false);
+ }
+ }
+
+ /// <summary>
+ /// Asynchronously wait for the process to exit.
+ /// </summary>
+ /// <param name="process">The process to wait for.</param>
+ /// <param name="cancelToken">A <see cref="CancellationToken"/> to observe while waiting for the process to exit.</param>
+ /// <returns>True if the task exited normally, false if cancelled before the process exited.</returns>
+ public static async Task<bool> WaitForExitAsync(this Process process, CancellationToken cancelToken)
+ {
+ if (!process.EnableRaisingEvents)
+ {
+ throw new InvalidOperationException("EnableRisingEvents must be enabled to async wait for a task to exit.");
+ }
+
+ // Add an event handler for the process exit event
+ var tcs = new TaskCompletionSource<bool>();
+ process.Exited += (sender, args) => tcs.TrySetResult(true);
+
+ // Return immediately if the process has already exited
+ if (process.HasExitedSafe())
+ {
+ return true;
+ }
+
+ // Register with the cancellation token then await
+ using (var cancelRegistration = cancelToken.Register(() => tcs.TrySetResult(process.HasExitedSafe())))
+ {
+ return await tcs.Task.ConfigureAwait(false);
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the associated process has been terminated using
+ /// <see cref="Process.HasExited"/>. This is safe to call even if there is no operating system process
+ /// associated with the <see cref="Process"/>.
+ /// </summary>
+ /// <param name="process">The process to check the exit status for.</param>
+ /// <returns>
+ /// True if the operating system process referenced by the <see cref="Process"/> component has
+ /// terminated, or if there is no associated operating system process; otherwise, false.
+ /// </returns>
+ private static bool HasExitedSafe(this Process process)
+ {
+ try
+ {
+ return process.HasExited;
+ }
+ catch (InvalidOperationException)
+ {
+ return true;
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 6e5fe97e5..3552a45a2 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -78,8 +78,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (!string.IsNullOrEmpty(hwType)
&& encodingOptions.EnableHardwareEncoding
- && codecMap.ContainsKey(hwType)
- && CheckVaapi(state, hwType, encodingOptions))
+ && codecMap.ContainsKey(hwType))
{
var preferredEncoder = codecMap[hwType];
@@ -93,23 +92,6 @@ namespace MediaBrowser.Controller.MediaEncoding
return defaultEncoder;
}
- private bool CheckVaapi(EncodingJobInfo state, string hwType, EncodingOptions encodingOptions)
- {
- if (!string.Equals(hwType, "vaapi", StringComparison.OrdinalIgnoreCase))
- {
- // No vaapi requested, return OK.
- return true;
- }
-
- if (string.IsNullOrEmpty(encodingOptions.VaapiDevice))
- {
- // No device specified, return OK.
- return true;
- }
-
- return IsVaapiSupported(state);
- }
-
private bool IsVaapiSupported(EncodingJobInfo state)
{
var videoStream = state.VideoStream;
@@ -424,7 +406,13 @@ namespace MediaBrowser.Controller.MediaEncoding
if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase))
{
- return "aac -strict experimental";
+ // Use libfdk_aac for better audio quality if using custom build of FFmpeg which has fdk_aac support
+ if (_mediaEncoder.SupportsEncoder("libfdk_aac"))
+ {
+ return "libfdk_aac";
+ }
+
+ return "aac";
}
if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase))
@@ -1605,7 +1593,7 @@ namespace MediaBrowser.Controller.MediaEncoding
// For VAAPI and CUVID decoder
// these encoders cannot automatically adjust the size of graphical subtitles to fit the output video,
// thus needs to be manually adjusted.
- if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)
+ if ((IsVaapiSupported(state) && string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
|| (videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1)
{
var videoStream = state.VideoStream;
@@ -1648,7 +1636,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// If we're hardware VAAPI decoding and software encoding, download frames from the decoder first
- else if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)
+ else if (IsVaapiSupported(state) && string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)
&& string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
{
/*
@@ -2014,19 +2002,29 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// If we're hardware VAAPI decoding and software encoding, download frames from the decoder first
- else if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)
+ else if (IsVaapiSupported(state) && string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)
&& string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
{
var codec = videoStream.Codec.ToLowerInvariant();
- var pixelFormat = videoStream.PixelFormat.ToLowerInvariant();
-
- // Assert hardware VAAPI decodable (Except h264 10-bit and higher color depth)
- // TODO: a propery way to detect hardware capabilities and falling back when transcoding is failed
- if ((pixelFormat ?? string.Empty).IndexOf("p10", StringComparison.OrdinalIgnoreCase) == -1
- || ((pixelFormat ?? string.Empty).IndexOf("p10", StringComparison.OrdinalIgnoreCase) != -1
- && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
- || string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
- || string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCase))))
+ var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase)
+ || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase));
+
+ // Assert 10-bit hardware VAAPI decodable
+ if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCase)))
+ {
+ /*
+ Download data from GPU to CPU as p010le format.
+ Colorspace conversion is unnecessary here as libx264 will handle it.
+ If this step is missing, it will fail on AMD but not on intel.
+ */
+ filters.Add("hwdownload");
+ filters.Add("format=p010le");
+ }
+
+ // Assert 8-bit hardware VAAPI decodable
+ else if (!isColorDepth10)
{
filters.Add("hwdownload");
filters.Add("format=nv12");
diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs
index 43d33c716..3f177a9fa 100644
--- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs
+++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs
@@ -155,47 +155,44 @@ namespace MediaBrowser.MediaEncoding.Attachments
inputPath,
attachmentStreamIndex,
outputPath);
- var startInfo = new ProcessStartInfo
- {
- Arguments = processArgs,
- FileName = _mediaEncoder.EncoderPath,
- UseShellExecute = false,
- CreateNoWindow = true,
- WindowStyle = ProcessWindowStyle.Hidden,
- ErrorDialog = false
- };
- var process = new Process
- {
- StartInfo = startInfo
- };
- _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments);
+ int exitCode;
- process.Start();
+ using (var process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ Arguments = processArgs,
+ FileName = _mediaEncoder.EncoderPath,
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false
+ },
+ EnableRaisingEvents = true
+ })
+ {
+ _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments);
- var processTcs = new TaskCompletionSource<bool>();
- process.EnableRaisingEvents = true;
- process.Exited += (sender, args) => processTcs.TrySetResult(true);
- var unregister = cancellationToken.Register(() => processTcs.TrySetResult(process.HasExited));
- var ranToCompletion = await processTcs.Task.ConfigureAwait(false);
- unregister.Dispose();
+ process.Start();
- if (!ranToCompletion)
- {
- try
- {
- _logger.LogWarning("Killing ffmpeg attachment extraction process");
- process.Kill();
- }
- catch (Exception ex)
+ var ranToCompletion = await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false);
+
+ if (!ranToCompletion)
{
- _logger.LogError(ex, "Error killing attachment extraction process");
+ try
+ {
+ _logger.LogWarning("Killing ffmpeg attachment extraction process");
+ process.Kill();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error killing attachment extraction process");
+ }
}
- }
- var exitCode = ranToCompletion ? process.ExitCode : -1;
-
- process.Dispose();
+ exitCode = ranToCompletion ? process.ExitCode : -1;
+ }
var failed = false;
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
index f5decdc0d..6e036d24c 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
@@ -42,6 +42,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
"libvpx",
"libvpx-vp9",
"aac",
+ "libfdk_aac",
"libmp3lame",
"libopus",
"libvorbis",
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index c5bba8780..f4260afbc 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -13,7 +13,6 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.MediaEncoding.Probing;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
@@ -22,6 +21,7 @@ using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
+using System.Diagnostics;
namespace MediaBrowser.MediaEncoding.Encoder
{
@@ -38,7 +38,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
private readonly ILogger _logger;
private readonly IServerConfigurationManager _configurationManager;
private readonly IFileSystem _fileSystem;
- private readonly IProcessFactory _processFactory;
private readonly ILocalizationManager _localization;
private readonly Lazy<EncodingHelper> _encodingHelperFactory;
private readonly string _startupOptionFFmpegPath;
@@ -55,7 +54,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
ILogger<MediaEncoder> logger,
IServerConfigurationManager configurationManager,
IFileSystem fileSystem,
- IProcessFactory processFactory,
ILocalizationManager localization,
Lazy<EncodingHelper> encodingHelperFactory,
string startupOptionsFFmpegPath)
@@ -63,7 +61,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger = logger;
_configurationManager = configurationManager;
_fileSystem = fileSystem;
- _processFactory = processFactory;
_localization = localization;
_encodingHelperFactory = encodingHelperFactory;
_startupOptionFFmpegPath = startupOptionsFFmpegPath;
@@ -354,30 +351,33 @@ namespace MediaBrowser.MediaEncoding.Encoder
: "{0} -i {1} -threads 0 -v warning -print_format json -show_streams -show_format";
args = string.Format(args, probeSizeArgument, inputPath).Trim();
- var process = _processFactory.Create(new ProcessOptions
+ var process = new Process
{
- CreateNoWindow = true,
- UseShellExecute = false,
+ StartInfo = new ProcessStartInfo
+ {
+ CreateNoWindow = true,
+ UseShellExecute = false,
- // Must consume both or ffmpeg may hang due to deadlocks. See comments below.
- RedirectStandardOutput = true,
+ // Must consume both or ffmpeg may hang due to deadlocks. See comments below.
+ RedirectStandardOutput = true,
- FileName = _ffprobePath,
- Arguments = args,
+ FileName = _ffprobePath,
+ Arguments = args,
- IsHidden = true,
- ErrorDialog = false,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false,
+ },
EnableRaisingEvents = true
- });
+ };
if (forceEnableLogging)
{
- _logger.LogInformation("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
+ _logger.LogInformation("{ProcessFileName} {ProcessArgs}", process.StartInfo.FileName, process.StartInfo.Arguments);
}
else
{
- _logger.LogDebug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
+ _logger.LogDebug("{ProcessFileName} {ProcessArgs}", process.StartInfo.FileName, process.StartInfo.Arguments);
}
using (var processWrapper = new ProcessWrapper(process, this))
@@ -563,18 +563,21 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- var process = _processFactory.Create(new ProcessOptions
+ var process = new Process
{
- CreateNoWindow = true,
- UseShellExecute = false,
- FileName = _ffmpegPath,
- Arguments = args,
- IsHidden = true,
- ErrorDialog = false,
+ StartInfo = new ProcessStartInfo
+ {
+ CreateNoWindow = true,
+ UseShellExecute = false,
+ FileName = _ffmpegPath,
+ Arguments = args,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false,
+ },
EnableRaisingEvents = true
- });
+ };
- _logger.LogDebug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
+ _logger.LogDebug("{ProcessFileName} {ProcessArguments}", process.StartInfo.FileName, process.StartInfo.Arguments);
using (var processWrapper = new ProcessWrapper(process, this))
{
@@ -591,7 +594,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
timeoutMs = DefaultImageExtractionTimeout;
}
- ranToCompletion = await process.WaitForExitAsync(timeoutMs).ConfigureAwait(false);
+ ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMilliseconds(timeoutMs)).ConfigureAwait(false);
if (!ranToCompletion)
{
@@ -692,23 +695,27 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- var process = _processFactory.Create(new ProcessOptions
+ var processStartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
UseShellExecute = false,
FileName = _ffmpegPath,
Arguments = args,
- IsHidden = true,
- ErrorDialog = false,
- EnableRaisingEvents = true
- });
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false
+ };
- _logger.LogInformation(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
+ _logger.LogInformation(processStartInfo.FileName + " " + processStartInfo.Arguments);
await _thumbnailResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
bool ranToCompletion = false;
+ var process = new Process
+ {
+ StartInfo = processStartInfo,
+ EnableRaisingEvents = true
+ };
using (var processWrapper = new ProcessWrapper(process, this))
{
try
@@ -724,7 +731,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
while (isResponsive)
{
- if (await process.WaitForExitAsync(30000).ConfigureAwait(false))
+ if (await process.WaitForExitAsync(TimeSpan.FromSeconds(30)).ConfigureAwait(false))
{
ranToCompletion = true;
break;
@@ -941,14 +948,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
private bool _disposed = false;
- public ProcessWrapper(IProcess process, MediaEncoder mediaEncoder)
+ public ProcessWrapper(Process process, MediaEncoder mediaEncoder)
{
Process = process;
_mediaEncoder = mediaEncoder;
Process.Exited += OnProcessExited;
}
- public IProcess Process { get; }
+ public Process Process { get; }
public bool HasExited { get; private set; }
@@ -956,7 +963,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
void OnProcessExited(object sender, EventArgs e)
{
- var process = (IProcess)sender;
+ var process = (Process)sender;
HasExited = true;
@@ -971,7 +978,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
DisposeProcess(process);
}
- private void DisposeProcess(IProcess process)
+ private void DisposeProcess(Process process)
{
lock (_mediaEncoder._runningProcessesLock)
{
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index b76b52941..ba171295e 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Concurrent;
+using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -12,7 +13,6 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
@@ -31,7 +31,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
private readonly IMediaEncoder _mediaEncoder;
private readonly IHttpClient _httpClient;
private readonly IMediaSourceManager _mediaSourceManager;
- private readonly IProcessFactory _processFactory;
public SubtitleEncoder(
ILibraryManager libraryManager,
@@ -40,8 +39,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
IFileSystem fileSystem,
IMediaEncoder mediaEncoder,
IHttpClient httpClient,
- IMediaSourceManager mediaSourceManager,
- IProcessFactory processFactory)
+ IMediaSourceManager mediaSourceManager)
{
_libraryManager = libraryManager;
_logger = logger;
@@ -50,7 +48,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
_mediaEncoder = mediaEncoder;
_httpClient = httpClient;
_mediaSourceManager = mediaSourceManager;
- _processFactory = processFactory;
}
private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles");
@@ -429,49 +426,53 @@ namespace MediaBrowser.MediaEncoding.Subtitles
encodingParam = " -sub_charenc " + encodingParam;
}
- var process = _processFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
- FileName = _mediaEncoder.EncoderPath,
- Arguments = string.Format("{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath),
- EnableRaisingEvents = true,
- IsHidden = true,
- ErrorDialog = false
- });
-
- _logger.LogInformation("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
-
- try
- {
- process.Start();
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error starting ffmpeg");
+ int exitCode;
- throw;
- }
-
- var ranToCompletion = await process.WaitForExitAsync(300000).ConfigureAwait(false);
+ using (var process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ CreateNoWindow = true,
+ UseShellExecute = false,
+ FileName = _mediaEncoder.EncoderPath,
+ Arguments = string.Format("{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath),
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false
+ },
+ EnableRaisingEvents = true
+ })
+ {
+ _logger.LogInformation("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
- if (!ranToCompletion)
- {
try
{
- _logger.LogInformation("Killing ffmpeg subtitle conversion process");
-
- process.Kill();
+ process.Start();
}
catch (Exception ex)
{
- _logger.LogError(ex, "Error killing subtitle conversion process");
+ _logger.LogError(ex, "Error starting ffmpeg");
+
+ throw;
}
- }
- var exitCode = ranToCompletion ? process.ExitCode : -1;
+ var ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMinutes(5)).ConfigureAwait(false);
+
+ if (!ranToCompletion)
+ {
+ try
+ {
+ _logger.LogInformation("Killing ffmpeg subtitle conversion process");
- process.Dispose();
+ process.Kill();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error killing subtitle conversion process");
+ }
+ }
+
+ exitCode = ranToCompletion ? process.ExitCode : -1;
+ }
var failed = false;
@@ -578,49 +579,53 @@ namespace MediaBrowser.MediaEncoding.Subtitles
outputCodec,
outputPath);
- var process = _processFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
- EnableRaisingEvents = true,
- FileName = _mediaEncoder.EncoderPath,
- Arguments = processArgs,
- IsHidden = true,
- ErrorDialog = false
- });
-
- _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments);
-
- try
- {
- process.Start();
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error starting ffmpeg");
+ int exitCode;
- throw;
- }
-
- var ranToCompletion = await process.WaitForExitAsync(300000).ConfigureAwait(false);
+ using (var process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ CreateNoWindow = true,
+ UseShellExecute = false,
+ FileName = _mediaEncoder.EncoderPath,
+ Arguments = processArgs,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false
+ },
+ EnableRaisingEvents = true
+ })
+ {
+ _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments);
- if (!ranToCompletion)
- {
try
{
- _logger.LogWarning("Killing ffmpeg subtitle extraction process");
-
- process.Kill();
+ process.Start();
}
catch (Exception ex)
{
- _logger.LogError(ex, "Error killing subtitle extraction process");
+ _logger.LogError(ex, "Error starting ffmpeg");
+
+ throw;
}
- }
- var exitCode = ranToCompletion ? process.ExitCode : -1;
+ var ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMinutes(5)).ConfigureAwait(false);
+
+ if (!ranToCompletion)
+ {
+ try
+ {
+ _logger.LogWarning("Killing ffmpeg subtitle extraction process");
- process.Dispose();
+ process.Kill();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error killing subtitle extraction process");
+ }
+ }
+
+ exitCode = ranToCompletion ? process.ExitCode : -1;
+ }
var failed = false;
diff --git a/MediaBrowser.Model/Diagnostics/IProcess.cs b/MediaBrowser.Model/Diagnostics/IProcess.cs
deleted file mode 100644
index 514d1e737..000000000
--- a/MediaBrowser.Model/Diagnostics/IProcess.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using System.IO;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Model.Diagnostics
-{
- public interface IProcess : IDisposable
- {
- event EventHandler Exited;
-
- void Kill();
- bool WaitForExit(int timeMs);
- Task<bool> WaitForExitAsync(int timeMs);
- int ExitCode { get; }
- void Start();
- StreamWriter StandardInput { get; }
- StreamReader StandardError { get; }
- StreamReader StandardOutput { get; }
- ProcessOptions StartInfo { get; }
- }
-}
diff --git a/MediaBrowser.Model/Diagnostics/IProcessFactory.cs b/MediaBrowser.Model/Diagnostics/IProcessFactory.cs
deleted file mode 100644
index 57082acc5..000000000
--- a/MediaBrowser.Model/Diagnostics/IProcessFactory.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-#pragma warning disable CS1591
-
-namespace MediaBrowser.Model.Diagnostics
-{
- public interface IProcessFactory
- {
- IProcess Create(ProcessOptions options);
- }
-
- public class ProcessOptions
- {
- public string FileName { get; set; }
- public string Arguments { get; set; }
- public string WorkingDirectory { get; set; }
- public bool CreateNoWindow { get; set; }
- public bool UseShellExecute { get; set; }
- public bool EnableRaisingEvents { get; set; }
- public bool ErrorDialog { get; set; }
- public bool RedirectStandardError { get; set; }
- public bool RedirectStandardInput { get; set; }
- public bool RedirectStandardOutput { get; set; }
- public bool IsHidden { get; set; }
- }
-}
diff --git a/nuget.config b/nuget.config
new file mode 100644
index 000000000..326331f32
--- /dev/null
+++ b/nuget.config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <packageSources>
+ <add key="NuGet official package source" value="https://api.nuget.org/v3/index.json" />
+ </packageSources>
+</configuration>
diff --git a/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs b/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs
index 1646237a0..a64d17349 100644
--- a/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs
+++ b/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs
@@ -7,6 +7,8 @@ namespace Jellyfin.Naming.Tests.Video
{
public class ExtraTests : BaseVideoTest
{
+ private readonly NamingOptions _videoOptions = new NamingOptions();
+
// Requirements
// movie-deleted = ExtraType deletedscene
@@ -15,42 +17,64 @@ namespace Jellyfin.Naming.Tests.Video
[Fact]
public void TestKodiExtras()
{
- var videoOptions = new NamingOptions();
-
- Test("trailer.mp4", ExtraType.Trailer, videoOptions);
- Test("300-trailer.mp4", ExtraType.Trailer, videoOptions);
+ Test("trailer.mp4", ExtraType.Trailer, _videoOptions);
+ Test("300-trailer.mp4", ExtraType.Trailer, _videoOptions);
- Test("theme.mp3", ExtraType.ThemeSong, videoOptions);
+ Test("theme.mp3", ExtraType.ThemeSong, _videoOptions);
}
[Fact]
public void TestExpandedExtras()
{
- var videoOptions = new NamingOptions();
+ Test("trailer.mp4", ExtraType.Trailer, _videoOptions);
+ Test("trailer.mp3", null, _videoOptions);
+ Test("300-trailer.mp4", ExtraType.Trailer, _videoOptions);
- Test("trailer.mp4", ExtraType.Trailer, videoOptions);
- Test("trailer.mp3", null, videoOptions);
- Test("300-trailer.mp4", ExtraType.Trailer, videoOptions);
+ Test("theme.mp3", ExtraType.ThemeSong, _videoOptions);
+ Test("theme.mkv", null, _videoOptions);
- Test("theme.mp3", ExtraType.ThemeSong, videoOptions);
- Test("theme.mkv", null, videoOptions);
+ Test("300-scene.mp4", ExtraType.Scene, _videoOptions);
+ Test("300-scene2.mp4", ExtraType.Scene, _videoOptions);
+ Test("300-clip.mp4", ExtraType.Clip, _videoOptions);
+
+ Test("300-deleted.mp4", ExtraType.DeletedScene, _videoOptions);
+ Test("300-deletedscene.mp4", ExtraType.DeletedScene, _videoOptions);
+ Test("300-interview.mp4", ExtraType.Interview, _videoOptions);
+ Test("300-behindthescenes.mp4", ExtraType.BehindTheScenes, _videoOptions);
+ }
- Test("300-scene.mp4", ExtraType.Scene, videoOptions);
- Test("300-scene2.mp4", ExtraType.Scene, videoOptions);
- Test("300-clip.mp4", ExtraType.Clip, videoOptions);
+ [Theory]
+ [InlineData(ExtraType.BehindTheScenes, "behind the scenes" )]
+ [InlineData(ExtraType.DeletedScene, "deleted scenes" )]
+ [InlineData(ExtraType.Interview, "interviews" )]
+ [InlineData(ExtraType.Scene, "scenes" )]
+ [InlineData(ExtraType.Sample, "samples" )]
+ [InlineData(ExtraType.Clip, "shorts" )]
+ [InlineData(ExtraType.Clip, "featurettes" )]
+ [InlineData(ExtraType.Unknown, "extras" )]
+ public void TestDirectories(ExtraType type, string dirName)
+ {
+ Test(dirName + "/300.mp4", type, _videoOptions);
+ Test("300/" + dirName + "/something.mkv", type, _videoOptions);
+ Test("/data/something/Movies/300/" + dirName + "/whoknows.mp4", type, _videoOptions);
+ }
- Test("300-deleted.mp4", ExtraType.DeletedScene, videoOptions);
- Test("300-deletedscene.mp4", ExtraType.DeletedScene, videoOptions);
- Test("300-interview.mp4", ExtraType.Interview, videoOptions);
- Test("300-behindthescenes.mp4", ExtraType.BehindTheScenes, videoOptions);
+ [Theory]
+ [InlineData("gibberish")]
+ [InlineData("not a scene")]
+ [InlineData("The Big Short")]
+ public void TestNonExtraDirectories(string dirName)
+ {
+ Test(dirName + "/300.mp4", null, _videoOptions);
+ Test("300/" + dirName + "/something.mkv", null, _videoOptions);
+ Test("/data/something/Movies/300/" + dirName + "/whoknows.mp4", null, _videoOptions);
+ Test("/data/something/Movies/" + dirName + "/" + dirName + ".mp4", null, _videoOptions);
}
[Fact]
public void TestSample()
{
- var videoOptions = new NamingOptions();
-
- Test("300-sample.mp4", ExtraType.Sample, videoOptions);
+ Test("300-sample.mp4", ExtraType.Sample, _videoOptions);
}
private void Test(string input, ExtraType? expectedType, NamingOptions videoOptions)