make api project portable

pull/702/head
Luke Pulverenti 8 years ago
parent b28857feea
commit 13d8110ce2

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save