make api project portable

This commit is contained in:
Luke Pulverenti 2016-10-31 23:07:45 -04:00
parent b28857feea
commit 13d8110ce2
35 changed files with 326 additions and 255 deletions

View File

@ -577,6 +577,23 @@ namespace Emby.Common.Implementations.IO
Directory.CreateDirectory(path);
}
public List<FileSystemMetadata> 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<FileSystemMetadata> GetDirectories(string path, bool recursive = false)
{
var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;

View File

@ -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",

View File

@ -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;
/// <summary>
/// The active transcoding jobs
@ -63,13 +66,15 @@ namespace MediaBrowser.Api
/// <param name="config">The configuration.</param>
/// <param name="fileSystem">The file system.</param>
/// <param name="mediaSourceManager">The media source manager.</param>
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.
/// </summary>
/// <value>The process.</value>
public Process Process { get; set; }
public IProcess Process { get; set; }
public ILogger Logger { get; private set; }
/// <summary>
/// Gets or sets the active request count.
@ -717,7 +715,9 @@ namespace MediaBrowser.Api
/// Gets or sets the kill timer.
/// </summary>
/// <value>The kill timer.</value>
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<object> callback)
{
StartKillTimer(callback, PingTimeout);
}
public void StartKillTimer(TimerCallback callback, int intervalMs)
public void StartKillTimer(Action<object> 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
{

View File

@ -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
/// <summary>
/// The _active connections
/// </summary>
protected readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim>> ActiveConnections =
new List<Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim>>();
protected readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim>> ActiveConnections =
new List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim>>();
/// <summary>
/// Gets the name.
@ -43,12 +44,9 @@ namespace MediaBrowser.Api
/// </summary>
protected ILogger Logger;
/// <summary>
/// Initializes a new instance of the <see cref="BasePeriodicWebSocketListener{TStateType}" /> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <exception cref="System.ArgumentNullException">logger</exception>
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;
}
/// <summary>
@ -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<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim>(message.Connection, cancellationTokenSource, timer, state, semaphore));
ActiveConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim>(message.Connection, cancellationTokenSource, timer, state, semaphore));
}
if (timer != null)
@ -154,7 +153,7 @@ namespace MediaBrowser.Api
{
var connection = (IWebSocketConnection)state;
Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim> tuple;
Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim> tuple;
lock (ActiveConnections)
{
@ -177,7 +176,7 @@ namespace MediaBrowser.Api
protected void SendData(bool force)
{
List<Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim>> tuples;
List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim>> tuples;
lock (ActiveConnections)
{
@ -205,7 +204,7 @@ namespace MediaBrowser.Api
}
}
private async void SendData(Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim> tuple)
private async void SendData(Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim> tuple)
{
var connection = tuple.Item1;
@ -266,7 +265,7 @@ namespace MediaBrowser.Api
/// Disposes the connection.
/// </summary>
/// <param name="connection">The connection.</param>
private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim> connection)
private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim> connection)
{
Logger.Debug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name);

View File

@ -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 = "\\";
/// <summary>
/// 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
/// <returns>IEnumerable{FileSystemEntryInfo}.</returns>
private IEnumerable<FileSystemEntryInfo> 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);
}
/// <summary>
/// Gets the name.
/// </summary>
/// <param name="drive">The drive.</param>
/// <returns>System.String.</returns>
private string GetName(DriveInfo drive)
{
return drive.Name;
}
/// <summary>
/// Gets the network shares.
/// </summary>

View File

@ -150,7 +150,7 @@ namespace MediaBrowser.Api.Images
.OrderBy(i => i.Name)
.ToList();
}
catch (DirectoryNotFoundException)
catch (IOException)
{
return new List<ImageByNameInfo>();
}

View File

@ -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);

View File

@ -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);
}
/// <summary>

View File

@ -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);
}
/// <summary>

View File

@ -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);
});
}
}
}
}

View File

@ -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))

View File

@ -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<object> 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<object> 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<string, string>(StringComparer.OrdinalIgnoreCase);
outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType("file." + request.Container);

View File

@ -11,10 +11,9 @@
<AssemblyName>MediaBrowser.Api</AssemblyName>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<ReleaseVersion>
</ReleaseVersion>
<TargetFrameworkProfile />
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -45,13 +44,6 @@
<PropertyGroup>
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
@ -183,12 +175,8 @@
<Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
<Name>MediaBrowser.Model</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj">
<Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project>
<Name>MediaBrowser.Server.Implementations</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="EmitMSBuildWarning" BeforeTargets="Build">
<Warning Text="Packages containing MSBuild targets and props files cannot be fully installed in projects targeting multiple frameworks. The MSBuild targets and props files have been ignored." />
</Target>
</Project>

View File

@ -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
/// <param name="process">The process.</param>
/// <param name="job">The job.</param>
/// <param name="state">The state.</param>
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<string, string>();
//var dict = new Dictionary<string, string>();
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);
}
/// <summary>

View File

@ -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;

View File

@ -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<object> 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);

View File

@ -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;

View File

@ -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
/// <summary>
/// Initializes a new instance of the <see cref="ScheduledTasksWebSocketListener" /> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="taskManager">The task manager.</param>
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);
}
}

View File

@ -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
/// <summary>
/// Initializes a new instance of the <see cref="SessionInfoWebSocketListener"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="sessionManager">The session manager.</param>
public SessionInfoWebSocketListener(ILogger logger, ISessionManager sessionManager)
: base(logger)
public SessionInfoWebSocketListener(ILogger logger, ISessionManager sessionManager, ITimerFactory timerFactory)
: base(logger, timerFactory)
{
_sessionManager = sessionManager;

View File

@ -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;

View File

@ -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;

View File

@ -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
/// </summary>
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;

View File

@ -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
/// <summary>
/// Initializes a new instance of the <see cref="SystemInfoWebSocketListener" /> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="appHost">The app host.</param>
public SystemInfoWebSocketListener(ILogger logger, IServerApplicationHost appHost)
: base(logger)
public SystemInfoWebSocketListener(ILogger logger, IServerApplicationHost appHost, ITimerFactory timerFactory)
: base(logger, timerFactory)
{
_appHost = appHost;
}

View File

@ -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<FileSystemMetadata>();
}

View File

@ -0,0 +1,17 @@
{
"frameworks":{
"netstandard1.6":{
"dependencies":{
"NETStandard.Library":"1.6.0",
}
},
".NETPortable,Version=v4.5,Profile=Profile7":{
"buildOptions": {
"define": [ ]
},
"frameworkAssemblies":{
}
}
}
}

View File

@ -393,5 +393,8 @@ namespace MediaBrowser.Controller.LiveTv
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
string GetEmbyTvActiveRecordingPath(string id);
Task<LiveStream> GetEmbyTvLiveStream(string id);
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -305,6 +305,8 @@ namespace MediaBrowser.Model.IO
char DirectorySeparatorChar { get; }
string GetFullPath(string path);
List<FileSystemMetadata> GetDrives();
}
public enum FileOpenMode

View File

@ -106,6 +106,8 @@
<Compile Include="Devices\LocalFileInfo.cs" />
<Compile Include="Devices\DeviceInfo.cs" />
<Compile Include="Devices\DevicesOptions.cs" />
<Compile Include="Diagnostics\IProcess.cs" />
<Compile Include="Diagnostics\IProcessFactory.cs" />
<Compile Include="Dlna\CodecProfile.cs" />
<Compile Include="Dlna\ContainerProfile.cs" />
<Compile Include="Dlna\DeviceProfile.cs" />
@ -422,6 +424,8 @@
<Compile Include="Tasks\ScheduledTaskHelpers.cs" />
<Compile Include="Tasks\TaskCompletionEventArgs.cs" />
<Compile Include="Tasks\TaskExecutionOptions.cs" />
<Compile Include="Threading\ITimer.cs" />
<Compile Include="Threading\ITimerFactory.cs" />
<Compile Include="Updates\CheckForUpdateResult.cs" />
<Compile Include="Updates\PackageTargetSystem.cs" />
<Compile Include="Updates\InstallationInfo.cs" />

View File

@ -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);
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace MediaBrowser.Model.Threading
{
public interface ITimerFactory
{
ITimer Create(Action<object> callback, object state, TimeSpan dueTime, TimeSpan period);
ITimer Create(Action<object> callback, object state, int dueTimeMs, int periodMs);
}
}

View File

@ -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;
}

View File

@ -75,6 +75,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
public event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
public string GetEmbyTvActiveRecordingPath(string id)
{
return EmbyTV.EmbyTV.Current.GetActiveRecordingPath(id);
}
public Task<LiveStream> 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;