diff --git a/Emby.Common.Implementations/IO/ManagedFileSystem.cs b/Emby.Common.Implementations/IO/ManagedFileSystem.cs index bfc316d3f0..a8aa1a3cdf 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 4cb5213ba3..444d0e13ec 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 588236a399..8f5b5eaaf3 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 b650cd4c2d..fe7de387f8 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 c05446fbb8..bab538c91f 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 12ac8f68f0..e0a9246c10 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 dba90d2730..c41907a878 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 f6c9c9767b..eb871746d7 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 bdb9133d34..1700a10cd3 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 35948b453e..ea610ac5c1 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 18afcd51e6..c3bb80dcb5 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 83785466cd..fffd7ad7ef 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 fdfbaae0f0..df491ce855 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 0000000000..e69ce0e64f --- /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 ba3b3e348d..c628892149 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 outputAudio = GetAudioEncoder(state); + //if (!string.IsNullOrWhiteSpace(outputAudio)) + //{ + // dict["outputAudio"] = outputAudio; + //} - var outputVideo = GetVideoEncoder(state); - if (!string.IsNullOrWhiteSpace(outputVideo)) - { - dict["outputVideo"] = outputVideo; - } + //var outputVideo = GetVideoEncoder(state); + //if (!string.IsNullOrWhiteSpace(outputVideo)) + //{ + // dict["outputVideo"] = outputVideo; + //} - if (ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputAudio ?? string.Empty, StringComparer.OrdinalIgnoreCase) && - ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputVideo ?? string.Empty, StringComparer.OrdinalIgnoreCase)) - { - return Task.FromResult(true); - } + //if (ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputAudio ?? string.Empty, StringComparer.OrdinalIgnoreCase) && + // ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputVideo ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + //{ + // return Task.FromResult(true); + //} - dict["id"] = AppHost.SystemId; - dict["type"] = state.VideoRequest == null ? "Audio" : "Video"; + //dict["id"] = AppHost.SystemId; + //dict["type"] = state.VideoRequest == null ? "Audio" : "Video"; - var audioStream = state.AudioStream; - if (audioStream != null && !string.IsNullOrWhiteSpace(audioStream.Codec)) - { - dict["inputAudio"] = audioStream.Codec; - } + //var audioStream = state.AudioStream; + //if (audioStream != null && !string.IsNullOrWhiteSpace(audioStream.Codec)) + //{ + // dict["inputAudio"] = audioStream.Codec; + //} - var videoStream = state.VideoStream; - if (videoStream != null && !string.IsNullOrWhiteSpace(videoStream.Codec)) - { - dict["inputVideo"] = videoStream.Codec; - } + //var videoStream = state.VideoStream; + //if (videoStream != null && !string.IsNullOrWhiteSpace(videoStream.Codec)) + //{ + // dict["inputVideo"] = videoStream.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 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); + //} - if (state.SupportedAudioCodecs.Count > 0) - { - dict["supportedAudioCodecs"] = string.Join(",", state.SupportedAudioCodecs.ToArray()); - } + //if (state.SupportedAudioCodecs.Count > 0) + //{ + // dict["supportedAudioCodecs"] = string.Join(",", state.SupportedAudioCodecs.ToArray()); + //} - var auth = AuthorizationContext.GetAuthorizationInfo(Request); + //var auth = AuthorizationContext.GetAuthorizationInfo(Request); - 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"; + //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"; - //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(); - } + ////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(); + //} - if (!ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputVideo ?? string.Empty, StringComparer.OrdinalIgnoreCase)) - { - var list = ServerConfigurationManager.Configuration.CodecsUsed.ToList(); - list.Add(outputVideo); - ServerConfigurationManager.Configuration.CodecsUsed = list.ToArray(); - } + //if (!ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputVideo ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + //{ + // var list = ServerConfigurationManager.Configuration.CodecsUsed.ToList(); + // list.Add(outputVideo); + // ServerConfigurationManager.Configuration.CodecsUsed = list.ToArray(); + //} - ServerConfigurationManager.SaveConfiguration(); + //ServerConfigurationManager.SaveConfiguration(); - //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"; + ////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); + //return HttpClient.Post(options); } /// diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 07ace5c2c2..353e832057 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 4519268fcf..65c1af79e3 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 a7d53cd447..c42d0c3e4c 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 6e64345b9f..ee74ec450c 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 8f68569b7a..b90a718529 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 61a26d160a..ac9749a6dc 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 906a52209a..5f9d1ff0ee 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 aaf9a33479..c641695dd8 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 a53bfac276..8d74cc66c0 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 d67c1b47f4..bdae670e15 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 0000000000..fbbe9eaf32 --- /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 8e3c1931b1..08e4956adc 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 0000000000..ab0b0cfcff --- /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 0000000000..998bbcd28d --- /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 4f920c3b03..50e32572da 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 a1b478496c..5999f02db2 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 0000000000..42090250bf --- /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 0000000000..5f3df1738d --- /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 fccb298b1a..9dff243c1e 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 894ab5e58a..93fc5459a1 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;