From ed1f2a8a0c0e2502438aed80369e94150f3bd32d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 31 Oct 2016 16:00:26 -0400 Subject: update SubtitleService --- MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs | 4 +--- .../MediaBrowser.Server.Implementations.csproj | 5 ----- 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'MediaBrowser.Server.Implementations') diff --git a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs index 60d0d7c41..7b88f12df 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs @@ -88,8 +88,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer Headers["Content-Length"] = source.Length.ToString(UsCulture); } - private const int BufferSize = 81920; - public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken) { try @@ -102,7 +100,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer { using (var src = SourceStream) { - await src.CopyToAsync(responseStream, BufferSize).ConfigureAwait(false); + await src.CopyToAsync(responseStream).ConfigureAwait(false); } } } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index f3224127a..e6f203120 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -79,7 +79,6 @@ True - @@ -87,16 +86,12 @@ - ..\ThirdParty\ServiceStack\ServiceStack.dll - - ..\ThirdParty\ServiceStack\ServiceStack.Common.dll - ..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll -- cgit v1.2.3 From 13d8110ce29a7d976c3e88dc4b330922964ac11a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 31 Oct 2016 23:07:45 -0400 Subject: make api project portable --- .../IO/ManagedFileSystem.cs | 17 ++ Emby.Common.Implementations/project.json | 3 +- MediaBrowser.Api/ApiEntryPoint.cs | 41 ++--- MediaBrowser.Api/BasePeriodicWebSocketListener.cs | 27 ++- MediaBrowser.Api/EnvironmentService.cs | 27 +-- MediaBrowser.Api/Images/ImageByNameService.cs | 2 +- MediaBrowser.Api/Images/ImageService.cs | 2 +- MediaBrowser.Api/Images/RemoteImageService.cs | 21 +-- MediaBrowser.Api/ItemLookupService.cs | 19 +- .../Library/FileOrganizationService.cs | 4 +- .../Library/LibraryStructureService.cs | 2 +- MediaBrowser.Api/LiveTv/LiveTvService.cs | 9 +- MediaBrowser.Api/MediaBrowser.Api.csproj | 20 +-- MediaBrowser.Api/MediaBrowser.Api.nuget.targets | 6 + MediaBrowser.Api/Playback/BaseStreamingService.cs | 199 ++++++++++----------- MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 7 +- MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs | 6 +- MediaBrowser.Api/Playback/TranscodingThrottler.cs | 16 +- .../ScheduledTasksWebSocketListener.cs | 12 +- .../Session/SessionInfoWebSocketListener.cs | 7 +- MediaBrowser.Api/Sync/SyncJobWebSocketListener.cs | 8 +- MediaBrowser.Api/Sync/SyncJobsWebSocketListener.cs | 8 +- .../System/ActivityLogWebSocketListener.cs | 7 +- .../System/SystemInfoWebSocketListener.cs | 7 +- MediaBrowser.Api/System/SystemService.cs | 2 +- MediaBrowser.Api/project.json | 17 ++ MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 3 + MediaBrowser.Model/Diagnostics/IProcess.cs | 19 ++ MediaBrowser.Model/Diagnostics/IProcessFactory.cs | 27 +++ MediaBrowser.Model/IO/IFileSystem.cs | 2 + MediaBrowser.Model/MediaBrowser.Model.csproj | 4 + MediaBrowser.Model/Threading/ITimer.cs | 10 ++ MediaBrowser.Model/Threading/ITimerFactory.cs | 10 ++ .../Manager/ItemImageProvider.cs | 2 +- .../LiveTv/LiveTvManager.cs | 10 ++ 35 files changed, 327 insertions(+), 256 deletions(-) create mode 100644 MediaBrowser.Api/MediaBrowser.Api.nuget.targets create mode 100644 MediaBrowser.Api/project.json create mode 100644 MediaBrowser.Model/Diagnostics/IProcess.cs create mode 100644 MediaBrowser.Model/Diagnostics/IProcessFactory.cs create mode 100644 MediaBrowser.Model/Threading/ITimer.cs create mode 100644 MediaBrowser.Model/Threading/ITimerFactory.cs (limited to 'MediaBrowser.Server.Implementations') diff --git a/Emby.Common.Implementations/IO/ManagedFileSystem.cs b/Emby.Common.Implementations/IO/ManagedFileSystem.cs index bfc316d3f..a8aa1a3cd 100644 --- a/Emby.Common.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Common.Implementations/IO/ManagedFileSystem.cs @@ -577,6 +577,23 @@ namespace Emby.Common.Implementations.IO Directory.CreateDirectory(path); } + public List GetDrives() + { + // Only include drives in the ready state or this method could end up being very slow, waiting for drives to timeout + return DriveInfo.GetDrives().Where(d => d.IsReady).Select(d => new FileSystemMetadata + { + Name = GetName(d), + FullName = d.RootDirectory.FullName, + IsDirectory = true + + }).ToList(); + } + + private string GetName(DriveInfo drive) + { + return drive.Name; + } + public IEnumerable GetDirectories(string path, bool recursive = false) { var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; diff --git a/Emby.Common.Implementations/project.json b/Emby.Common.Implementations/project.json index 4cb5213ba..444d0e13e 100644 --- a/Emby.Common.Implementations/project.json +++ b/Emby.Common.Implementations/project.json @@ -43,7 +43,8 @@ "MediaBrowser.Model": { "target": "project" }, - "System.Net.Requests": "4.0.11", + "System.IO.FileSystem.DriveInfo": "4.0.0", + "System.Net.Requests": "4.0.11", "System.Xml.XmlSerializer": "4.0.11", "System.Net.Http": "4.1.0", "System.Net.Primitives": "4.0.11", diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 588236a39..8f5b5eaaf 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -16,9 +16,10 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; +using MediaBrowser.Model.Diagnostics; using MediaBrowser.Model.IO; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Threading; namespace MediaBrowser.Api { @@ -46,6 +47,8 @@ namespace MediaBrowser.Api private readonly ISessionManager _sessionManager; private readonly IFileSystem _fileSystem; private readonly IMediaSourceManager _mediaSourceManager; + public readonly ITimerFactory TimerFactory; + public readonly IProcessFactory ProcessFactory; /// /// The active transcoding jobs @@ -63,13 +66,15 @@ namespace MediaBrowser.Api /// The configuration. /// The file system. /// The media source manager. - public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config, IFileSystem fileSystem, IMediaSourceManager mediaSourceManager) + public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config, IFileSystem fileSystem, IMediaSourceManager mediaSourceManager, ITimerFactory timerFactory, IProcessFactory processFactory) { Logger = logger; _sessionManager = sessionManager; _config = config; _fileSystem = fileSystem; _mediaSourceManager = mediaSourceManager; + TimerFactory = timerFactory; + ProcessFactory = processFactory; Instance = this; _sessionManager.PlaybackProgress += _sessionManager_PlaybackProgress; @@ -116,7 +121,7 @@ namespace MediaBrowser.Api { DeleteEncodedMediaCache(); } - catch (DirectoryNotFoundException) + catch (FileNotFoundException) { // Don't clutter the log } @@ -168,7 +173,8 @@ namespace MediaBrowser.Api // Try to allow for some time to kill the ffmpeg processes and delete the partial stream files if (jobCount > 0) { - Thread.Sleep(1000); + var task = Task.Delay(1000); + Task.WaitAll(task); } } @@ -190,14 +196,14 @@ namespace MediaBrowser.Api string liveStreamId, string transcodingJobId, TranscodingJobType type, - Process process, + IProcess process, string deviceId, StreamState state, CancellationTokenSource cancellationTokenSource) { lock (_activeTranscodingJobs) { - var job = new TranscodingJob(Logger) + var job = new TranscodingJob(Logger, TimerFactory) { Type = type, Path = path, @@ -599,10 +605,6 @@ namespace MediaBrowser.Api { DeleteHlsPartialStreamFiles(path); } - } - catch (DirectoryNotFoundException) - { - } catch (FileNotFoundException) { @@ -650,10 +652,6 @@ namespace MediaBrowser.Api { //Logger.Debug("Deleting HLS file {0}", file); _fileSystem.DeleteFile(file); - } - catch (DirectoryNotFoundException) - { - } catch (FileNotFoundException) { @@ -706,7 +704,7 @@ namespace MediaBrowser.Api /// Gets or sets the process. /// /// The process. - public Process Process { get; set; } + public IProcess Process { get; set; } public ILogger Logger { get; private set; } /// /// Gets or sets the active request count. @@ -717,7 +715,9 @@ namespace MediaBrowser.Api /// Gets or sets the kill timer. /// /// The kill timer. - private Timer KillTimer { get; set; } + private ITimer KillTimer { get; set; } + + private readonly ITimerFactory _timerFactory; public string DeviceId { get; set; } @@ -747,9 +747,10 @@ namespace MediaBrowser.Api public DateTime LastPingDate { get; set; } public int PingTimeout { get; set; } - public TranscodingJob(ILogger logger) + public TranscodingJob(ILogger logger, ITimerFactory timerFactory) { Logger = logger; + _timerFactory = timerFactory; } public void StopKillTimer() @@ -775,12 +776,12 @@ namespace MediaBrowser.Api } } - public void StartKillTimer(TimerCallback callback) + public void StartKillTimer(Action callback) { StartKillTimer(callback, PingTimeout); } - public void StartKillTimer(TimerCallback callback, int intervalMs) + public void StartKillTimer(Action callback, int intervalMs) { if (HasExited) { @@ -792,7 +793,7 @@ namespace MediaBrowser.Api if (KillTimer == null) { //Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); - KillTimer = new Timer(callback, this, intervalMs, Timeout.Infinite); + KillTimer = _timerFactory.Create(callback, this, intervalMs, Timeout.Infinite); } else { diff --git a/MediaBrowser.Api/BasePeriodicWebSocketListener.cs b/MediaBrowser.Api/BasePeriodicWebSocketListener.cs index b650cd4c2..fe7de387f 100644 --- a/MediaBrowser.Api/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Api/BasePeriodicWebSocketListener.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; +using MediaBrowser.Model.Threading; namespace MediaBrowser.Api { @@ -22,8 +23,8 @@ namespace MediaBrowser.Api /// /// The _active connections /// - protected readonly List> ActiveConnections = - new List>(); + protected readonly List> ActiveConnections = + new List>(); /// /// Gets the name. @@ -43,12 +44,9 @@ namespace MediaBrowser.Api /// protected ILogger Logger; - /// - /// Initializes a new instance of the class. - /// - /// The logger. - /// logger - protected BasePeriodicWebSocketListener(ILogger logger) + protected ITimerFactory TimerFactory { get; private set; } + + protected BasePeriodicWebSocketListener(ILogger logger, ITimerFactory timerFactory) { if (logger == null) { @@ -56,6 +54,7 @@ namespace MediaBrowser.Api } Logger = logger; + TimerFactory = timerFactory; } /// @@ -124,7 +123,7 @@ namespace MediaBrowser.Api Logger.Debug("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name); var timer = SendOnTimer ? - new Timer(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) : + TimerFactory.Create(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) : null; var state = new TStateType @@ -137,7 +136,7 @@ namespace MediaBrowser.Api lock (ActiveConnections) { - ActiveConnections.Add(new Tuple(message.Connection, cancellationTokenSource, timer, state, semaphore)); + ActiveConnections.Add(new Tuple(message.Connection, cancellationTokenSource, timer, state, semaphore)); } if (timer != null) @@ -154,7 +153,7 @@ namespace MediaBrowser.Api { var connection = (IWebSocketConnection)state; - Tuple tuple; + Tuple tuple; lock (ActiveConnections) { @@ -177,7 +176,7 @@ namespace MediaBrowser.Api protected void SendData(bool force) { - List> tuples; + List> tuples; lock (ActiveConnections) { @@ -205,7 +204,7 @@ namespace MediaBrowser.Api } } - private async void SendData(Tuple tuple) + private async void SendData(Tuple tuple) { var connection = tuple.Item1; @@ -266,7 +265,7 @@ namespace MediaBrowser.Api /// Disposes the connection. /// /// The connection. - private void DisposeConnection(Tuple connection) + private void DisposeConnection(Tuple connection) { Logger.Debug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name); diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs index c05446fbb..bab538c91 100644 --- a/MediaBrowser.Api/EnvironmentService.cs +++ b/MediaBrowser.Api/EnvironmentService.cs @@ -4,12 +4,8 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Linq; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; -using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; namespace MediaBrowser.Api @@ -110,6 +106,7 @@ namespace MediaBrowser.Api public class EnvironmentService : BaseApiService { const char UncSeparator = '\\'; + const string UncSeparatorString = "\\"; /// /// The _network manager @@ -139,7 +136,7 @@ namespace MediaBrowser.Api try { var qnap = "/share/CACHEDEV1_DATA"; - if (Directory.Exists(qnap)) + if (_fileSystem.DirectoryExists(qnap)) { result.Path = qnap; } @@ -166,7 +163,7 @@ namespace MediaBrowser.Api throw new ArgumentNullException("Path"); } - var networkPrefix = UncSeparator.ToString(CultureInfo.InvariantCulture) + UncSeparator.ToString(CultureInfo.InvariantCulture); + var networkPrefix = UncSeparatorString + UncSeparatorString; if (path.StartsWith(networkPrefix, StringComparison.OrdinalIgnoreCase) && path.LastIndexOf(UncSeparator) == 1) { @@ -203,13 +200,11 @@ namespace MediaBrowser.Api /// IEnumerable{FileSystemEntryInfo}. private IEnumerable GetDrives() { - // Only include drives in the ready state or this method could end up being very slow, waiting for drives to timeout - return DriveInfo.GetDrives().Where(d => d.IsReady).Select(d => new FileSystemEntryInfo + return _fileSystem.GetDrives().Select(d => new FileSystemEntryInfo { - Name = GetName(d), - Path = d.RootDirectory.FullName, + Name = d.Name, + Path = d.FullName, Type = FileSystemEntryType.Directory - }); } @@ -227,16 +222,6 @@ namespace MediaBrowser.Api return ToOptimizedSerializedResultUsingCache(result); } - /// - /// Gets the name. - /// - /// The drive. - /// System.String. - private string GetName(DriveInfo drive) - { - return drive.Name; - } - /// /// Gets the network shares. /// diff --git a/MediaBrowser.Api/Images/ImageByNameService.cs b/MediaBrowser.Api/Images/ImageByNameService.cs index 12ac8f68f..e0a9246c1 100644 --- a/MediaBrowser.Api/Images/ImageByNameService.cs +++ b/MediaBrowser.Api/Images/ImageByNameService.cs @@ -150,7 +150,7 @@ namespace MediaBrowser.Api.Images .OrderBy(i => i.Name) .ToList(); } - catch (DirectoryNotFoundException) + catch (IOException) { return new List(); } diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index dba90d273..c41907a87 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -320,7 +320,7 @@ namespace MediaBrowser.Api.Images { if (info.IsLocalFile) { - var fileInfo = new FileInfo(info.Path); + var fileInfo = _fileSystem.GetFileInfo(info.Path); length = fileInfo.Length; var size = _imageProcessor.GetImageSize(info); diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs index f6c9c9767..eb871746d 100644 --- a/MediaBrowser.Api/Images/RemoteImageService.cs +++ b/MediaBrowser.Api/Images/RemoteImageService.cs @@ -234,21 +234,18 @@ namespace MediaBrowser.Api.Images try { - using (var reader = new StreamReader(pointerCachePath)) - { - contentPath = await reader.ReadToEndAsync().ConfigureAwait(false); - } + contentPath = _fileSystem.ReadAllText(pointerCachePath); - if (_fileSystem.FileExists(contentPath)) + if (_fileSystem.FileExists(contentPath)) { return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false); } } - catch (DirectoryNotFoundException) + catch (FileNotFoundException) { // Means the file isn't cached yet } - catch (FileNotFoundException) + catch (IOException) { // Means the file isn't cached yet } @@ -256,10 +253,7 @@ namespace MediaBrowser.Api.Images await DownloadImage(request.ImageUrl, urlHash, pointerCachePath).ConfigureAwait(false); // Read the pointer file again - using (var reader = new StreamReader(pointerCachePath)) - { - contentPath = await reader.ReadToEndAsync().ConfigureAwait(false); - } + contentPath = _fileSystem.ReadAllText(pointerCachePath); return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false); } @@ -294,10 +288,7 @@ namespace MediaBrowser.Api.Images } _fileSystem.CreateDirectory(Path.GetDirectoryName(pointerCachePath)); - using (var writer = new StreamWriter(pointerCachePath)) - { - await writer.WriteAsync(fullCachePath).ConfigureAwait(false); - } + _fileSystem.WriteAllText(pointerCachePath, fullCachePath); } /// diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs index bdb9133d3..1700a10cd 100644 --- a/MediaBrowser.Api/ItemLookupService.cs +++ b/MediaBrowser.Api/ItemLookupService.cs @@ -247,21 +247,18 @@ namespace MediaBrowser.Api try { - using (var reader = new StreamReader(pointerCachePath)) - { - contentPath = await reader.ReadToEndAsync().ConfigureAwait(false); - } + contentPath = _fileSystem.ReadAllText(pointerCachePath); if (_fileSystem.FileExists(contentPath)) { return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false); } } - catch (DirectoryNotFoundException) + catch (FileNotFoundException) { // Means the file isn't cached yet } - catch (FileNotFoundException) + catch (IOException) { // Means the file isn't cached yet } @@ -269,10 +266,7 @@ namespace MediaBrowser.Api await DownloadImage(request.ProviderName, request.ImageUrl, urlHash, pointerCachePath).ConfigureAwait(false); // Read the pointer file again - using (var reader = new StreamReader(pointerCachePath)) - { - contentPath = await reader.ReadToEndAsync().ConfigureAwait(false); - } + contentPath = _fileSystem.ReadAllText(pointerCachePath); return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false); } @@ -303,10 +297,7 @@ namespace MediaBrowser.Api } _fileSystem.CreateDirectory(Path.GetDirectoryName(pointerCachePath)); - using (var writer = new StreamWriter(pointerCachePath)) - { - await writer.WriteAsync(fullCachePath).ConfigureAwait(false); - } + _fileSystem.WriteAllText(pointerCachePath, fullCachePath); } /// diff --git a/MediaBrowser.Api/Library/FileOrganizationService.cs b/MediaBrowser.Api/Library/FileOrganizationService.cs index 35948b453..ea610ac5c 100644 --- a/MediaBrowser.Api/Library/FileOrganizationService.cs +++ b/MediaBrowser.Api/Library/FileOrganizationService.cs @@ -204,10 +204,10 @@ namespace MediaBrowser.Api.Library public void Post(DeleteSmartMatchEntry request) { - request.Entries.ForEach(entry => + foreach (var entry in request.Entries) { _iFileOrganizationService.DeleteSmartMatchEntry(entry.Name, entry.Value); - }); + } } } } diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs index 18afcd51e..c3bb80dcb 100644 --- a/MediaBrowser.Api/Library/LibraryStructureService.cs +++ b/MediaBrowser.Api/Library/LibraryStructureService.cs @@ -259,7 +259,7 @@ namespace MediaBrowser.Api.Library if (!_fileSystem.DirectoryExists(currentPath)) { - throw new DirectoryNotFoundException("The media collection does not exist"); + throw new FileNotFoundException("The media collection does not exist"); } if (!string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase) && _fileSystem.DirectoryExists(newPath)) diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 83785466c..fffd7ad7e 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -22,7 +22,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.IO; using MediaBrowser.Model.Services; -using MediaBrowser.Server.Implementations.LiveTv.EmbyTV; namespace MediaBrowser.Api.LiveTv { @@ -708,11 +707,11 @@ namespace MediaBrowser.Api.LiveTv _fileSystem = fileSystem; } - public async Task Get(GetLiveRecordingFile request) + public object Get(GetLiveRecordingFile request) { - var path = EmbyTV.Current.GetActiveRecordingPath(request.Id); + var path = _liveTvManager.GetEmbyTvActiveRecordingPath(request.Id); - if (path == null) + if (string.IsNullOrWhiteSpace(path)) { throw new FileNotFoundException(); } @@ -729,7 +728,7 @@ namespace MediaBrowser.Api.LiveTv public async Task Get(GetLiveStreamFile request) { - var directStreamProvider = (await EmbyTV.Current.GetLiveStream(request.Id).ConfigureAwait(false)) as IDirectStreamProvider; + var directStreamProvider = (await _liveTvManager.GetEmbyTvLiveStream(request.Id).ConfigureAwait(false)) as IDirectStreamProvider; var outputHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType("file." + request.Container); diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index fdfbaae0f..df491ce85 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -11,10 +11,9 @@ MediaBrowser.Api 512 ..\ - v4.6 - - - + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 true @@ -45,13 +44,6 @@ Always - - - - - - - Properties\SharedVersion.cs @@ -183,12 +175,8 @@ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B} MediaBrowser.Model - - {2e781478-814d-4a48-9d80-bff206441a65} - MediaBrowser.Server.Implementations - - + diff --git a/MediaBrowser.Api/MediaBrowser.Api.nuget.targets b/MediaBrowser.Api/MediaBrowser.Api.nuget.targets new file mode 100644 index 000000000..e69ce0e64 --- /dev/null +++ b/MediaBrowser.Api/MediaBrowser.Api.nuget.targets @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index ba3b3e348..c62889214 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -2,7 +2,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Dlna; -using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dlna; @@ -14,18 +13,15 @@ using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Model.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller; -using MediaBrowser.Controller.IO; +using MediaBrowser.Model.Diagnostics; namespace MediaBrowser.Api.Playback { @@ -1158,32 +1154,24 @@ namespace MediaBrowser.Api.Playback var transcodingId = Guid.NewGuid().ToString("N"); var commandLineArgs = GetCommandLineArguments(outputPath, state, true); - var process = new Process + var process = ApiEntryPoint.Instance.ProcessFactory.Create(new ProcessOptions { - StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, + CreateNoWindow = true, + UseShellExecute = false, - // Must consume both stdout and stderr or deadlocks may occur - //RedirectStandardOutput = true, - RedirectStandardError = true, - RedirectStandardInput = true, + // Must consume both stdout and stderr or deadlocks may occur + //RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, - FileName = MediaEncoder.EncoderPath, - Arguments = commandLineArgs, + FileName = MediaEncoder.EncoderPath, + Arguments = commandLineArgs, - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - }, - - EnableRaisingEvents = true - }; - - if (!string.IsNullOrWhiteSpace(workingDirectory)) - { - process.StartInfo.WorkingDirectory = workingDirectory; - } + IsHidden = true, + ErrorDialog = false, + EnableRaisingEvents = true, + WorkingDirectory = !string.IsNullOrWhiteSpace(workingDirectory) ? workingDirectory : null + }); var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, state.Request.PlaySessionId, @@ -1268,7 +1256,7 @@ namespace MediaBrowser.Api.Playback { if (EnableThrottling(state)) { - transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ServerConfigurationManager); + transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ServerConfigurationManager, ApiEntryPoint.Instance.TimerFactory, FileSystem); state.TranscodingThrottler.Start(); } } @@ -1520,7 +1508,7 @@ namespace MediaBrowser.Api.Playback /// The process. /// The job. /// The state. - private void OnFfMpegProcessExited(Process process, TranscodingJob job, StreamState state) + private void OnFfMpegProcessExited(IProcess process, TranscodingJob job, StreamState state) { if (job != null) { @@ -2408,97 +2396,98 @@ namespace MediaBrowser.Api.Playback { return Task.FromResult(true); } + return Task.FromResult(true); - var dict = new Dictionary(); + //var dict = new Dictionary(); - var outputAudio = GetAudioEncoder(state); - if (!string.IsNullOrWhiteSpace(outputAudio)) - { - dict["outputAudio"] = outputAudio; - } - - var outputVideo = GetVideoEncoder(state); - if (!string.IsNullOrWhiteSpace(outputVideo)) - { - dict["outputVideo"] = outputVideo; - } + //var outputAudio = GetAudioEncoder(state); + //if (!string.IsNullOrWhiteSpace(outputAudio)) + //{ + // dict["outputAudio"] = outputAudio; + //} - if (ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputAudio ?? string.Empty, StringComparer.OrdinalIgnoreCase) && - ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputVideo ?? string.Empty, StringComparer.OrdinalIgnoreCase)) - { - return Task.FromResult(true); - } + //var outputVideo = GetVideoEncoder(state); + //if (!string.IsNullOrWhiteSpace(outputVideo)) + //{ + // dict["outputVideo"] = outputVideo; + //} - dict["id"] = AppHost.SystemId; - dict["type"] = state.VideoRequest == null ? "Audio" : "Video"; + //if (ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputAudio ?? string.Empty, StringComparer.OrdinalIgnoreCase) && + // ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputVideo ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + //{ + // return Task.FromResult(true); + //} - var audioStream = state.AudioStream; - if (audioStream != null && !string.IsNullOrWhiteSpace(audioStream.Codec)) - { - dict["inputAudio"] = audioStream.Codec; - } + //dict["id"] = AppHost.SystemId; + //dict["type"] = state.VideoRequest == null ? "Audio" : "Video"; - var videoStream = state.VideoStream; - if (videoStream != null && !string.IsNullOrWhiteSpace(videoStream.Codec)) - { - dict["inputVideo"] = videoStream.Codec; - } + //var audioStream = state.AudioStream; + //if (audioStream != null && !string.IsNullOrWhiteSpace(audioStream.Codec)) + //{ + // dict["inputAudio"] = audioStream.Codec; + //} - var cert = GetType().Assembly.GetModules().First().GetSignerCertificate(); - if (cert != null) - { - dict["assemblySig"] = cert.GetCertHashString(); - dict["certSubject"] = cert.Subject ?? string.Empty; - dict["certIssuer"] = cert.Issuer ?? string.Empty; - } - else - { - return Task.FromResult(true); - } + //var videoStream = state.VideoStream; + //if (videoStream != null && !string.IsNullOrWhiteSpace(videoStream.Codec)) + //{ + // dict["inputVideo"] = videoStream.Codec; + //} - if (state.SupportedAudioCodecs.Count > 0) - { - dict["supportedAudioCodecs"] = string.Join(",", state.SupportedAudioCodecs.ToArray()); - } + //var cert = GetType().Assembly.GetModules().First().GetSignerCertificate(); + //if (cert != null) + //{ + // dict["assemblySig"] = cert.GetCertHashString(); + // dict["certSubject"] = cert.Subject ?? string.Empty; + // dict["certIssuer"] = cert.Issuer ?? string.Empty; + //} + //else + //{ + // return Task.FromResult(true); + //} - var auth = AuthorizationContext.GetAuthorizationInfo(Request); + //if (state.SupportedAudioCodecs.Count > 0) + //{ + // dict["supportedAudioCodecs"] = string.Join(",", state.SupportedAudioCodecs.ToArray()); + //} - dict["appName"] = auth.Client ?? string.Empty; - dict["appVersion"] = auth.Version ?? string.Empty; - dict["device"] = auth.Device ?? string.Empty; - dict["deviceId"] = auth.DeviceId ?? string.Empty; - dict["context"] = "streaming"; + //var auth = AuthorizationContext.GetAuthorizationInfo(Request); - //Logger.Info(JsonSerializer.SerializeToString(dict)); - if (!ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputAudio ?? string.Empty, StringComparer.OrdinalIgnoreCase)) - { - var list = ServerConfigurationManager.Configuration.CodecsUsed.ToList(); - list.Add(outputAudio); - ServerConfigurationManager.Configuration.CodecsUsed = list.ToArray(); - } + //dict["appName"] = auth.Client ?? string.Empty; + //dict["appVersion"] = auth.Version ?? string.Empty; + //dict["device"] = auth.Device ?? string.Empty; + //dict["deviceId"] = auth.DeviceId ?? string.Empty; + //dict["context"] = "streaming"; - if (!ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputVideo ?? string.Empty, StringComparer.OrdinalIgnoreCase)) - { - var list = ServerConfigurationManager.Configuration.CodecsUsed.ToList(); - list.Add(outputVideo); - ServerConfigurationManager.Configuration.CodecsUsed = list.ToArray(); - } + ////Logger.Info(JsonSerializer.SerializeToString(dict)); + //if (!ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputAudio ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + //{ + // var list = ServerConfigurationManager.Configuration.CodecsUsed.ToList(); + // list.Add(outputAudio); + // ServerConfigurationManager.Configuration.CodecsUsed = list.ToArray(); + //} - ServerConfigurationManager.SaveConfiguration(); + //if (!ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputVideo ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + //{ + // var list = ServerConfigurationManager.Configuration.CodecsUsed.ToList(); + // list.Add(outputVideo); + // ServerConfigurationManager.Configuration.CodecsUsed = list.ToArray(); + //} - //Logger.Info(JsonSerializer.SerializeToString(dict)); - var options = new HttpRequestOptions() - { - Url = "https://mb3admin.com/admin/service/transcoding/report", - CancellationToken = CancellationToken.None, - LogRequest = false, - LogErrors = false, - BufferContent = false - }; - options.RequestContent = JsonSerializer.SerializeToString(dict); - options.RequestContentType = "application/json"; + //ServerConfigurationManager.SaveConfiguration(); - return HttpClient.Post(options); + ////Logger.Info(JsonSerializer.SerializeToString(dict)); + //var options = new HttpRequestOptions() + //{ + // Url = "https://mb3admin.com/admin/service/transcoding/report", + // CancellationToken = CancellationToken.None, + // LogRequest = false, + // LogErrors = false, + // BufferContent = false + //}; + //options.RequestContent = JsonSerializer.SerializeToString(dict); + //options.RequestContentType = "application/json"; + + //return HttpClient.Post(options); } /// diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 07ace5c2c..353e83205 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -356,7 +356,8 @@ namespace MediaBrowser.Api.Playback.Hls { Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, file.FullName); - Thread.Sleep(100); + var task = Task.Delay(100); + Task.WaitAll(task); DeleteFile(file, retryCount + 1); } catch (Exception ex) @@ -378,7 +379,7 @@ namespace MediaBrowser.Api.Playback.Hls .OrderByDescending(fileSystem.GetLastWriteTimeUtc) .FirstOrDefault(); } - catch (DirectoryNotFoundException) + catch (IOException) { return null; } @@ -881,7 +882,7 @@ namespace MediaBrowser.Api.Playback.Hls if (state.IsOutputVideo && !EnableCopyTs(state) && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && (state.Request.StartTimeTicks ?? 0) > 0) { - timestampOffsetParam = " -output_ts_offset " + MediaEncoder.GetTimeParameter(state.Request.StartTimeTicks ?? 0).ToString(CultureInfo.InvariantCulture); + timestampOffsetParam = " -output_ts_offset " + MediaEncoder.GetTimeParameter(state.Request.StartTimeTicks ?? 0); } var mapArgs = state.IsOutputVideo ? GetMapArgs(state) : string.Empty; diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs index 4519268fc..65c1af79e 100644 --- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs +++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs @@ -79,11 +79,13 @@ namespace MediaBrowser.Api.Playback.Hls { private readonly IServerApplicationPaths _appPaths; private readonly IServerConfigurationManager _config; + private readonly IFileSystem _fileSystem; - public HlsSegmentService(IServerApplicationPaths appPaths, IServerConfigurationManager config) + public HlsSegmentService(IServerApplicationPaths appPaths, IServerConfigurationManager config, IFileSystem fileSystem) { _appPaths = appPaths; _config = config; + _fileSystem = fileSystem; } public Task Get(GetHlsPlaylistLegacy request) @@ -111,7 +113,7 @@ namespace MediaBrowser.Api.Playback.Hls var normalizedPlaylistId = request.PlaylistId; - var playlistPath = Directory.EnumerateFiles(_config.ApplicationPaths.TranscodingTempPath, "*") + var playlistPath = _fileSystem.GetFilePaths(_config.ApplicationPaths.TranscodingTempPath) .FirstOrDefault(i => string.Equals(Path.GetExtension(i), ".m3u8", StringComparison.OrdinalIgnoreCase) && i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1); return GetFileResult(file, playlistPath); diff --git a/MediaBrowser.Api/Playback/TranscodingThrottler.cs b/MediaBrowser.Api/Playback/TranscodingThrottler.cs index a7d53cd44..c42d0c3e4 100644 --- a/MediaBrowser.Api/Playback/TranscodingThrottler.cs +++ b/MediaBrowser.Api/Playback/TranscodingThrottler.cs @@ -2,8 +2,8 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; using System; -using System.IO; -using System.Threading; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Threading; namespace MediaBrowser.Api.Playback { @@ -11,15 +11,19 @@ namespace MediaBrowser.Api.Playback { private readonly TranscodingJob _job; private readonly ILogger _logger; - private Timer _timer; + private ITimer _timer; private bool _isPaused; private readonly IConfigurationManager _config; + private readonly ITimerFactory _timerFactory; + private readonly IFileSystem _fileSystem; - public TranscodingThrottler(TranscodingJob job, ILogger logger, IConfigurationManager config) + public TranscodingThrottler(TranscodingJob job, ILogger logger, IConfigurationManager config, ITimerFactory timerFactory, IFileSystem fileSystem) { _job = job; _logger = logger; _config = config; + _timerFactory = timerFactory; + _fileSystem = fileSystem; } private EncodingOptions GetOptions() @@ -29,7 +33,7 @@ namespace MediaBrowser.Api.Playback public void Start() { - _timer = new Timer(TimerCallback, null, 5000, 5000); + _timer = _timerFactory.Create(TimerCallback, null, 5000, 5000); } private void TimerCallback(object state) @@ -120,7 +124,7 @@ namespace MediaBrowser.Api.Playback try { - var bytesTranscoded = job.BytesTranscoded ?? new FileInfo(path).Length; + var bytesTranscoded = job.BytesTranscoded ?? _fileSystem.GetFileInfo(path).Length; // Estimate the bytes the transcoder should be ahead double gapFactor = gapLengthInTicks; diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs index 6e64345b9..ee74ec450 100644 --- a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs @@ -1,10 +1,10 @@ -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Events; +using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Tasks; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using MediaBrowser.Model.Threading; namespace MediaBrowser.Api.ScheduledTasks { @@ -31,10 +31,8 @@ namespace MediaBrowser.Api.ScheduledTasks /// /// Initializes a new instance of the class. /// - /// The logger. - /// The task manager. - public ScheduledTasksWebSocketListener(ILogger logger, ITaskManager taskManager) - : base(logger) + public ScheduledTasksWebSocketListener(ILogger logger, ITaskManager taskManager, ITimerFactory timerFactory) + : base(logger, timerFactory) { TaskManager = taskManager; @@ -84,7 +82,7 @@ namespace MediaBrowser.Api.ScheduledTasks { TaskManager.TaskExecuting -= TaskManager_TaskExecuting; TaskManager.TaskCompleted -= TaskManager_TaskCompleted; - + base.Dispose(dispose); } } diff --git a/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs b/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs index 8f68569b7..b90a71852 100644 --- a/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs +++ b/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs @@ -6,6 +6,7 @@ using MediaBrowser.Model.Session; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using MediaBrowser.Model.Threading; namespace MediaBrowser.Api.Session { @@ -31,10 +32,8 @@ namespace MediaBrowser.Api.Session /// /// Initializes a new instance of the class. /// - /// The logger. - /// The session manager. - public SessionInfoWebSocketListener(ILogger logger, ISessionManager sessionManager) - : base(logger) + public SessionInfoWebSocketListener(ILogger logger, ISessionManager sessionManager, ITimerFactory timerFactory) + : base(logger, timerFactory) { _sessionManager = sessionManager; diff --git a/MediaBrowser.Api/Sync/SyncJobWebSocketListener.cs b/MediaBrowser.Api/Sync/SyncJobWebSocketListener.cs index 61a26d160..ac9749a6d 100644 --- a/MediaBrowser.Api/Sync/SyncJobWebSocketListener.cs +++ b/MediaBrowser.Api/Sync/SyncJobWebSocketListener.cs @@ -1,11 +1,11 @@ -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Sync; +using MediaBrowser.Controller.Sync; using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Sync; using System; using System.Linq; using System.Threading.Tasks; +using MediaBrowser.Model.Threading; namespace MediaBrowser.Api.Sync { @@ -26,8 +26,8 @@ namespace MediaBrowser.Api.Sync private readonly ISyncManager _syncManager; private string _jobId; - public SyncJobWebSocketListener(ILogger logger, ISyncManager syncManager) - : base(logger) + public SyncJobWebSocketListener(ILogger logger, ISyncManager syncManager, ITimerFactory timerFactory) + : base(logger, timerFactory) { _syncManager = syncManager; _syncManager.SyncJobCancelled += _syncManager_SyncJobCancelled; diff --git a/MediaBrowser.Api/Sync/SyncJobsWebSocketListener.cs b/MediaBrowser.Api/Sync/SyncJobsWebSocketListener.cs index 906a52209..5f9d1ff0e 100644 --- a/MediaBrowser.Api/Sync/SyncJobsWebSocketListener.cs +++ b/MediaBrowser.Api/Sync/SyncJobsWebSocketListener.cs @@ -1,9 +1,9 @@ -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Sync; +using MediaBrowser.Controller.Sync; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Sync; using System.Collections.Generic; using System.Threading.Tasks; +using MediaBrowser.Model.Threading; namespace MediaBrowser.Api.Sync { @@ -25,8 +25,8 @@ namespace MediaBrowser.Api.Sync private string _userId; private string _targetId; - public SyncJobsWebSocketListener(ILogger logger, ISyncManager syncManager) - : base(logger) + public SyncJobsWebSocketListener(ILogger logger, ISyncManager syncManager, ITimerFactory timerFactory) + : base(logger, timerFactory) { _syncManager = syncManager; _syncManager.SyncJobCancelled += _syncManager_SyncJobCancelled; diff --git a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs index aaf9a3347..c641695dd 100644 --- a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs +++ b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs @@ -1,9 +1,9 @@ -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Activity; using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; using System.Collections.Generic; using System.Threading.Tasks; +using MediaBrowser.Model.Threading; namespace MediaBrowser.Api.System { @@ -26,8 +26,7 @@ namespace MediaBrowser.Api.System /// private readonly IActivityManager _activityManager; - public ActivityLogWebSocketListener(ILogger logger, IActivityManager activityManager) - : base(logger) + public ActivityLogWebSocketListener(ILogger logger, ITimerFactory timerFactory, IActivityManager activityManager) : base(logger, timerFactory) { _activityManager = activityManager; _activityManager.EntryCreated += _activityManager_EntryCreated; diff --git a/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs b/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs index a53bfac27..8d74cc66c 100644 --- a/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs +++ b/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs @@ -3,6 +3,7 @@ using MediaBrowser.Controller.Net; using MediaBrowser.Model.Logging; using MediaBrowser.Model.System; using System.Threading.Tasks; +using MediaBrowser.Model.Threading; namespace MediaBrowser.Api.System { @@ -28,10 +29,8 @@ namespace MediaBrowser.Api.System /// /// Initializes a new instance of the class. /// - /// The logger. - /// The app host. - public SystemInfoWebSocketListener(ILogger logger, IServerApplicationHost appHost) - : base(logger) + public SystemInfoWebSocketListener(ILogger logger, IServerApplicationHost appHost, ITimerFactory timerFactory) + : base(logger, timerFactory) { _appHost = appHost; } diff --git a/MediaBrowser.Api/System/SystemService.cs b/MediaBrowser.Api/System/SystemService.cs index d67c1b47f..bdae670e1 100644 --- a/MediaBrowser.Api/System/SystemService.cs +++ b/MediaBrowser.Api/System/SystemService.cs @@ -126,7 +126,7 @@ namespace MediaBrowser.Api.System .Where(i => string.Equals(i.Extension, ".txt", StringComparison.OrdinalIgnoreCase)) .ToList(); } - catch (DirectoryNotFoundException) + catch (IOException) { files = new List(); } diff --git a/MediaBrowser.Api/project.json b/MediaBrowser.Api/project.json new file mode 100644 index 000000000..fbbe9eaf3 --- /dev/null +++ b/MediaBrowser.Api/project.json @@ -0,0 +1,17 @@ +{ + "frameworks":{ + "netstandard1.6":{ + "dependencies":{ + "NETStandard.Library":"1.6.0", + } + }, + ".NETPortable,Version=v4.5,Profile=Profile7":{ + "buildOptions": { + "define": [ ] + }, + "frameworkAssemblies":{ + + } + } + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 8e3c1931b..08e4956ad 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -393,5 +393,8 @@ namespace MediaBrowser.Controller.LiveTv event EventHandler> TimerCancelled; event EventHandler> TimerCreated; event EventHandler> SeriesTimerCreated; + + string GetEmbyTvActiveRecordingPath(string id); + Task GetEmbyTvLiveStream(string id); } } diff --git a/MediaBrowser.Model/Diagnostics/IProcess.cs b/MediaBrowser.Model/Diagnostics/IProcess.cs new file mode 100644 index 000000000..ab0b0cfcf --- /dev/null +++ b/MediaBrowser.Model/Diagnostics/IProcess.cs @@ -0,0 +1,19 @@ +using System; +using System.IO; + +namespace MediaBrowser.Model.Diagnostics +{ + public interface IProcess : IDisposable + { + event EventHandler Exited; + + void Kill(); + bool WaitForExit(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 new file mode 100644 index 000000000..998bbcd28 --- /dev/null +++ b/MediaBrowser.Model/Diagnostics/IProcessFactory.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +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 IsHidden { get; set; } + } +} diff --git a/MediaBrowser.Model/IO/IFileSystem.cs b/MediaBrowser.Model/IO/IFileSystem.cs index 4f920c3b0..50e32572d 100644 --- a/MediaBrowser.Model/IO/IFileSystem.cs +++ b/MediaBrowser.Model/IO/IFileSystem.cs @@ -305,6 +305,8 @@ namespace MediaBrowser.Model.IO char DirectorySeparatorChar { get; } string GetFullPath(string path); + + List GetDrives(); } public enum FileOpenMode diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index a1b478496..5999f02db 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -106,6 +106,8 @@ + + @@ -422,6 +424,8 @@ + + diff --git a/MediaBrowser.Model/Threading/ITimer.cs b/MediaBrowser.Model/Threading/ITimer.cs new file mode 100644 index 000000000..42090250b --- /dev/null +++ b/MediaBrowser.Model/Threading/ITimer.cs @@ -0,0 +1,10 @@ +using System; + +namespace MediaBrowser.Model.Threading +{ + public interface ITimer : IDisposable + { + void Change(TimeSpan dueTime, TimeSpan period); + void Change(int dueTimeMs, int periodMs); + } +} diff --git a/MediaBrowser.Model/Threading/ITimerFactory.cs b/MediaBrowser.Model/Threading/ITimerFactory.cs new file mode 100644 index 000000000..5f3df1738 --- /dev/null +++ b/MediaBrowser.Model/Threading/ITimerFactory.cs @@ -0,0 +1,10 @@ +using System; + +namespace MediaBrowser.Model.Threading +{ + public interface ITimerFactory + { + ITimer Create(Action callback, object state, TimeSpan dueTime, TimeSpan period); + ITimer Create(Action callback, object state, int dueTimeMs, int periodMs); + } +} diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index fccb298b1..9dff243c1 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -556,7 +556,7 @@ namespace MediaBrowser.Providers.Manager switch (type) { case ImageType.Primary: - return !(item is Movie || item is Series || item is Season || item is Game); + return !(item is Movie || item is Series || item is Game); default: return true; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 894ab5e58..93fc5459a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -75,6 +75,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv public event EventHandler> TimerCreated; public event EventHandler> SeriesTimerCreated; + public string GetEmbyTvActiveRecordingPath(string id) + { + return EmbyTV.EmbyTV.Current.GetActiveRecordingPath(id); + } + + public Task GetEmbyTvLiveStream(string id) + { + return EmbyTV.EmbyTV.Current.GetLiveStream(id); + } + public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager, IFileSystem fileSystem, ISecurityManager security) { _config = config; -- cgit v1.2.3 From b1276dc2084515ed817ba8b2af405a9bc1f57cd6 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 1 Nov 2016 00:07:12 -0400 Subject: make media encoding project portable --- Emby.Common.Implementations/BaseApplicationHost.cs | 14 ++ .../Diagnostics/CommonProcess.cs | 108 +++++++++++++++ .../Diagnostics/ProcessFactory.cs | 12 ++ .../Threading/CommonTimer.cs | 39 ++++++ .../Threading/TimerFactory.cs | 21 +++ Emby.Common.Implementations/project.json | 2 + Emby.Server.sln | 18 +++ MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs | 7 +- MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 41 +++--- .../Encoder/EncoderValidator.cs | 26 ++-- .../Encoder/FontConfigLoader.cs | 6 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 148 ++++++++++----------- MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs | 7 +- .../MediaBrowser.MediaEncoding.csproj | 15 +-- .../MediaBrowser.MediaEncoding.nuget.targets | 6 + .../Subtitles/OpenSubtitleDownloader.cs | 15 ++- .../Subtitles/SubtitleEncoder.cs | 111 ++++++---------- MediaBrowser.MediaEncoding/project.json | 17 +++ MediaBrowser.Model/Diagnostics/IProcessFactory.cs | 5 +- MediaBrowser.Model/TextEncoding/IEncoding.cs | 5 +- .../MediaBrowser.Server.Implementations.csproj | 3 + .../TextEncoding/TextEncoding.cs | 33 ++++- .../ApplicationHost.cs | 9 +- 23 files changed, 449 insertions(+), 219 deletions(-) create mode 100644 Emby.Common.Implementations/Diagnostics/CommonProcess.cs create mode 100644 Emby.Common.Implementations/Diagnostics/ProcessFactory.cs create mode 100644 Emby.Common.Implementations/Threading/CommonTimer.cs create mode 100644 Emby.Common.Implementations/Threading/TimerFactory.cs create mode 100644 MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.nuget.targets create mode 100644 MediaBrowser.MediaEncoding/project.json (limited to 'MediaBrowser.Server.Implementations') diff --git a/Emby.Common.Implementations/BaseApplicationHost.cs b/Emby.Common.Implementations/BaseApplicationHost.cs index 2fe82e5a4..897557efd 100644 --- a/Emby.Common.Implementations/BaseApplicationHost.cs +++ b/Emby.Common.Implementations/BaseApplicationHost.cs @@ -27,11 +27,16 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Extensions; using Emby.Common.Implementations.Cryptography; +using Emby.Common.Implementations.Diagnostics; +using Emby.Common.Implementations.Threading; using MediaBrowser.Common; using MediaBrowser.Common.IO; using MediaBrowser.Model.Cryptography; +using MediaBrowser.Model.Diagnostics; using MediaBrowser.Model.System; using MediaBrowser.Model.Tasks; +using MediaBrowser.Model.Threading; + #if NETSTANDARD1_6 using System.Runtime.Loader; #endif @@ -146,6 +151,9 @@ namespace Emby.Common.Implementations protected ISystemEvents SystemEvents { get; private set; } + protected IProcessFactory ProcessFactory { get; private set; } + protected ITimerFactory TimerFactory { get; private set; } + /// /// Gets the name. /// @@ -535,6 +543,12 @@ return null; IsoManager = new IsoManager(); RegisterSingleInstance(IsoManager); + ProcessFactory = new ProcessFactory(); + RegisterSingleInstance(ProcessFactory); + + TimerFactory = new TimerFactory(); + RegisterSingleInstance(TimerFactory); + return Task.FromResult(true); } diff --git a/Emby.Common.Implementations/Diagnostics/CommonProcess.cs b/Emby.Common.Implementations/Diagnostics/CommonProcess.cs new file mode 100644 index 000000000..06677bc29 --- /dev/null +++ b/Emby.Common.Implementations/Diagnostics/CommonProcess.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using MediaBrowser.Model.Diagnostics; + +namespace Emby.Common.Implementations.Diagnostics +{ + public class CommonProcess : IProcess + { + public event EventHandler Exited; + + private readonly ProcessOptions _options; + private readonly Process _process; + + public CommonProcess(ProcessOptions options) + { + _options = 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 + }; + +#if NET46 + startInfo.ErrorDialog = options.ErrorDialog; + + if (options.IsHidden) + { + startInfo.WindowStyle = ProcessWindowStyle.Hidden; + } +#endif + + _process = new Process + { + StartInfo = startInfo + }; + + if (options.EnableRaisingEvents) + { + _process.EnableRaisingEvents = true; + _process.Exited += _process_Exited; + } + } + + private void _process_Exited(object sender, EventArgs e) + { + if (Exited != null) + { + Exited(_process, e); + } + } + + public ProcessOptions StartInfo + { + get { return _options; } + } + + public StreamWriter StandardInput + { + get { return _process.StandardInput; } + } + + public StreamReader StandardError + { + get { return _process.StandardError; } + } + + public StreamReader StandardOutput + { + get { return _process.StandardOutput; } + } + + public int ExitCode + { + get { return _process.ExitCode; } + } + + public void Start() + { + _process.Start(); + } + + public void Kill() + { + _process.Kill(); + } + + public bool WaitForExit(int timeMs) + { + return _process.WaitForExit(timeMs); + } + + public void Dispose() + { + _process.Dispose(); + } + } +} diff --git a/Emby.Common.Implementations/Diagnostics/ProcessFactory.cs b/Emby.Common.Implementations/Diagnostics/ProcessFactory.cs new file mode 100644 index 000000000..292da023c --- /dev/null +++ b/Emby.Common.Implementations/Diagnostics/ProcessFactory.cs @@ -0,0 +1,12 @@ +using MediaBrowser.Model.Diagnostics; + +namespace Emby.Common.Implementations.Diagnostics +{ + public class ProcessFactory : IProcessFactory + { + public IProcess Create(ProcessOptions options) + { + return new CommonProcess(options); + } + } +} diff --git a/Emby.Common.Implementations/Threading/CommonTimer.cs b/Emby.Common.Implementations/Threading/CommonTimer.cs new file mode 100644 index 000000000..8895f6798 --- /dev/null +++ b/Emby.Common.Implementations/Threading/CommonTimer.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.Threading; + +namespace Emby.Common.Implementations.Threading +{ + public class CommonTimer : ITimer + { + private readonly Timer _timer; + + public CommonTimer(Action callback, object state, TimeSpan dueTime, TimeSpan period) + { + _timer = new Timer(new TimerCallback(callback), state, dueTime, period); + } + + public CommonTimer(Action callback, object state, int dueTimeMs, int periodMs) + { + _timer = new Timer(new TimerCallback(callback), state, dueTimeMs, periodMs); + } + + public void Change(TimeSpan dueTime, TimeSpan period) + { + _timer.Change(dueTime, period); + } + + public void Change(int dueTimeMs, int periodMs) + { + _timer.Change(dueTimeMs, periodMs); + } + + public void Dispose() + { + _timer.Dispose(); + } + } +} diff --git a/Emby.Common.Implementations/Threading/TimerFactory.cs b/Emby.Common.Implementations/Threading/TimerFactory.cs new file mode 100644 index 000000000..028dd0963 --- /dev/null +++ b/Emby.Common.Implementations/Threading/TimerFactory.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using MediaBrowser.Model.Threading; + +namespace Emby.Common.Implementations.Threading +{ + public class TimerFactory : ITimerFactory + { + public ITimer Create(Action callback, object state, TimeSpan dueTime, TimeSpan period) + { + return new CommonTimer(callback, state, dueTime, period); + } + + public ITimer Create(Action callback, object state, int dueTimeMs, int periodMs) + { + return new CommonTimer(callback, state, dueTimeMs, periodMs); + } + } +} diff --git a/Emby.Common.Implementations/project.json b/Emby.Common.Implementations/project.json index 444d0e13e..a65b86345 100644 --- a/Emby.Common.Implementations/project.json +++ b/Emby.Common.Implementations/project.json @@ -44,6 +44,8 @@ "target": "project" }, "System.IO.FileSystem.DriveInfo": "4.0.0", + "System.Diagnostics.Process": "4.1.0", + "System.Threading.Timer": "4.0.1", "System.Net.Requests": "4.0.11", "System.Xml.XmlSerializer": "4.0.11", "System.Net.Http": "4.1.0", diff --git a/Emby.Server.sln b/Emby.Server.sln index 2e2e093d5..e9073a8d0 100644 --- a/Emby.Server.sln +++ b/Emby.Server.sln @@ -42,6 +42,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Emby.Dlna", "Emby.Dlna\Emby EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Photos", "Emby.Photos\Emby.Photos.csproj", "{89AB4548-770D-41FD-A891-8DAFF44F452C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Api", "MediaBrowser.Api\MediaBrowser.Api.csproj", "{4FD51AC5-2C16-4308-A993-C3A84F3B4582}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.MediaEncoding", "MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj", "{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -145,6 +149,18 @@ Global {89AB4548-770D-41FD-A891-8DAFF44F452C}.Release Mono|Any CPU.Build.0 = Release|Any CPU {89AB4548-770D-41FD-A891-8DAFF44F452C}.Release|Any CPU.ActiveCfg = Release|Any CPU {89AB4548-770D-41FD-A891-8DAFF44F452C}.Release|Any CPU.Build.0 = Release|Any CPU + {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release Mono|Any CPU.ActiveCfg = Release Mono|Any CPU + {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release Mono|Any CPU.Build.0 = Release Mono|Any CPU + {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Any CPU.Build.0 = Release|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|Any CPU.ActiveCfg = Release Mono|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|Any CPU.Build.0 = Release Mono|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -166,5 +182,7 @@ Global {C227ADB7-E256-4E70-A8B9-22B9E0CF4F55} = {8ADD772F-F0A4-4A53-9B2F-AF4A4C585839} {F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5} = {8ADD772F-F0A4-4A53-9B2F-AF4A4C585839} {89AB4548-770D-41FD-A891-8DAFF44F452C} = {8ADD772F-F0A4-4A53-9B2F-AF4A4C585839} + {4FD51AC5-2C16-4308-A993-C3A84F3B4582} = {8ADD772F-F0A4-4A53-9B2F-AF4A4C585839} + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451} = {8ADD772F-F0A4-4A53-9B2F-AF4A4C585839} EndGlobalSection EndGlobal diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs index 06f992efd..5a554d26f 100644 --- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs @@ -7,15 +7,13 @@ using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; -using MediaBrowser.Model.IO; +using MediaBrowser.Model.Diagnostics; namespace MediaBrowser.MediaEncoding.Encoder { public class AudioEncoder : BaseEncoder { - public AudioEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager) + public AudioEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProcessFactory processFactory) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager, processFactory) { } @@ -116,5 +114,6 @@ namespace MediaBrowser.MediaEncoding.Encoder { get { return false; } } + } } diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index f43f01871..b8087fded 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -11,15 +11,12 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Globalization; using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; -using MediaBrowser.Model.IO; +using MediaBrowser.Model.Diagnostics; using MediaBrowser.Model.Dlna; namespace MediaBrowser.MediaEncoding.Encoder @@ -35,6 +32,7 @@ namespace MediaBrowser.MediaEncoding.Encoder protected readonly ISessionManager SessionManager; protected readonly ISubtitleEncoder SubtitleEncoder; protected readonly IMediaSourceManager MediaSourceManager; + protected IProcessFactory ProcessFactory; protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); @@ -46,7 +44,7 @@ namespace MediaBrowser.MediaEncoding.Encoder ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, - IMediaSourceManager mediaSourceManager) + IMediaSourceManager mediaSourceManager, IProcessFactory processFactory) { MediaEncoder = mediaEncoder; Logger = logger; @@ -57,6 +55,7 @@ namespace MediaBrowser.MediaEncoding.Encoder SessionManager = sessionManager; SubtitleEncoder = subtitleEncoder; MediaSourceManager = mediaSourceManager; + ProcessFactory = processFactory; } public async Task Start(EncodingJobOptions options, @@ -75,27 +74,23 @@ namespace MediaBrowser.MediaEncoding.Encoder var commandLineArgs = await GetCommandLineArguments(encodingJob).ConfigureAwait(false); - var process = new Process + var process = ProcessFactory.Create(new ProcessOptions { - StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, - - // Must consume both stdout and stderr or deadlocks may occur - //RedirectStandardOutput = true, - RedirectStandardError = true, - RedirectStandardInput = true, + CreateNoWindow = true, + UseShellExecute = false, - FileName = MediaEncoder.EncoderPath, - Arguments = commandLineArgs, + // Must consume both stdout and stderr or deadlocks may occur + //RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - }, + FileName = MediaEncoder.EncoderPath, + Arguments = commandLineArgs, + IsHidden = true, + ErrorDialog = false, EnableRaisingEvents = true - }; + }); var workingDirectory = GetWorkingDirectory(options); if (!string.IsNullOrWhiteSpace(workingDirectory)) @@ -149,7 +144,7 @@ namespace MediaBrowser.MediaEncoding.Encoder return encodingJob; } - private void Cancel(Process process, EncodingJob job) + private void Cancel(IProcess process, EncodingJob job) { Logger.Info("Killing ffmpeg process for {0}", job.OutputFilePath); @@ -164,7 +159,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// The process. /// The job. - private void OnFfMpegProcessExited(Process process, EncodingJob job) + private void OnFfMpegProcessExited(IProcess process, EncodingJob job) { job.HasExited = true; diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index a78d6cfd6..20b5eb05d 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using MediaBrowser.Model.Diagnostics; using MediaBrowser.Model.Logging; namespace MediaBrowser.MediaEncoding.Encoder @@ -8,10 +9,12 @@ namespace MediaBrowser.MediaEncoding.Encoder public class EncoderValidator { private readonly ILogger _logger; + private readonly IProcessFactory _processFactory; - public EncoderValidator(ILogger logger) + public EncoderValidator(ILogger logger, IProcessFactory processFactory) { _logger = logger; + _processFactory = processFactory; } public Tuple, List> Validate(string encoderPath) @@ -145,19 +148,16 @@ namespace MediaBrowser.MediaEncoding.Encoder private string GetProcessOutput(string path, string arguments) { - var process = new Process + var process = _processFactory.Create(new ProcessOptions { - StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, - FileName = path, - Arguments = arguments, - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false, - RedirectStandardOutput = true - } - }; + CreateNoWindow = true, + UseShellExecute = false, + FileName = path, + Arguments = arguments, + IsHidden = true, + ErrorDialog = false, + RedirectStandardOutput = true + }); _logger.Info("Running {0} {1}", path, arguments); diff --git a/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs b/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs index 7f4e7909a..42048ab9e 100644 --- a/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs +++ b/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs @@ -88,9 +88,9 @@ namespace MediaBrowser.MediaEncoding.Encoder /// Task. private async Task DownloadFontFile(string fontsDirectory, string fontFilename, IProgress progress) { - var existingFile = Directory - .EnumerateFiles(_appPaths.ProgramDataPath, fontFilename, SearchOption.AllDirectories) - .FirstOrDefault(); + var existingFile = _fileSystem + .GetFilePaths(_appPaths.ProgramDataPath, true) + .FirstOrDefault(i => string.Equals(fontFilename, Path.GetFileName(i), StringComparison.OrdinalIgnoreCase)); if (existingFile != null) { diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index bf6ff7655..d9571f8e5 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -14,19 +14,16 @@ using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.IO; using MediaBrowser.Model.Configuration; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; -using MediaBrowser.Controller.IO; +using MediaBrowser.Model.Diagnostics; namespace MediaBrowser.MediaEncoding.Encoder { @@ -81,14 +78,19 @@ namespace MediaBrowser.MediaEncoding.Encoder protected readonly Func MediaSourceManager; private readonly IHttpClient _httpClient; private readonly IZipClient _zipClient; + private readonly IProcessFactory _processFactory; private readonly IMemoryStreamProvider _memoryStreamProvider; private readonly List _runningProcesses = new List(); private readonly bool _hasExternalEncoder; - private string _originalFFMpegPath; - private string _originalFFProbePath; - - public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func subtitleEncoder, Func mediaSourceManager, IHttpClient httpClient, IZipClient zipClient, IMemoryStreamProvider memoryStreamProvider) + private readonly string _originalFFMpegPath; + private readonly string _originalFFProbePath; + private readonly int DefaultImageExtractionTimeoutMs; + private readonly bool EnableEncoderFontFile; + + public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func subtitleEncoder, Func mediaSourceManager, IHttpClient httpClient, IZipClient zipClient, IMemoryStreamProvider memoryStreamProvider, IProcessFactory processFactory, + int defaultImageExtractionTimeoutMs, + bool enableEncoderFontFile) { _logger = logger; _jsonSerializer = jsonSerializer; @@ -104,6 +106,9 @@ namespace MediaBrowser.MediaEncoding.Encoder _httpClient = httpClient; _zipClient = zipClient; _memoryStreamProvider = memoryStreamProvider; + _processFactory = processFactory; + DefaultImageExtractionTimeoutMs = defaultImageExtractionTimeoutMs; + EnableEncoderFontFile = enableEncoderFontFile; FFProbePath = ffProbePath; FFMpegPath = ffMpegPath; _originalFFProbePath = ffProbePath; @@ -158,12 +163,12 @@ namespace MediaBrowser.MediaEncoding.Encoder if (!string.IsNullOrWhiteSpace(FFMpegPath)) { - var result = new EncoderValidator(_logger).Validate(FFMpegPath); + var result = new EncoderValidator(_logger, _processFactory).Validate(FFMpegPath); SetAvailableDecoders(result.Item1); SetAvailableEncoders(result.Item2); - if (Environment.OSVersion.Platform == PlatformID.Win32NT) + if (EnableEncoderFontFile) { var directory = Path.GetDirectoryName(FFMpegPath); @@ -255,7 +260,7 @@ namespace MediaBrowser.MediaEncoding.Encoder private bool ValidateVersion(string path, bool logOutput) { - return new EncoderValidator(_logger).ValidateVersion(path, logOutput); + return new EncoderValidator(_logger, _processFactory).ValidateVersion(path, logOutput); } private void ConfigureEncoderPaths() @@ -509,27 +514,22 @@ namespace MediaBrowser.MediaEncoding.Encoder ? "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_chapters -show_format" : "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_format"; - var process = new Process + var process = _processFactory.Create(new ProcessOptions { - StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, - - // Must consume both or ffmpeg may hang due to deadlocks. See comments below. - RedirectStandardOutput = true, - //RedirectStandardError = true, - RedirectStandardInput = false, - FileName = FFProbePath, - Arguments = string.Format(args, - probeSizeArgument, inputPath).Trim(), - - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - }, - + CreateNoWindow = true, + UseShellExecute = false, + + // Must consume both or ffmpeg may hang due to deadlocks. See comments below. + RedirectStandardOutput = true, + //RedirectStandardError = true, + RedirectStandardInput = false, + FileName = FFProbePath, + Arguments = string.Format(args, probeSizeArgument, inputPath).Trim(), + + IsHidden = true, + ErrorDialog = false, EnableRaisingEvents = true - }; + }); _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); @@ -644,26 +644,22 @@ namespace MediaBrowser.MediaEncoding.Encoder var args = "{0} -i {1} -map 0:v:{2} -an -filter:v idet -frames:v 500 -an -f null /dev/null"; - var process = new Process + var process = _processFactory.Create(new ProcessOptions { - StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, - - // Must consume both or ffmpeg may hang due to deadlocks. See comments below. - //RedirectStandardOutput = true, - RedirectStandardError = true, - RedirectStandardInput = false, - FileName = FFMpegPath, - Arguments = string.Format(args, probeSizeArgument, inputPath, videoStream.Index.ToString(CultureInfo.InvariantCulture)).Trim(), - - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - }, - + CreateNoWindow = true, + UseShellExecute = false, + + // Must consume both or ffmpeg may hang due to deadlocks. See comments below. + //RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = false, + FileName = FFMpegPath, + Arguments = string.Format(args, probeSizeArgument, inputPath, videoStream.Index.ToString(CultureInfo.InvariantCulture)).Trim(), + + IsHidden = true, + ErrorDialog = false, EnableRaisingEvents = true - }; + }); _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); var idetFoundInterlaced = false; @@ -916,18 +912,15 @@ namespace MediaBrowser.MediaEncoding.Encoder args = string.Format("-ss {0} ", GetTimeParameter(offset.Value)) + args; } - var process = new Process + var process = _processFactory.Create(new ProcessOptions { - StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, - FileName = FFMpegPath, - Arguments = args, - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - } - }; + CreateNoWindow = true, + UseShellExecute = false, + FileName = FFMpegPath, + Arguments = args, + IsHidden = true, + ErrorDialog = false + }); _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); @@ -944,7 +937,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var timeoutMs = ConfigurationManager.Configuration.ImageExtractionTimeoutMs; if (timeoutMs <= 0) { - timeoutMs = Environment.Is64BitOperatingSystem ? (Environment.ProcessorCount > 2 ? 14000 : 20000) : 40000; + timeoutMs = DefaultImageExtractionTimeoutMs; } ranToCompletion = process.WaitForExit(timeoutMs); @@ -1022,19 +1015,16 @@ namespace MediaBrowser.MediaEncoding.Encoder args = probeSize + " " + args; } - var process = new Process + var process = _processFactory.Create(new ProcessOptions { - StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, - FileName = FFMpegPath, - Arguments = args, - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false, - RedirectStandardInput = true - } - }; + CreateNoWindow = true, + UseShellExecute = false, + FileName = FFMpegPath, + Arguments = args, + IsHidden = true, + ErrorDialog = false, + RedirectStandardInput = true + }); _logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments); @@ -1107,7 +1097,8 @@ namespace MediaBrowser.MediaEncoding.Encoder LibraryManager, SessionManager, SubtitleEncoder(), - MediaSourceManager()) + MediaSourceManager(), + _processFactory) .Start(options, progress, cancellationToken).ConfigureAwait(false); await job.TaskCompletionSource.Task.ConfigureAwait(false); @@ -1127,7 +1118,8 @@ namespace MediaBrowser.MediaEncoding.Encoder LibraryManager, SessionManager, SubtitleEncoder(), - MediaSourceManager()) + MediaSourceManager(), + _processFactory) .Start(options, progress, cancellationToken).ConfigureAwait(false); await job.TaskCompletionSource.Task.ConfigureAwait(false); @@ -1231,14 +1223,14 @@ namespace MediaBrowser.MediaEncoding.Encoder private class ProcessWrapper : IDisposable { - public readonly Process Process; + public readonly IProcess Process; public bool HasExited; public int? ExitCode; private readonly MediaEncoder _mediaEncoder; private readonly ILogger _logger; public bool IsRedirectingStdin { get; private set; } - public ProcessWrapper(Process process, MediaEncoder mediaEncoder, ILogger logger, bool isRedirectingStdin) + public ProcessWrapper(IProcess process, MediaEncoder mediaEncoder, ILogger logger, bool isRedirectingStdin) { Process = process; _mediaEncoder = mediaEncoder; @@ -1249,7 +1241,7 @@ namespace MediaBrowser.MediaEncoding.Encoder void Process_Exited(object sender, EventArgs e) { - var process = (Process)sender; + var process = (IProcess)sender; HasExited = true; @@ -1269,7 +1261,7 @@ namespace MediaBrowser.MediaEncoding.Encoder DisposeProcess(process); } - private void DisposeProcess(Process process) + private void DisposeProcess(IProcess process) { try { diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs index 73f82b61c..cbbca479a 100644 --- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs @@ -8,15 +8,13 @@ using MediaBrowser.Model.Logging; using System; using System.IO; using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; -using MediaBrowser.Model.IO; +using MediaBrowser.Model.Diagnostics; namespace MediaBrowser.MediaEncoding.Encoder { public class VideoEncoder : BaseEncoder { - public VideoEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager) + public VideoEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProcessFactory processFactory) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager, processFactory) { } @@ -193,5 +191,6 @@ namespace MediaBrowser.MediaEncoding.Encoder { get { return true; } } + } } \ No newline at end of file diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 89e0b61c1..63e789a59 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -9,10 +9,10 @@ Properties MediaBrowser.MediaEncoding MediaBrowser.MediaEncoding - v4.6 512 - ..\ - + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 true @@ -37,13 +37,6 @@ 4 - - - - - - - ..\packages\UniversalDetector.1.0.1\lib\portable-net45+sl4+wp71+win8+wpa81\UniversalDetector.dll True @@ -108,7 +101,7 @@ - +