aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Reed <ebr@mediabrowser3.com>2013-09-25 14:32:36 -0400
committerEric Reed <ebr@mediabrowser3.com>2013-09-25 14:32:36 -0400
commitc02c0db35af078e1a78897aecdade2efe57d3f06 (patch)
treeaf9ef64305efd2e353a202c27b188d2c44cd9b5b
parentc6e57c6448c04998bcae5a906e7a064300542e75 (diff)
parent2d9b48d00fd31aaa96676c82a054b2794493fbf9 (diff)
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
-rw-r--r--CONTRIBUTORS.md1
-rw-r--r--MediaBrowser.Api/ApiEntryPoint.cs50
-rw-r--r--MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs181
-rw-r--r--MediaBrowser.Api/BaseApiService.cs147
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj41
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs2
-rw-r--r--MediaBrowser.Api/Playback/Hls/AudioHlsService.cs36
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs24
-rw-r--r--MediaBrowser.Api/Playback/Hls/HlsSegmentResponseFilter.cs53
-rw-r--r--MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs147
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs67
-rw-r--r--MediaBrowser.Api/SessionsService.cs258
-rw-r--r--MediaBrowser.Api/UserLibrary/UserLibraryService.cs60
-rw-r--r--MediaBrowser.Common.Implementations/Archiving/ZipClient.cs87
-rw-r--r--MediaBrowser.Common.Implementations/BaseApplicationHost.cs59
-rw-r--r--MediaBrowser.Common.Implementations/Logging/NlogManager.cs18
-rw-r--r--MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj29
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs15
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs37
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs6
-rw-r--r--MediaBrowser.Common.Implementations/packages.config1
-rw-r--r--MediaBrowser.Common/MediaBrowser.Common.csproj23
-rw-r--r--MediaBrowser.Common/ScheduledTasks/ITaskManager.cs7
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs29
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj18
-rw-r--r--MediaBrowser.Controller/Providers/BaseMetadataProvider.cs2
-rw-r--r--MediaBrowser.Controller/Session/ISessionManager.cs60
-rw-r--r--MediaBrowser.Controller/Session/ISessionRemoteController.cs61
-rw-r--r--MediaBrowser.Controller/Session/PlaybackInfo.cs38
-rw-r--r--MediaBrowser.Controller/Session/SessionInfo.cs19
-rw-r--r--MediaBrowser.Model/ApiClient/IApiClient.cs4
-rw-r--r--MediaBrowser.Model/IO/IZipClient.cs16
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj11
-rw-r--r--MediaBrowser.Model/Session/SessionInfoDto.cs17
-rw-r--r--MediaBrowser.Mono.sln68
-rw-r--r--MediaBrowser.Mono.userprefs19
-rw-r--r--MediaBrowser.Providers/MediaBrowser.Providers.csproj15
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfoProvider.cs1
-rw-r--r--MediaBrowser.Providers/Movies/FanArtMovieProvider.cs1
-rw-r--r--MediaBrowser.Providers/Music/SoundtrackPostScanTask.cs4
-rw-r--r--MediaBrowser.Providers/Savers/AlbumXmlSaver.cs5
-rw-r--r--MediaBrowser.Providers/Savers/ArtistXmlSaver.cs5
-rw-r--r--MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs5
-rw-r--r--MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs5
-rw-r--r--MediaBrowser.Providers/Savers/FolderXmlSaver.cs3
-rw-r--r--MediaBrowser.Providers/Savers/GameXmlSaver.cs7
-rw-r--r--MediaBrowser.Providers/Savers/MovieXmlSaver.cs5
-rw-r--r--MediaBrowser.Providers/Savers/PersonXmlSaver.cs5
-rw-r--r--MediaBrowser.Providers/Savers/SeasonXmlSaver.cs3
-rw-r--r--MediaBrowser.Providers/Savers/SeriesXmlSaver.cs10
-rw-r--r--MediaBrowser.Providers/Savers/XmlSaverHelpers.cs53
-rw-r--r--MediaBrowser.Providers/TV/SeriesPostScanTask.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs94
-rw-r--r--MediaBrowser.Server.Implementations/Dto/DtoService.cs4
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs (renamed from MediaBrowser.ServerApplication/EntryPoints/UdpServerEntryPoint.cs)6
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs15
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs54
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs6
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs10
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs10
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs8
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj86
-rw-r--r--MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs15
-rw-r--r--MediaBrowser.Server.Implementations/Providers/ImageSaver.cs12
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs151
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs52
-rw-r--r--MediaBrowser.Server.Implementations/Session/WebSocketController.cs92
-rw-r--r--MediaBrowser.Server.Implementations/WebSocket/AlchemyWebSocket.cs4
-rw-r--r--MediaBrowser.Server.Mono/FFMpeg/FFMpegDownloader.cs36
-rw-r--r--MediaBrowser.Server.Mono/MainWindow.cs16
-rw-r--r--MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj119
-rw-r--r--MediaBrowser.Server.Mono/Native/Assemblies.cs22
-rw-r--r--MediaBrowser.Server.Mono/Native/Autorun.cs20
-rw-r--r--MediaBrowser.Server.Mono/Native/HttpMessageHandlerFactory.cs25
-rw-r--r--MediaBrowser.Server.Mono/Native/NativeApp.cs25
-rw-r--r--MediaBrowser.Server.Mono/Native/ServerAuthorization.cs26
-rw-r--r--MediaBrowser.Server.Mono/Native/Sqlite.cs36
-rw-r--r--MediaBrowser.Server.Mono/Program.cs16
-rw-r--r--MediaBrowser.Server.Mono/Properties/AssemblyInfo.cs22
-rw-r--r--MediaBrowser.Server.Mono/gtk-gui/MainWindow.cs20
-rw-r--r--MediaBrowser.Server.Mono/gtk-gui/generated.cs29
-rw-r--r--MediaBrowser.Server.Mono/gtk-gui/gui.stetic20
-rw-r--r--MediaBrowser.ServerApplication/App.xaml.cs53
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs143
-rw-r--r--MediaBrowser.ServerApplication/EntryPoints/StartupWizard.cs14
-rw-r--r--MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs302
-rw-r--r--MediaBrowser.ServerApplication/FFMpeg/FFMpegInfo.cs24
-rw-r--r--MediaBrowser.ServerApplication/FFMpeg/ffmpeg-20130904-git-f974289-win32-static.7z.REMOVED.git-id1
-rw-r--r--MediaBrowser.ServerApplication/Implementations/DotNetZipClient.cs43
-rw-r--r--MediaBrowser.ServerApplication/Implementations/FFMpegDownloader.cs205
-rw-r--r--MediaBrowser.ServerApplication/Implementations/ffmpeg20130904.zip.REMOVED.git-id1
-rw-r--r--MediaBrowser.ServerApplication/Implementations/readme.txt5
-rw-r--r--MediaBrowser.ServerApplication/MainStartup.cs1
-rw-r--r--MediaBrowser.ServerApplication/MainWindow.xaml.cs17
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj25
-rw-r--r--MediaBrowser.ServerApplication/Native/Assemblies.cs25
-rw-r--r--MediaBrowser.ServerApplication/Native/Autorun.cs31
-rw-r--r--MediaBrowser.ServerApplication/Native/BrowserLauncher.cs68
-rw-r--r--MediaBrowser.ServerApplication/Native/HttpMessageHandlerFactory.cs26
-rw-r--r--MediaBrowser.ServerApplication/Native/NativeApp.cs25
-rw-r--r--MediaBrowser.ServerApplication/Native/RegisterServer.bat (renamed from MediaBrowser.ServerApplication/RegisterServer.bat)0
-rw-r--r--MediaBrowser.ServerApplication/Native/ServerAuthorization.cs56
-rw-r--r--MediaBrowser.ServerApplication/Native/Sqlite.cs36
-rw-r--r--MediaBrowser.ServerApplication/Resources/Images/mb3logo800.pngbin35600 -> 28816 bytes
-rw-r--r--MediaBrowser.ServerApplication/packages.config1
-rw-r--r--MediaBrowser.WebDashboard/ApiClient.js15
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj33
-rw-r--r--MediaBrowser.WebDashboard/packages.config2
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec4
-rw-r--r--Nuget/MediaBrowser.Common.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec4
114 files changed, 2729 insertions, 1336 deletions
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index ee6870271..18cef5819 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -57,3 +57,4 @@
- [Detector1](https://github.com/Detector1)
- [BlackIce013](https://github.com/blackice013)
- [mporcas] (https://github.com/mporcas)
+ - [tikuf] (https://github.com/tikuf/)
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index 52707c3c6..8754e57a1 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -62,7 +62,7 @@ namespace MediaBrowser.Api
{
var jobCount = _activeTranscodingJobs.Count;
- Parallel.ForEach(_activeTranscodingJobs, OnTranscodeKillTimerStopped);
+ Parallel.ForEach(_activeTranscodingJobs, KillTranscodingJob);
// Try to allow for some time to kill the ffmpeg processes and delete the partial stream files
if (jobCount > 0)
@@ -84,7 +84,8 @@ namespace MediaBrowser.Api
/// <param name="process">The process.</param>
/// <param name="isVideo">if set to <c>true</c> [is video].</param>
/// <param name="startTimeTicks">The start time ticks.</param>
- public void OnTranscodeBeginning(string path, TranscodingJobType type, Process process, bool isVideo, long? startTimeTicks)
+ /// <param name="sourcePath">The source path.</param>
+ public void OnTranscodeBeginning(string path, TranscodingJobType type, Process process, bool isVideo, long? startTimeTicks, string sourcePath)
{
lock (_activeTranscodingJobs)
{
@@ -95,7 +96,8 @@ namespace MediaBrowser.Api
Process = process,
ActiveRequestCount = 1,
IsVideo = isVideo,
- StartTimeTicks = startTimeTicks
+ StartTimeTicks = startTimeTicks,
+ SourcePath = sourcePath
});
}
}
@@ -178,7 +180,7 @@ namespace MediaBrowser.Api
if (job.ActiveRequestCount == 0)
{
- var timerDuration = type == TranscodingJobType.Progressive ? 1000 : 60000;
+ var timerDuration = type == TranscodingJobType.Progressive ? 1000 : 180000;
if (job.KillTimer == null)
{
@@ -196,10 +198,47 @@ namespace MediaBrowser.Api
/// Called when [transcode kill timer stopped].
/// </summary>
/// <param name="state">The state.</param>
- private async void OnTranscodeKillTimerStopped(object state)
+ private void OnTranscodeKillTimerStopped(object state)
{
var job = (TranscodingJob)state;
+ KillTranscodingJob(job);
+ }
+
+ /// <summary>
+ /// Kills the single transcoding job.
+ /// </summary>
+ /// <param name="sourcePath">The source path.</param>
+ internal void KillSingleTranscodingJob(string sourcePath)
+ {
+ if (string.IsNullOrEmpty(sourcePath))
+ {
+ throw new ArgumentNullException("sourcePath");
+ }
+
+ var jobs = new List<TranscodingJob>();
+
+ lock (_activeTranscodingJobs)
+ {
+ // This is really only needed for HLS.
+ // Progressive streams can stop on their own reliably
+ jobs.AddRange(_activeTranscodingJobs.Where(i => string.Equals(sourcePath, i.SourcePath) && i.Type == TranscodingJobType.Hls));
+ }
+
+ // This method of killing is a bit of a shortcut, but it saves clients from having to send a request just for that
+ // But we can only kill if there's one active job. If there are more we won't know which one to stop
+ if (jobs.Count == 1)
+ {
+ KillTranscodingJob(jobs.First());
+ }
+ }
+
+ /// <summary>
+ /// Kills the transcoding job.
+ /// </summary>
+ /// <param name="job">The job.</param>
+ private async void KillTranscodingJob(TranscodingJob job)
+ {
lock (_activeTranscodingJobs)
{
_activeTranscodingJobs.Remove(job);
@@ -373,6 +412,7 @@ namespace MediaBrowser.Api
public bool IsVideo { get; set; }
public long? StartTimeTicks { get; set; }
+ public string SourcePath { get; set; }
}
/// <summary>
diff --git a/MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs b/MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs
new file mode 100644
index 000000000..d225bdd99
--- /dev/null
+++ b/MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs
@@ -0,0 +1,181 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Logging;
+using ServiceStack.Common.Web;
+using ServiceStack.ServiceHost;
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Api
+{
+ public class AuthorizationRequestFilterAttribute : Attribute, IHasRequestFilter
+ {
+ //This property will be resolved by the IoC container
+ /// <summary>
+ /// Gets or sets the user manager.
+ /// </summary>
+ /// <value>The user manager.</value>
+ public IUserManager UserManager { get; set; }
+
+ public ISessionManager SessionManager { get; set; }
+
+ /// <summary>
+ /// Gets or sets the logger.
+ /// </summary>
+ /// <value>The logger.</value>
+ public ILogger Logger { get; set; }
+
+ /// <summary>
+ /// The request filter is executed before the service.
+ /// </summary>
+ /// <param name="request">The http request wrapper</param>
+ /// <param name="response">The http response wrapper</param>
+ /// <param name="requestDto">The request DTO</param>
+ public void RequestFilter(IHttpRequest request, IHttpResponse response, object requestDto)
+ {
+ //This code is executed before the service
+
+ var auth = GetAuthorization(request);
+
+ if (auth != null)
+ {
+ User user = null;
+
+ if (auth.ContainsKey("UserId"))
+ {
+ var userId = auth["UserId"];
+
+ if (!string.IsNullOrEmpty(userId))
+ {
+ user = UserManager.GetUserById(new Guid(userId));
+ }
+ }
+
+ string deviceId;
+ string device;
+ string client;
+ string version;
+
+ auth.TryGetValue("DeviceId", out deviceId);
+ auth.TryGetValue("Device", out device);
+ auth.TryGetValue("Client", out client);
+ auth.TryGetValue("Version", out version);
+
+ if (!string.IsNullOrEmpty(client) && !string.IsNullOrEmpty(deviceId) && !string.IsNullOrEmpty(device) && !string.IsNullOrEmpty(version))
+ {
+ SessionManager.LogConnectionActivity(client, version, deviceId, device, user);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets the auth.
+ /// </summary>
+ /// <param name="httpReq">The HTTP req.</param>
+ /// <returns>Dictionary{System.StringSystem.String}.</returns>
+ public static Dictionary<string, string> GetAuthorization(IHttpRequest httpReq)
+ {
+ var auth = httpReq.Headers[HttpHeaders.Authorization];
+
+ return GetAuthorization(auth);
+ }
+
+ /// <summary>
+ /// Gets the authorization.
+ /// </summary>
+ /// <param name="httpReq">The HTTP req.</param>
+ /// <returns>Dictionary{System.StringSystem.String}.</returns>
+ public static AuthorizationInfo GetAuthorization(IRequestContext httpReq)
+ {
+ var header = httpReq.GetHeader("Authorization");
+
+ var auth = GetAuthorization(header);
+
+ string userId;
+ string deviceId;
+ string device;
+ string client;
+ string version;
+
+ auth.TryGetValue("UserId", out userId);
+ auth.TryGetValue("DeviceId", out deviceId);
+ auth.TryGetValue("Device", out device);
+ auth.TryGetValue("Client", out client);
+ auth.TryGetValue("Version", out version);
+
+ return new AuthorizationInfo
+ {
+ Client = client,
+ Device = device,
+ DeviceId = deviceId,
+ UserId = userId,
+ Version = version
+ };
+ }
+
+ /// <summary>
+ /// Gets the authorization.
+ /// </summary>
+ /// <param name="authorizationHeader">The authorization header.</param>
+ /// <returns>Dictionary{System.StringSystem.String}.</returns>
+ private static Dictionary<string, string> GetAuthorization(string authorizationHeader)
+ {
+ if (authorizationHeader == null) return null;
+
+ var parts = authorizationHeader.Split(' ');
+
+ // There should be at least to parts
+ if (parts.Length < 2) return null;
+
+ // It has to be a digest request
+ if (!string.Equals(parts[0], "MediaBrowser", StringComparison.OrdinalIgnoreCase))
+ {
+ return null;
+ }
+
+ // Remove uptil the first space
+ authorizationHeader = authorizationHeader.Substring(authorizationHeader.IndexOf(' '));
+ parts = authorizationHeader.Split(',');
+
+ var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+
+ foreach (var item in parts)
+ {
+ var param = item.Trim().Split(new[] { '=' }, 2);
+ result.Add(param[0], param[1].Trim(new[] { '"' }));
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// A new shallow copy of this filter is used on every request.
+ /// </summary>
+ /// <returns>IHasRequestFilter.</returns>
+ public IHasRequestFilter Copy()
+ {
+ return this;
+ }
+
+ /// <summary>
+ /// Order in which Request Filters are executed.
+ /// &lt;0 Executed before global request filters
+ /// &gt;0 Executed after global request filters
+ /// </summary>
+ /// <value>The priority.</value>
+ public int Priority
+ {
+ get { return 0; }
+ }
+ }
+
+ public class AuthorizationInfo
+ {
+ public string UserId;
+ public string DeviceId;
+ public string Device;
+ public string Client;
+ public string Version;
+ }
+}
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index b3f5027e0..069bc0fe1 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -2,9 +2,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Logging;
-using ServiceStack.Common.Web;
using ServiceStack.ServiceHost;
using System;
using System.Collections.Generic;
@@ -15,7 +13,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class BaseApiService
/// </summary>
- [RequestFilter]
+ [AuthorizationRequestFilter]
public class BaseApiService : IHasResultFactory, IRestfulService
{
/// <summary>
@@ -308,147 +306,4 @@ namespace MediaBrowser.Api
return item;
}
}
-
- /// <summary>
- /// Class RequestFilterAttribute
- /// </summary>
- public class RequestFilterAttribute : Attribute, IHasRequestFilter
- {
- //This property will be resolved by the IoC container
- /// <summary>
- /// Gets or sets the user manager.
- /// </summary>
- /// <value>The user manager.</value>
- public IUserManager UserManager { get; set; }
-
- public ISessionManager SessionManager { get; set; }
-
- /// <summary>
- /// Gets or sets the logger.
- /// </summary>
- /// <value>The logger.</value>
- public ILogger Logger { get; set; }
-
- /// <summary>
- /// The request filter is executed before the service.
- /// </summary>
- /// <param name="request">The http request wrapper</param>
- /// <param name="response">The http response wrapper</param>
- /// <param name="requestDto">The request DTO</param>
- public void RequestFilter(IHttpRequest request, IHttpResponse response, object requestDto)
- {
- //This code is executed before the service
-
- var auth = GetAuthorization(request);
-
- if (auth != null)
- {
- User user = null;
-
- if (auth.ContainsKey("UserId"))
- {
- var userId = auth["UserId"];
-
- if (!string.IsNullOrEmpty(userId))
- {
- user = UserManager.GetUserById(new Guid(userId));
- }
- }
-
- string deviceId;
- string device;
- string client;
- string version;
-
- auth.TryGetValue("DeviceId", out deviceId);
- auth.TryGetValue("Device", out device);
- auth.TryGetValue("Client", out client);
- auth.TryGetValue("Version", out version);
-
- if (!string.IsNullOrEmpty(client) && !string.IsNullOrEmpty(deviceId) && !string.IsNullOrEmpty(device) && !string.IsNullOrEmpty(version))
- {
- SessionManager.LogConnectionActivity(client, version, deviceId, device, user);
- }
- }
- }
-
- /// <summary>
- /// Gets the auth.
- /// </summary>
- /// <param name="httpReq">The HTTP req.</param>
- /// <returns>Dictionary{System.StringSystem.String}.</returns>
- public static Dictionary<string, string> GetAuthorization(IHttpRequest httpReq)
- {
- var auth = httpReq.Headers[HttpHeaders.Authorization];
-
- return GetAuthorization(auth);
- }
-
- /// <summary>
- /// Gets the authorization.
- /// </summary>
- /// <param name="httpReq">The HTTP req.</param>
- /// <returns>Dictionary{System.StringSystem.String}.</returns>
- public static Dictionary<string, string> GetAuthorization(IRequestContext httpReq)
- {
- var auth = httpReq.GetHeader("Authorization");
-
- return GetAuthorization(auth);
- }
-
- /// <summary>
- /// Gets the authorization.
- /// </summary>
- /// <param name="authorizationHeader">The authorization header.</param>
- /// <returns>Dictionary{System.StringSystem.String}.</returns>
- private static Dictionary<string, string> GetAuthorization(string authorizationHeader)
- {
- if (authorizationHeader == null) return null;
-
- var parts = authorizationHeader.Split(' ');
-
- // There should be at least to parts
- if (parts.Length < 2) return null;
-
- // It has to be a digest request
- if (!string.Equals(parts[0], "MediaBrowser", StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
-
- // Remove uptil the first space
- authorizationHeader = authorizationHeader.Substring(authorizationHeader.IndexOf(' '));
- parts = authorizationHeader.Split(',');
-
- var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-
- foreach (var item in parts)
- {
- var param = item.Trim().Split(new[] { '=' }, 2);
- result.Add(param[0], param[1].Trim(new[] { '"' }));
- }
-
- return result;
- }
-
- /// <summary>
- /// A new shallow copy of this filter is used on every request.
- /// </summary>
- /// <returns>IHasRequestFilter.</returns>
- public IHasRequestFilter Copy()
- {
- return this;
- }
-
- /// <summary>
- /// Order in which Request Filters are executed.
- /// &lt;0 Executed before global request filters
- /// &gt;0 Executed after global request filters
- /// </summary>
- /// <value>The priority.</value>
- public int Priority
- {
- get { return 0; }
- }
- }
}
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index c7cca812f..4f54b5249 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -13,6 +13,8 @@
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -36,29 +38,25 @@
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
- <Reference Include="MoreLinq, Version=1.0.16006.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="MoreLinq">
<HintPath>..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.Common, Version=3.9.60.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="ServiceStack.Common">
<HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Common.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.Interfaces, Version=3.9.60.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="ServiceStack.Interfaces">
<HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Interfaces.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.Text, Version=3.9.59.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="ServiceStack.Text">
<HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
</Reference>
- <Reference Include="System" />
- <Reference Include="System.Core" />
- <Reference Include="Microsoft.CSharp" />
- <Reference Include="System.Data" />
- <Reference Include="System.Drawing" />
- <Reference Include="System.Net.Http" />
- <Reference Include="System.XML" />
+ <Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
@@ -70,6 +68,7 @@
<Compile Include="DefaultTheme\Models.cs" />
<Compile Include="DisplayPreferencesService.cs" />
<Compile Include="EnvironmentService.cs" />
+ <Compile Include="AuthorizationRequestFilterAttribute.cs" />
<Compile Include="GamesService.cs" />
<Compile Include="Images\ImageByNameService.cs" />
<Compile Include="Images\ImageRequest.cs" />
@@ -88,6 +87,8 @@
<Compile Include="PackageService.cs" />
<Compile Include="Playback\Hls\AudioHlsService.cs" />
<Compile Include="Playback\Hls\BaseHlsService.cs" />
+ <Compile Include="Playback\Hls\HlsSegmentResponseFilter.cs" />
+ <Compile Include="Playback\Hls\HlsSegmentService.cs" />
<Compile Include="Playback\Hls\VideoHlsService.cs" />
<Compile Include="Playback\Progressive\AudioService.cs" />
<Compile Include="Playback\Progressive\BaseProgressiveStreamingService.cs" />
@@ -128,22 +129,24 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
- <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
+ <Project>{9142EEFA-7570-41E1-BFCC-468BB571AF2F}</Project>
<Name>MediaBrowser.Common</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
- <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
+ <Project>{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}</Project>
<Name>MediaBrowser.Controller</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
- <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
+ <Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
- <ItemGroup />
+ <ItemGroup>
+ <Folder Include="Filters\" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index e31a112d5..c782c243d 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -613,7 +613,7 @@ namespace MediaBrowser.Api.Playback
EnableRaisingEvents = true
};
- ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, TranscodingJobType, process, video != null, state.Request.StartTimeTicks);
+ ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, TranscodingJobType, process, video != null, state.Request.StartTimeTicks, state.Item.Path);
Logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
diff --git a/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs b/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs
index d7ee73a9e..6e36ba0ad 100644
--- a/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs
@@ -6,7 +6,6 @@ using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO;
using ServiceStack.ServiceHost;
using System;
-using System.IO;
namespace MediaBrowser.Api.Playback.Hls
{
@@ -21,27 +20,6 @@ namespace MediaBrowser.Api.Playback.Hls
}
/// <summary>
- /// Class GetHlsAudioSegment
- /// </summary>
- [Route("/Audio/{Id}/hls/{SegmentId}/stream.mp3", "GET")]
- [Route("/Audio/{Id}/hls/{SegmentId}/stream.aac", "GET")]
- [Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
- public class GetHlsAudioSegment
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- public string Id { get; set; }
-
- /// <summary>
- /// Gets or sets the segment id.
- /// </summary>
- /// <value>The segment id.</value>
- public string SegmentId { get; set; }
- }
-
- /// <summary>
/// Class AudioHlsService
/// </summary>
public class AudioHlsService : BaseHlsService
@@ -64,20 +42,6 @@ namespace MediaBrowser.Api.Playback.Hls
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetHlsAudioSegment request)
- {
- var file = request.SegmentId + Path.GetExtension(RequestContext.PathInfo);
-
- file = Path.Combine(ApplicationPaths.EncodedMediaCachePath, file);
-
- return ResultFactory.GetStaticFileResult(RequestContext, file, FileShare.ReadWrite);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
public object Get(GetHlsAudioStream request)
{
return ProcessRequest(request);
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index e680546b0..05441bba7 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -10,7 +10,6 @@ using MediaBrowser.Model.IO;
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -213,29 +212,6 @@ namespace MediaBrowser.Api.Playback.Hls
return count;
}
- protected void ExtendHlsTimer(string itemId, string playlistId)
- {
- var normalizedPlaylistId = playlistId.Replace("-low", string.Empty);
-
- foreach (var playlist in Directory.EnumerateFiles(ApplicationPaths.EncodedMediaCachePath, "*.m3u8")
- .Where(i => i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1)
- .ToList())
- {
- ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
-
- // Avoid implicitly captured closure
- var playlist1 = playlist;
-
- Task.Run(async () =>
- {
- // This is an arbitrary time period corresponding to when the request completes.
- await Task.Delay(30000).ConfigureAwait(false);
-
- ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist1, TranscodingJobType.Hls);
- });
- }
- }
-
/// <summary>
/// Gets the command line arguments.
/// </summary>
diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentResponseFilter.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentResponseFilter.cs
new file mode 100644
index 000000000..44996c99f
--- /dev/null
+++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentResponseFilter.cs
@@ -0,0 +1,53 @@
+using MediaBrowser.Controller;
+using MediaBrowser.Model.Logging;
+using ServiceStack.ServiceHost;
+using ServiceStack.Text.Controller;
+using System;
+using System.IO;
+using System.Linq;
+
+namespace MediaBrowser.Api.Playback.Hls
+{
+ public class HlsSegmentResponseFilter : Attribute, IHasResponseFilter
+ {
+ public ILogger Logger { get; set; }
+ public IServerApplicationPaths ApplicationPaths { get; set; }
+
+ public void ResponseFilter(IHttpRequest req, IHttpResponse res, object response)
+ {
+ var pathInfo = PathInfo.Parse(req.PathInfo);
+ var itemId = pathInfo.GetArgumentValue<string>(1);
+ var playlistId = pathInfo.GetArgumentValue<string>(3);
+
+ OnEndRequest(itemId, playlistId);
+ }
+
+ public IHasResponseFilter Copy()
+ {
+ return this;
+ }
+
+ public int Priority
+ {
+ get { return -1; }
+ }
+
+ /// <summary>
+ /// Called when [end request].
+ /// </summary>
+ /// <param name="itemId">The item id.</param>
+ /// <param name="playlistId">The playlist id.</param>
+ protected void OnEndRequest(string itemId, string playlistId)
+ {
+ Logger.Info("OnEndRequest " + playlistId);
+ var normalizedPlaylistId = playlistId.Replace("-low", string.Empty);
+
+ foreach (var playlist in Directory.EnumerateFiles(ApplicationPaths.EncodedMediaCachePath, "*.m3u8")
+ .Where(i => i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1)
+ .ToList())
+ {
+ ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls);
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
new file mode 100644
index 000000000..f1fa86f78
--- /dev/null
+++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
@@ -0,0 +1,147 @@
+using MediaBrowser.Controller;
+using ServiceStack.ServiceHost;
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Api.Playback.Hls
+{
+ /// <summary>
+ /// Class GetHlsAudioSegment
+ /// </summary>
+ [Route("/Audio/{Id}/hls/{SegmentId}/stream.mp3", "GET")]
+ [Route("/Audio/{Id}/hls/{SegmentId}/stream.aac", "GET")]
+ [Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
+ public class GetHlsAudioSegment
+ {
+ /// <summary>
+ /// Gets or sets the id.
+ /// </summary>
+ /// <value>The id.</value>
+ public string Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets the segment id.
+ /// </summary>
+ /// <value>The segment id.</value>
+ public string SegmentId { get; set; }
+ }
+
+ /// <summary>
+ /// Class GetHlsVideoSegment
+ /// </summary>
+ [Route("/Videos/{Id}/hls/{PlaylistId}/{SegmentId}.ts", "GET")]
+ [Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
+ public class GetHlsVideoSegment
+ {
+ /// <summary>
+ /// Gets or sets the id.
+ /// </summary>
+ /// <value>The id.</value>
+ public string Id { get; set; }
+
+ public string PlaylistId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the segment id.
+ /// </summary>
+ /// <value>The segment id.</value>
+ public string SegmentId { get; set; }
+ }
+
+ /// <summary>
+ /// Class GetHlsVideoSegment
+ /// </summary>
+ [Route("/Videos/{Id}/hls/{PlaylistId}/stream.m3u8", "GET")]
+ [Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
+ public class GetHlsPlaylist
+ {
+ /// <summary>
+ /// Gets or sets the id.
+ /// </summary>
+ /// <value>The id.</value>
+ public string Id { get; set; }
+
+ public string PlaylistId { get; set; }
+ }
+
+ public class HlsSegmentService : BaseApiService
+ {
+ private readonly IServerApplicationPaths _appPaths;
+
+ public HlsSegmentService(IServerApplicationPaths appPaths)
+ {
+ _appPaths = appPaths;
+ }
+
+ public object Get(GetHlsPlaylist request)
+ {
+ OnBeginRequest(request.PlaylistId);
+
+ var file = request.PlaylistId + Path.GetExtension(RequestContext.PathInfo);
+
+ file = Path.Combine(_appPaths.EncodedMediaCachePath, file);
+
+ return ResultFactory.GetStaticFileResult(RequestContext, file, FileShare.ReadWrite);
+ }
+
+ /// <summary>
+ /// Gets the specified request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>System.Object.</returns>
+ public object Get(GetHlsVideoSegment request)
+ {
+ var file = request.SegmentId + Path.GetExtension(RequestContext.PathInfo);
+
+ file = Path.Combine(_appPaths.EncodedMediaCachePath, file);
+
+ OnBeginRequest(request.PlaylistId);
+
+ return ResultFactory.GetStaticFileResult(RequestContext, file);
+ }
+
+ /// <summary>
+ /// Gets the specified request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>System.Object.</returns>
+ public object Get(GetHlsAudioSegment request)
+ {
+ var file = request.SegmentId + Path.GetExtension(RequestContext.PathInfo);
+
+ file = Path.Combine(_appPaths.EncodedMediaCachePath, file);
+
+ return ResultFactory.GetStaticFileResult(RequestContext, file, FileShare.ReadWrite);
+ }
+
+ /// <summary>
+ /// Called when [begin request].
+ /// </summary>
+ /// <param name="playlistId">The playlist id.</param>
+ protected void OnBeginRequest(string playlistId)
+ {
+ var normalizedPlaylistId = playlistId.Replace("-low", string.Empty);
+
+ foreach (var playlist in Directory.EnumerateFiles(_appPaths.EncodedMediaCachePath, "*.m3u8")
+ .Where(i => i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1)
+ .ToList())
+ {
+ ExtendPlaylistTimer(playlist);
+ }
+ }
+
+ private void ExtendPlaylistTimer(string playlist)
+ {
+ ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
+
+ Task.Run(async () =>
+ {
+ await Task.Delay(20000).ConfigureAwait(false);
+
+ ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls);
+ });
+ }
+ }
+}
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index 901b27688..4694b68a1 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -5,7 +5,6 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Model.IO;
using ServiceStack.ServiceHost;
using System;
-using System.IO;
namespace MediaBrowser.Api.Playback.Hls
{
@@ -32,44 +31,6 @@ namespace MediaBrowser.Api.Playback.Hls
}
/// <summary>
- /// Class GetHlsVideoSegment
- /// </summary>
- [Route("/Videos/{Id}/hls/{PlaylistId}/{SegmentId}.ts", "GET")]
- [Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
- public class GetHlsVideoSegment
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- public string Id { get; set; }
-
- public string PlaylistId { get; set; }
-
- /// <summary>
- /// Gets or sets the segment id.
- /// </summary>
- /// <value>The segment id.</value>
- public string SegmentId { get; set; }
- }
-
- /// <summary>
- /// Class GetHlsVideoSegment
- /// </summary>
- [Route("/Videos/{Id}/hls/{PlaylistId}/stream.m3u8", "GET")]
- [Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
- public class GetHlsPlaylist
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- public string Id { get; set; }
-
- public string PlaylistId { get; set; }
- }
-
- /// <summary>
/// Class VideoHlsService
/// </summary>
public class VideoHlsService : BaseHlsService
@@ -82,6 +43,7 @@ namespace MediaBrowser.Api.Playback.Hls
/// <param name="libraryManager">The library manager.</param>
/// <param name="isoManager">The iso manager.</param>
/// <param name="mediaEncoder">The media encoder.</param>
+ /// <param name="dtoService">The dto service.</param>
public VideoHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService)
{
@@ -92,33 +54,6 @@ namespace MediaBrowser.Api.Playback.Hls
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetHlsVideoSegment request)
- {
- ExtendHlsTimer(request.Id, request.PlaylistId);
-
- var file = request.SegmentId + Path.GetExtension(RequestContext.PathInfo);
-
- file = Path.Combine(ApplicationPaths.EncodedMediaCachePath, file);
-
- return ResultFactory.GetStaticFileResult(RequestContext, file);
- }
-
- public object Get(GetHlsPlaylist request)
- {
- ExtendHlsTimer(request.Id, request.PlaylistId);
-
- var file = request.PlaylistId + Path.GetExtension(RequestContext.PathInfo);
-
- file = Path.Combine(ApplicationPaths.EncodedMediaCachePath, file);
-
- return ResultFactory.GetStaticFileResult(RequestContext, file, FileShare.ReadWrite);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
public object Get(GetHlsVideoStream request)
{
return ProcessRequest(request);
diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs
index cad3c4384..5888d9fba 100644
--- a/MediaBrowser.Api/SessionsService.cs
+++ b/MediaBrowser.Api/SessionsService.cs
@@ -1,7 +1,5 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session;
using ServiceStack.ServiceHost;
using System;
@@ -189,6 +187,7 @@ namespace MediaBrowser.Api
/// Initializes a new instance of the <see cref="SessionsService" /> class.
/// </summary>
/// <param name="sessionManager">The session manager.</param>
+ /// <param name="dtoService">The dto service.</param>
public SessionsService(ISessionManager sessionManager, IDtoService dtoService)
{
_sessionManager = sessionManager;
@@ -214,52 +213,15 @@ namespace MediaBrowser.Api
public void Post(SendPlaystateCommand request)
{
- var task = SendPlaystateCommand(request);
-
- Task.WaitAll(task);
- }
-
- private async Task SendPlaystateCommand(SendPlaystateCommand request)
- {
- var session = _sessionManager.Sessions.FirstOrDefault(i => i.Id == request.Id);
-
- if (session == null)
+ var command = new PlaystateRequest
{
- throw new ResourceNotFoundException(string.Format("Session {0} not found.", request.Id));
- }
-
- if (!session.SupportsRemoteControl)
- {
- throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id));
- }
+ Command = request.Command,
+ SeekPositionTicks = request.SeekPositionTicks
+ };
- var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open);
+ var task = _sessionManager.SendPlaystateCommand(request.Id, command, CancellationToken.None);
- if (socket != null)
- {
- try
- {
- await socket.SendAsync(new WebSocketMessage<PlaystateRequest>
- {
- MessageType = "Playstate",
-
- Data = new PlaystateRequest
- {
- Command = request.Command,
- SeekPositionTicks = request.SeekPositionTicks
- }
-
- }, CancellationToken.None).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error sending web socket message", ex);
- }
- }
- else
- {
- throw new InvalidOperationException("The requested session does not have an open web socket.");
- }
+ Task.WaitAll(task);
}
/// <summary>
@@ -268,55 +230,17 @@ namespace MediaBrowser.Api
/// <param name="request">The request.</param>
public void Post(BrowseTo request)
{
- var task = BrowseTo(request);
-
- Task.WaitAll(task);
- }
-
- /// <summary>
- /// Browses to.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>Task.</returns>
- /// <exception cref="ResourceNotFoundException"></exception>
- /// <exception cref="System.ArgumentException"></exception>
- /// <exception cref="System.InvalidOperationException">The requested session does not have an open web socket.</exception>
- private async Task BrowseTo(BrowseTo request)
- {
- var session = _sessionManager.Sessions.FirstOrDefault(i => i.Id == request.Id);
-
- if (session == null)
- {
- throw new ResourceNotFoundException(string.Format("Session {0} not found.", request.Id));
- }
-
- if (!session.SupportsRemoteControl)
+ var command = new BrowseRequest
{
- throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id));
- }
+ Context = request.Context,
+ ItemId = request.ItemId,
+ ItemName = request.ItemName,
+ ItemType = request.ItemType
+ };
- var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open);
+ var task = _sessionManager.SendBrowseCommand(request.Id, command, CancellationToken.None);
- if (socket != null)
- {
- try
- {
- await socket.SendAsync(new WebSocketMessage<BrowseTo>
- {
- MessageType = "Browse",
- Data = request
-
- }, CancellationToken.None).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error sending web socket message", ex);
- }
- }
- else
- {
- throw new InvalidOperationException("The requested session does not have an open web socket.");
- }
+ Task.WaitAll(task);
}
/// <summary>
@@ -325,102 +249,27 @@ namespace MediaBrowser.Api
/// <param name="request">The request.</param>
public void Post(SendSystemCommand request)
{
- var task = SendSystemCommand(request);
+ var task = _sessionManager.SendSystemCommand(request.Id, request.Command, CancellationToken.None);
Task.WaitAll(task);
}
- private async Task SendSystemCommand(SendSystemCommand request)
- {
- var session = _sessionManager.Sessions.FirstOrDefault(i => i.Id == request.Id);
-
- if (session == null)
- {
- throw new ResourceNotFoundException(string.Format("Session {0} not found.", request.Id));
- }
-
- if (!session.SupportsRemoteControl)
- {
- throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id));
- }
-
- var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open);
-
- if (socket != null)
- {
- try
- {
- await socket.SendAsync(new WebSocketMessage<string>
- {
- MessageType = "SystemCommand",
- Data = request.Command.ToString()
-
- }, CancellationToken.None).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error sending web socket message", ex);
- }
- }
- else
- {
- throw new InvalidOperationException("The requested session does not have an open web socket.");
- }
- }
-
/// <summary>
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
public void Post(SendMessageCommand request)
{
- var task = SendMessageCommand(request);
-
- Task.WaitAll(task);
- }
-
- private async Task SendMessageCommand(SendMessageCommand request)
- {
- var session = _sessionManager.Sessions.FirstOrDefault(i => i.Id == request.Id);
-
- if (session == null)
- {
- throw new ResourceNotFoundException(string.Format("Session {0} not found.", request.Id));
- }
-
- if (!session.SupportsRemoteControl)
+ var command = new MessageCommand
{
- throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id));
- }
+ Header = string.IsNullOrEmpty(request.Header) ? "Message from Server" : request.Header,
+ TimeoutMs = request.TimeoutMs,
+ Text = request.Text
+ };
- var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open);
+ var task = _sessionManager.SendMessageCommand(request.Id, command, CancellationToken.None);
- if (socket != null)
- {
- try
- {
- await socket.SendAsync(new WebSocketMessage<MessageCommand>
- {
- MessageType = "MessageCommand",
-
- Data = new MessageCommand
- {
- Header = string.IsNullOrEmpty(request.Header) ? "Message from Server" : request.Header,
- TimeoutMs = request.TimeoutMs,
- Text = request.Text
- }
-
- }, CancellationToken.None).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error sending web socket message", ex);
- }
- }
- else
- {
- throw new InvalidOperationException("The requested session does not have an open web socket.");
- }
+ Task.WaitAll(task);
}
/// <summary>
@@ -429,62 +278,17 @@ namespace MediaBrowser.Api
/// <param name="request">The request.</param>
public void Post(Play request)
{
- var task = Play(request);
-
- Task.WaitAll(task);
- }
-
- /// <summary>
- /// Plays the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>Task.</returns>
- /// <exception cref="ResourceNotFoundException"></exception>
- /// <exception cref="System.ArgumentException"></exception>
- /// <exception cref="System.InvalidOperationException">The requested session does not have an open web socket.</exception>
- private async Task Play(Play request)
- {
- var session = _sessionManager.Sessions.FirstOrDefault(i => i.Id == request.Id);
-
- if (session == null)
+ var command = new PlayRequest
{
- throw new ResourceNotFoundException(string.Format("Session {0} not found.", request.Id));
- }
+ ItemIds = request.ItemIds.Split(',').ToArray(),
- if (!session.SupportsRemoteControl)
- {
- throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id));
- }
+ PlayCommand = request.PlayCommand,
+ StartPositionTicks = request.StartPositionTicks
+ };
- var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open);
+ var task = _sessionManager.SendPlayCommand(request.Id, command, CancellationToken.None);
- if (socket != null)
- {
- try
- {
- await socket.SendAsync(new WebSocketMessage<PlayRequest>
- {
- MessageType = "Play",
-
- Data = new PlayRequest
- {
- ItemIds = request.ItemIds.Split(',').ToArray(),
-
- PlayCommand = request.PlayCommand,
- StartPositionTicks = request.StartPositionTicks
- }
-
- }, CancellationToken.None).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error sending web socket message", ex);
- }
- }
- else
- {
- throw new InvalidOperationException("The requested session does not have an open web socket.");
- }
+ Task.WaitAll(task);
}
}
}
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index ab3e2af19..abd42910f 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -186,7 +186,7 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "DatePlayed", Description = "The date the item was played (if any)", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
public DateTime? DatePlayed { get; set; }
-
+
/// <summary>
/// Gets or sets the id.
/// </summary>
@@ -224,6 +224,13 @@ namespace MediaBrowser.Api.UserLibrary
[Api(Description = "Reports that a user has begun playing an item")]
public class OnPlaybackStart : IReturnVoid
{
+ public OnPlaybackStart()
+ {
+ // Have to default these until all clients have a chance to incorporate them
+ CanSeek = true;
+ QueueableMediaTypes = "Audio,Video,Book,Game";
+ }
+
/// <summary>
/// Gets or sets the user id.
/// </summary>
@@ -237,6 +244,20 @@ namespace MediaBrowser.Api.UserLibrary
/// <value>The id.</value>
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public string Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="UpdateUserItemRating" /> is likes.
+ /// </summary>
+ /// <value><c>true</c> if likes; otherwise, <c>false</c>.</value>
+ [ApiMember(Name = "CanSeek", Description = "Indicates if the client can seek", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
+ public bool CanSeek { get; set; }
+
+ /// <summary>
+ /// Gets or sets the id.
+ /// </summary>
+ /// <value>The id.</value>
+ [ApiMember(Name = "QueueableMediaTypes", Description = "A list of media types that can be queued from this item, comma delimited. Audio,Video,Book,Game", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST", AllowMultiple = true)]
+ public string QueueableMediaTypes { get; set; }
}
/// <summary>
@@ -378,6 +399,8 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="libraryManager">The library manager.</param>
/// <param name="userDataRepository">The user data repository.</param>
/// <param name="itemRepo">The item repo.</param>
+ /// <param name="sessionManager">The session manager.</param>
+ /// <param name="dtoService">The dto service.</param>
/// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo, ISessionManager sessionManager, IDtoService dtoService)
{
@@ -640,19 +663,11 @@ namespace MediaBrowser.Api.UserLibrary
private SessionInfo GetSession()
{
- var auth = RequestFilterAttribute.GetAuthorization(RequestContext);
-
- string deviceId;
- string client;
- string version;
-
- auth.TryGetValue("DeviceId", out deviceId);
- auth.TryGetValue("Client", out client);
- auth.TryGetValue("Version", out version);
+ var auth = AuthorizationRequestFilterAttribute.GetAuthorization(RequestContext);
- return _sessionManager.Sessions.First(i => string.Equals(i.DeviceId, deviceId) &&
- string.Equals(i.Client, client) &&
- string.Equals(i.ApplicationVersion, version));
+ return _sessionManager.Sessions.First(i => string.Equals(i.DeviceId, auth.DeviceId) &&
+ string.Equals(i.Client, auth.Client) &&
+ string.Equals(i.ApplicationVersion, auth.Version));
}
/// <summary>
@@ -665,7 +680,17 @@ namespace MediaBrowser.Api.UserLibrary
var item = _dtoService.GetItemByDtoId(request.Id, user.Id);
- _sessionManager.OnPlaybackStart(item, GetSession().Id);
+ var queueableMediaTypes = (request.QueueableMediaTypes ?? string.Empty);
+
+ var info = new PlaybackInfo
+ {
+ CanSeek = request.CanSeek,
+ Item = item,
+ SessionId = GetSession().Id,
+ QueueableMediaTypes = queueableMediaTypes.Split(',').ToList()
+ };
+
+ _sessionManager.OnPlaybackStart(info);
}
/// <summary>
@@ -693,7 +718,12 @@ namespace MediaBrowser.Api.UserLibrary
var item = _dtoService.GetItemByDtoId(request.Id, user.Id);
- var task = _sessionManager.OnPlaybackStopped(item, request.PositionTicks, GetSession().Id);
+ // Kill the encoding
+ ApiEntryPoint.Instance.KillSingleTranscodingJob(item.Path);
+
+ var session = GetSession();
+
+ var task = _sessionManager.OnPlaybackStopped(item, request.PositionTicks, session.Id);
Task.WaitAll(task);
}
diff --git a/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs b/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs
new file mode 100644
index 000000000..39690eb07
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs
@@ -0,0 +1,87 @@
+using MediaBrowser.Model.IO;
+using SharpCompress.Archive.SevenZip;
+using SharpCompress.Common;
+using SharpCompress.Reader;
+using System.IO;
+
+namespace MediaBrowser.Common.Implementations.Archiving
+{
+ /// <summary>
+ /// Class DotNetZipClient
+ /// </summary>
+ public class ZipClient : IZipClient
+ {
+ /// <summary>
+ /// Extracts all.
+ /// </summary>
+ /// <param name="sourceFile">The source file.</param>
+ /// <param name="targetPath">The target path.</param>
+ /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
+ public void ExtractAll(string sourceFile, string targetPath, bool overwriteExistingFiles)
+ {
+ using (var fileStream = File.OpenRead(sourceFile))
+ {
+ ExtractAll(fileStream, targetPath, overwriteExistingFiles);
+ }
+ }
+
+ /// <summary>
+ /// Extracts all.
+ /// </summary>
+ /// <param name="source">The source.</param>
+ /// <param name="targetPath">The target path.</param>
+ /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
+ public void ExtractAll(Stream source, string targetPath, bool overwriteExistingFiles)
+ {
+ using (var reader = ReaderFactory.Open(source))
+ {
+ var options = ExtractOptions.ExtractFullPath;
+
+ if (overwriteExistingFiles)
+ {
+ options = options | ExtractOptions.Overwrite;
+ }
+
+ reader.WriteAllToDirectory(targetPath, options);
+ }
+ }
+
+ /// <summary>
+ /// Extracts all from7z.
+ /// </summary>
+ /// <param name="sourceFile">The source file.</param>
+ /// <param name="targetPath">The target path.</param>
+ /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
+ public void ExtractAllFrom7z(string sourceFile, string targetPath, bool overwriteExistingFiles)
+ {
+ using (var fileStream = File.OpenRead(sourceFile))
+ {
+ ExtractAllFrom7z(fileStream, targetPath, overwriteExistingFiles);
+ }
+ }
+
+ /// <summary>
+ /// Extracts all from7z.
+ /// </summary>
+ /// <param name="source">The source.</param>
+ /// <param name="targetPath">The target path.</param>
+ /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
+ public void ExtractAllFrom7z(Stream source, string targetPath, bool overwriteExistingFiles)
+ {
+ using (var archive = SevenZipArchive.Open(source))
+ {
+ using (var reader = archive.ExtractAllEntries())
+ {
+ var options = ExtractOptions.ExtractFullPath;
+
+ if (overwriteExistingFiles)
+ {
+ options = options | ExtractOptions.Overwrite;
+ }
+
+ reader.WriteAllToDirectory(targetPath, options);
+ }
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
index c0ac6a4b3..0d96df9a2 100644
--- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
+++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Implementations.Archiving;
using MediaBrowser.Common.Implementations.NetworkManagement;
using MediaBrowser.Common.Implementations.ScheduledTasks;
using MediaBrowser.Common.Implementations.Security;
@@ -10,6 +11,7 @@ using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Common.Security;
using MediaBrowser.Common.Updates;
+using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Updates;
@@ -150,6 +152,12 @@ namespace MediaBrowser.Common.Implementations
protected IInstallationManager InstallationManager { get; set; }
/// <summary>
+ /// Gets or sets the zip client.
+ /// </summary>
+ /// <value>The zip client.</value>
+ protected IZipClient ZipClient { get; set; }
+
+ /// <summary>
/// Initializes a new instance of the <see cref="BaseApplicationHost{TApplicationPathsType}"/> class.
/// </summary>
protected BaseApplicationHost(TApplicationPathsType applicationPaths, ILogManager logManager)
@@ -202,13 +210,28 @@ namespace MediaBrowser.Common.Implementations
{
Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
- Task.Run(() => ConfigureAutoRunAtStartup());
+ Task.Run(() => ConfigureAutorun());
ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
});
}
/// <summary>
+ /// Configures the autorun.
+ /// </summary>
+ private void ConfigureAutorun()
+ {
+ try
+ {
+ ConfigureAutoRunAtStartup(ConfigurationManager.CommonConfiguration.RunAtStartup);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error configuring autorun", ex);
+ }
+ }
+
+ /// <summary>
/// Gets the composable part assemblies.
/// </summary>
/// <returns>IEnumerable{Assembly}.</returns>
@@ -281,6 +304,9 @@ namespace MediaBrowser.Common.Implementations
InstallationManager = new InstallationManager(Logger, this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, NetworkManager, ConfigurationManager);
RegisterSingleInstance(InstallationManager);
+
+ ZipClient = new ZipClient();
+ RegisterSingleInstance(ZipClient);
});
}
@@ -454,11 +480,6 @@ namespace MediaBrowser.Common.Implementations
}
/// <summary>
- /// Defines the full path to our shortcut in the start menu
- /// </summary>
- protected abstract string ProductShortcutPath { get; }
-
- /// <summary>
/// Handles the ConfigurationUpdated event of the ConfigurationManager control.
/// </summary>
/// <param name="sender">The source of the event.</param>
@@ -466,32 +487,10 @@ namespace MediaBrowser.Common.Implementations
/// <exception cref="System.NotImplementedException"></exception>
protected virtual void OnConfigurationUpdated(object sender, EventArgs e)
{
- ConfigureAutoRunAtStartup();
+ ConfigureAutorun();
}
- /// <summary>
- /// Configures the auto run at startup.
- /// </summary>
- private void ConfigureAutoRunAtStartup()
- {
- if (ConfigurationManager.CommonConfiguration.RunAtStartup)
- {
- //Copy our shortut into the startup folder for this user
- File.Copy(ProductShortcutPath, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), Path.GetFileName(ProductShortcutPath) ?? "MBstartup.lnk"), true);
- }
- else
- {
- //Remove our shortcut from the startup folder for this user
- try
- {
- File.Delete(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), Path.GetFileName(ProductShortcutPath) ?? "MBstartup.lnk"));
- }
- catch (FileNotFoundException)
- {
- //This is okay - trying to remove it anyway
- }
- }
- }
+ protected abstract void ConfigureAutoRunAtStartup(bool autorun);
/// <summary>
/// Removes the plugin.
diff --git a/MediaBrowser.Common.Implementations/Logging/NlogManager.cs b/MediaBrowser.Common.Implementations/Logging/NlogManager.cs
index 109e85d80..e20f9bc13 100644
--- a/MediaBrowser.Common.Implementations/Logging/NlogManager.cs
+++ b/MediaBrowser.Common.Implementations/Logging/NlogManager.cs
@@ -5,7 +5,6 @@ using NLog.Targets;
using System;
using System.IO;
using System.Linq;
-using System.Threading.Tasks;
namespace MediaBrowser.Common.Implementations.Logging
{
@@ -193,17 +192,14 @@ namespace MediaBrowser.Common.Implementations.Logging
if (LoggerLoaded != null)
{
- Task.Run(() =>
+ try
{
- try
- {
- LoggerLoaded(this, EventArgs.Empty);
- }
- catch (Exception ex)
- {
- GetLogger("Logger").ErrorException("Error in LoggerLoaded event", ex);
- }
- });
+ LoggerLoaded(this, EventArgs.Empty);
+ }
+ catch (Exception ex)
+ {
+ GetLogger("Logger").ErrorException("Error in LoggerLoaded event", ex);
+ }
}
}
}
diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
index a96f2c354..11da950f7 100644
--- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
+++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
@@ -13,6 +13,8 @@
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -35,17 +37,8 @@
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
- <Reference Include="NLog, Version=2.0.1.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\NLog.2.0.1.2\lib\net45\NLog.dll</HintPath>
- </Reference>
- <Reference Include="ServiceStack.Text, Version=3.9.59.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
- </Reference>
- <Reference Include="SimpleInjector, Version=2.3.5.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\SimpleInjector.2.3.5\lib\net40-client\SimpleInjector.dll</HintPath>
+ <Reference Include="SharpCompress">
+ <HintPath>..\packages\sharpcompress.0.10.1.3\lib\net40\SharpCompress.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
@@ -54,11 +47,21 @@
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
+ <Reference Include="NLog">
+ <HintPath>..\packages\NLog.2.0.1.2\lib\net45\NLog.dll</HintPath>
+ </Reference>
+ <Reference Include="ServiceStack.Text">
+ <HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
+ </Reference>
+ <Reference Include="SimpleInjector">
+ <HintPath>..\packages\SimpleInjector.2.3.5\lib\net40-client\SimpleInjector.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
+ <Compile Include="Archiving\ZipClient.cs" />
<Compile Include="BaseApplicationHost.cs" />
<Compile Include="BaseApplicationPaths.cs" />
<Compile Include="Configuration\BaseConfigurationManager.cs" />
@@ -88,11 +91,11 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
- <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
+ <Project>{9142EEFA-7570-41E1-BFCC-468BB571AF2F}</Project>
<Name>MediaBrowser.Common</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
- <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
+ <Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
index 8278c8a28..6605432fa 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
@@ -1,5 +1,4 @@
-using System.Threading.Tasks;
-using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Model.Logging;
@@ -8,6 +7,7 @@ using MediaBrowser.Model.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
namespace MediaBrowser.Common.Implementations.ScheduledTasks
{
@@ -78,6 +78,17 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
}
/// <summary>
+ /// Cancels if running
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public void CancelIfRunning<T>()
+ where T : IScheduledTask
+ {
+ var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T));
+ ((ScheduledTaskWorker)task).CancelIfRunning();
+ }
+
+ /// <summary>
/// Queues the scheduled task.
/// </summary>
/// <typeparam name="T"></typeparam>
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
index 15f955723..bfd626adb 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
@@ -54,33 +54,32 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
/// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{
- return Task.Run(() =>
- {
- // Delete log files more than n days old
- var minDateModified = DateTime.UtcNow.AddDays(-(ConfigurationManager.CommonConfiguration.LogFileRetentionDays));
+ // Delete log files more than n days old
+ var minDateModified = DateTime.UtcNow.AddDays(-(ConfigurationManager.CommonConfiguration.LogFileRetentionDays));
+
+ var filesToDelete = new DirectoryInfo(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath).EnumerateFileSystemInfos("*", SearchOption.AllDirectories)
+ .Where(f => f.LastWriteTimeUtc < minDateModified)
+ .ToList();
- var filesToDelete = new DirectoryInfo(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath).EnumerateFileSystemInfos("*", SearchOption.AllDirectories)
- .Where(f => f.LastWriteTimeUtc < minDateModified)
- .ToList();
+ var index = 0;
- var index = 0;
+ foreach (var file in filesToDelete)
+ {
+ double percent = index;
+ percent /= filesToDelete.Count;
- foreach (var file in filesToDelete)
- {
- double percent = index;
- percent /= filesToDelete.Count;
+ progress.Report(100 * percent);
- progress.Report(100 * percent);
+ cancellationToken.ThrowIfCancellationRequested();
- cancellationToken.ThrowIfCancellationRequested();
+ File.Delete(file.FullName);
- File.Delete(file.FullName);
+ index++;
+ }
- index++;
- }
+ progress.Report(100);
- progress.Report(100);
- });
+ return Task.FromResult(true);
}
/// <summary>
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs
index e860834ec..00928255c 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs
@@ -58,7 +58,11 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
progress.Report(0);
- return Task.Run(() => LogManager.ReloadLogger(ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging ? LogSeverity.Debug : LogSeverity.Info));
+ LogManager.ReloadLogger(ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging
+ ? LogSeverity.Debug
+ : LogSeverity.Info);
+
+ return Task.FromResult(true);
}
/// <summary>
diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config
index 4be861cce..d03cb14e0 100644
--- a/MediaBrowser.Common.Implementations/packages.config
+++ b/MediaBrowser.Common.Implementations/packages.config
@@ -2,5 +2,6 @@
<packages>
<package id="NLog" version="2.0.1.2" targetFramework="net45" />
<package id="ServiceStack.Text" version="3.9.62" targetFramework="net45" />
+ <package id="sharpcompress" version="0.10.1.3" targetFramework="net45" />
<package id="SimpleInjector" version="2.3.5" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj
index 1611c55da..8acd1a83c 100644
--- a/MediaBrowser.Common/MediaBrowser.Common.csproj
+++ b/MediaBrowser.Common/MediaBrowser.Common.csproj
@@ -13,6 +13,8 @@
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -32,26 +34,19 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
- <PropertyGroup>
- <ApplicationIcon>
- </ApplicationIcon>
- </PropertyGroup>
<ItemGroup>
- <Reference Include="ServiceStack.Common, Version=3.9.60.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="ServiceStack.Common">
<HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Common.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.Interfaces, Version=3.9.60.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="ServiceStack.Interfaces">
<HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Interfaces.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.Text, Version=3.9.59.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="ServiceStack.Text">
<HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
</Reference>
- <Reference Include="System" />
- <Reference Include="System.Core" />
- <Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
@@ -113,7 +108,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
- <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
+ <Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
diff --git a/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs b/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs
index ec0e7c1c9..394872783 100644
--- a/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs
+++ b/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs
@@ -22,6 +22,13 @@ namespace MediaBrowser.Common.ScheduledTasks
where T : IScheduledTask;
/// <summary>
+ /// Cancels if running.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ void CancelIfRunning<T>()
+ where T : IScheduledTask;
+
+ /// <summary>
/// Queues the scheduled task.
/// </summary>
/// <typeparam name="T"></typeparam>
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 0d91a2e86..0f090f587 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -16,7 +16,6 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
-using MoreLinq;
namespace MediaBrowser.Controller.Entities
{
@@ -171,6 +170,25 @@ namespace MediaBrowser.Controller.Entities
return ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken);
}
+ /// <summary>
+ /// Clears the children.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ public Task ClearChildren(CancellationToken cancellationToken)
+ {
+ var items = ActualChildren.ToList();
+
+ ClearChildrenInternal();
+
+ foreach (var item in items)
+ {
+ LibraryManager.ReportItemRemoved(item);
+ }
+
+ return ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken);
+ }
+
#region Indexing
/// <summary>
@@ -671,7 +689,7 @@ namespace MediaBrowser.Controller.Entities
var options = new ParallelOptions
{
- MaxDegreeOfParallelism = 20
+ MaxDegreeOfParallelism = 10
};
Parallel.ForEach(nonCachedChildren, options, child =>
@@ -733,6 +751,11 @@ namespace MediaBrowser.Controller.Entities
if (actualRemovals.Count > 0)
{
RemoveChildrenInternal(actualRemovals);
+
+ foreach (var item in actualRemovals)
+ {
+ LibraryManager.ReportItemRemoved(item);
+ }
}
await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false);
@@ -781,7 +804,7 @@ namespace MediaBrowser.Controller.Entities
foreach (var tuple in list)
{
- if (tasks.Count > 8)
+ if (tasks.Count > 5)
{
await Task.WhenAll(tasks).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index f49bd8cf0..0b27a350b 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -13,6 +13,8 @@
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -42,6 +44,8 @@
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <WarningLevel>4</WarningLevel>
+ <Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
@@ -51,12 +55,9 @@
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
- <Reference Include="MoreLinq, Version=1.0.16006.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll</HintPath>
- </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
@@ -66,6 +67,9 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
+ <Reference Include="MoreLinq">
+ <HintPath>..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
@@ -165,6 +169,8 @@
<Compile Include="Kernel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Providers\BaseMetadataProvider.cs" />
+ <Compile Include="Session\ISessionRemoteController.cs" />
+ <Compile Include="Session\PlaybackInfo.cs" />
<Compile Include="Session\SessionInfo.cs" />
<Compile Include="Sorting\IBaseItemComparer.cs" />
<Compile Include="Sorting\IUserBaseItemComparer.cs" />
@@ -172,11 +178,11 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
- <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
+ <Project>{9142EEFA-7570-41E1-BFCC-468BB571AF2F}</Project>
<Name>MediaBrowser.Common</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
- <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
+ <Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
diff --git a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs
index a8dc8788f..2364debed 100644
--- a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs
+++ b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs
@@ -385,7 +385,7 @@ namespace MediaBrowser.Controller.Providers
var sb = new StringBuilder();
var extensions = FileStampExtensionsDictionary;
- var numExtensions = extensions.Count;
+ var numExtensions = FilestampExtensions.Length;
// Record the name of each file
// Need to sort these because accoring to msdn docs, our i/o methods are not guaranteed in any order
diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs
index 1976c653a..0932ee52d 100644
--- a/MediaBrowser.Controller/Session/ISessionManager.cs
+++ b/MediaBrowser.Controller/Session/ISessionManager.cs
@@ -1,7 +1,9 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Session;
using System;
using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Session
@@ -12,6 +14,12 @@ namespace MediaBrowser.Controller.Session
public interface ISessionManager
{
/// <summary>
+ /// Adds the parts.
+ /// </summary>
+ /// <param name="remoteControllers">The remote controllers.</param>
+ void AddParts(IEnumerable<ISessionRemoteController> remoteControllers);
+
+ /// <summary>
/// Occurs when [playback start].
/// </summary>
event EventHandler<PlaybackProgressEventArgs> PlaybackStart;
@@ -47,11 +55,9 @@ namespace MediaBrowser.Controller.Session
/// <summary>
/// Used to report that playback has started for an item
/// </summary>
- /// <param name="item">The item.</param>
- /// <param name="sessionId">The session id.</param>
+ /// <param name="info">The info.</param>
/// <returns>Task.</returns>
- /// <exception cref="System.ArgumentNullException"></exception>
- Task OnPlaybackStart(BaseItem item, Guid sessionId);
+ Task OnPlaybackStart(PlaybackInfo info);
/// <summary>
/// Used to report playback progress for an item
@@ -59,6 +65,7 @@ namespace MediaBrowser.Controller.Session
/// <param name="item">The item.</param>
/// <param name="positionTicks">The position ticks.</param>
/// <param name="isPaused">if set to <c>true</c> [is paused].</param>
+ /// <param name="isMuted">if set to <c>true</c> [is muted].</param>
/// <param name="sessionId">The session id.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException"></exception>
@@ -73,5 +80,50 @@ namespace MediaBrowser.Controller.Session
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException"></exception>
Task OnPlaybackStopped(BaseItem item, long? positionTicks, Guid sessionId);
+
+ /// <summary>
+ /// Sends the system command.
+ /// </summary>
+ /// <param name="sessionId">The session id.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task SendSystemCommand(Guid sessionId, SystemCommand command, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Sends the message command.
+ /// </summary>
+ /// <param name="sessionId">The session id.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task SendMessageCommand(Guid sessionId, MessageCommand command, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Sends the play command.
+ /// </summary>
+ /// <param name="sessionId">The session id.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task SendPlayCommand(Guid sessionId, PlayRequest command, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Sends the browse command.
+ /// </summary>
+ /// <param name="sessionId">The session id.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task SendBrowseCommand(Guid sessionId, BrowseRequest command, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Sends the playstate command.
+ /// </summary>
+ /// <param name="sessionId">The session id.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task SendPlaystateCommand(Guid sessionId, PlaystateRequest command, CancellationToken cancellationToken);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Session/ISessionRemoteController.cs b/MediaBrowser.Controller/Session/ISessionRemoteController.cs
new file mode 100644
index 000000000..9ba5c983d
--- /dev/null
+++ b/MediaBrowser.Controller/Session/ISessionRemoteController.cs
@@ -0,0 +1,61 @@
+using MediaBrowser.Model.Session;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Session
+{
+ public interface ISessionRemoteController
+ {
+ /// <summary>
+ /// Supportses the specified session.
+ /// </summary>
+ /// <param name="session">The session.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
+ bool Supports(SessionInfo session);
+
+ /// <summary>
+ /// Sends the system command.
+ /// </summary>
+ /// <param name="session">The session.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task SendSystemCommand(SessionInfo session, SystemCommand command, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Sends the message command.
+ /// </summary>
+ /// <param name="session">The session.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task SendMessageCommand(SessionInfo session, MessageCommand command, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Sends the play command.
+ /// </summary>
+ /// <param name="session">The session.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task SendPlayCommand(SessionInfo session, PlayRequest command, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Sends the browse command.
+ /// </summary>
+ /// <param name="session">The session.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task SendBrowseCommand(SessionInfo session, BrowseRequest command, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Sends the playstate command.
+ /// </summary>
+ /// <param name="session">The session.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task SendPlaystateCommand(SessionInfo session, PlaystateRequest command, CancellationToken cancellationToken);
+ }
+}
diff --git a/MediaBrowser.Controller/Session/PlaybackInfo.cs b/MediaBrowser.Controller/Session/PlaybackInfo.cs
new file mode 100644
index 000000000..ab3111e76
--- /dev/null
+++ b/MediaBrowser.Controller/Session/PlaybackInfo.cs
@@ -0,0 +1,38 @@
+using MediaBrowser.Controller.Entities;
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Session
+{
+ public class PlaybackInfo
+ {
+ public PlaybackInfo()
+ {
+ QueueableMediaTypes = new List<string>();
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance can seek.
+ /// </summary>
+ /// <value><c>true</c> if this instance can seek; otherwise, <c>false</c>.</value>
+ public bool CanSeek { get; set; }
+
+ /// <summary>
+ /// Gets or sets the queueable media types.
+ /// </summary>
+ /// <value>The queueable media types.</value>
+ public List<string> QueueableMediaTypes { get; set; }
+
+ /// <summary>
+ /// Gets or sets the item.
+ /// </summary>
+ /// <value>The item.</value>
+ public BaseItem Item { get; set; }
+
+ /// <summary>
+ /// Gets or sets the session id.
+ /// </summary>
+ /// <value>The session id.</value>
+ public Guid SessionId { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs
index 6c0f1a085..dc934b70a 100644
--- a/MediaBrowser.Controller/Session/SessionInfo.cs
+++ b/MediaBrowser.Controller/Session/SessionInfo.cs
@@ -15,9 +15,22 @@ namespace MediaBrowser.Controller.Session
public SessionInfo()
{
WebSockets = new List<IWebSocketConnection>();
+ QueueableMediaTypes = new List<string>();
}
/// <summary>
+ /// Gets or sets a value indicating whether this instance can seek.
+ /// </summary>
+ /// <value><c>true</c> if this instance can seek; otherwise, <c>false</c>.</value>
+ public bool CanSeek { get; set; }
+
+ /// <summary>
+ /// Gets or sets the queueable media types.
+ /// </summary>
+ /// <value>The queueable media types.</value>
+ public List<string> QueueableMediaTypes { get; set; }
+
+ /// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
@@ -70,7 +83,7 @@ namespace MediaBrowser.Controller.Session
/// </summary>
/// <value>The name of the now viewing item.</value>
public string NowViewingItemName { get; set; }
-
+
/// <summary>
/// Gets or sets the now playing item.
/// </summary>
@@ -94,7 +107,7 @@ namespace MediaBrowser.Controller.Session
/// </summary>
/// <value><c>true</c> if this instance is muted; otherwise, <c>false</c>.</value>
public bool IsMuted { get; set; }
-
+
/// <summary>
/// Gets or sets the device id.
/// </summary>
@@ -126,7 +139,7 @@ namespace MediaBrowser.Controller.Session
return WebSockets.Any(i => i.State == WebSocketState.Open);
}
- return (DateTime.UtcNow - LastActivityDate).TotalMinutes <= 5;
+ return (DateTime.UtcNow - LastActivityDate).TotalMinutes <= 10;
}
}
diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs
index 03ea79b3b..4a459cac8 100644
--- a/MediaBrowser.Model/ApiClient/IApiClient.cs
+++ b/MediaBrowser.Model/ApiClient/IApiClient.cs
@@ -497,9 +497,11 @@ namespace MediaBrowser.Model.ApiClient
/// </summary>
/// <param name="itemId">The item id.</param>
/// <param name="userId">The user id.</param>
+ /// <param name="isSeekable">if set to <c>true</c> [is seekable].</param>
+ /// <param name="queueableMediaTypes">The list of media types that the client is capable of queuing onto the playlist. See MediaType class.</param>
/// <returns>Task{UserItemDataDto}.</returns>
/// <exception cref="ArgumentNullException">itemId</exception>
- Task ReportPlaybackStartAsync(string itemId, string userId);
+ Task ReportPlaybackStartAsync(string itemId, string userId, bool isSeekable, List<string> queueableMediaTypes);
/// <summary>
/// Reports playback progress to the server
diff --git a/MediaBrowser.Model/IO/IZipClient.cs b/MediaBrowser.Model/IO/IZipClient.cs
index c9e7e0db6..694c393aa 100644
--- a/MediaBrowser.Model/IO/IZipClient.cs
+++ b/MediaBrowser.Model/IO/IZipClient.cs
@@ -22,5 +22,21 @@ namespace MediaBrowser.Model.IO
/// <param name="targetPath">The target path.</param>
/// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
void ExtractAll(Stream source, string targetPath, bool overwriteExistingFiles);
+
+ /// <summary>
+ /// Extracts all from7z.
+ /// </summary>
+ /// <param name="sourceFile">The source file.</param>
+ /// <param name="targetPath">The target path.</param>
+ /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
+ void ExtractAllFrom7z(string sourceFile, string targetPath, bool overwriteExistingFiles);
+
+ /// <summary>
+ /// Extracts all from7z.
+ /// </summary>
+ /// <param name="source">The source.</param>
+ /// <param name="targetPath">The target path.</param>
+ /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
+ void ExtractAllFrom7z(Stream source, string targetPath, bool overwriteExistingFiles);
}
}
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 8fb471c2d..fa4fc2986 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -14,6 +14,8 @@
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<FodyPath>..\packages\Fody.1.17.0.0</FodyPath>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -162,14 +164,13 @@
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
- <Reference Include="PropertyChanged, Version=1.41.0.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\PropertyChanged.Fody.1.41.0.0\Lib\NET35\PropertyChanged.dll</HintPath>
- <Private>False</Private>
- </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime.Serialization" />
+ <Reference Include="PropertyChanged">
+ <HintPath>..\packages\PropertyChanged.Fody.1.41.0.0\Lib\NET35\PropertyChanged.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
diff --git a/MediaBrowser.Model/Session/SessionInfoDto.cs b/MediaBrowser.Model/Session/SessionInfoDto.cs
index f9b0e0abd..02b7f0226 100644
--- a/MediaBrowser.Model/Session/SessionInfoDto.cs
+++ b/MediaBrowser.Model/Session/SessionInfoDto.cs
@@ -1,12 +1,25 @@
-using System.ComponentModel;
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Entities;
using System;
+using System.Collections.Generic;
+using System.ComponentModel;
namespace MediaBrowser.Model.Session
{
public class SessionInfoDto : INotifyPropertyChanged
{
/// <summary>
+ /// Gets or sets a value indicating whether this instance can seek.
+ /// </summary>
+ /// <value><c>true</c> if this instance can seek; otherwise, <c>false</c>.</value>
+ public bool CanSeek { get; set; }
+
+ /// <summary>
+ /// Gets or sets the queueable media types.
+ /// </summary>
+ /// <value>The queueable media types.</value>
+ public List<string> QueueableMediaTypes { get; set; }
+
+ /// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
diff --git a/MediaBrowser.Mono.sln b/MediaBrowser.Mono.sln
new file mode 100644
index 000000000..0dc78ca2a
--- /dev/null
+++ b/MediaBrowser.Mono.sln
@@ -0,0 +1,68 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model", "MediaBrowser.Model\MediaBrowser.Model.csproj", "{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common", "MediaBrowser.Common\MediaBrowser.Common.csproj", "{9142EEFA-7570-41E1-BFCC-468BB571AF2F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common.Implementations", "MediaBrowser.Common.Implementations\MediaBrowser.Common.Implementations.csproj", "{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Controller", "MediaBrowser.Controller\MediaBrowser.Controller.csproj", "{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Providers", "MediaBrowser.Providers\MediaBrowser.Providers.csproj", "{442B5058-DCAF-4263-BB6A-F21E31120A1B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Implementations", "MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj", "{2E781478-814D-4A48-9D80-BFF206441A65}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.WebDashboard", "MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj", "{5624B7B5-B5A7-41D8-9F10-CC5611109619}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Api", "MediaBrowser.Api\MediaBrowser.Api.csproj", "{4FD51AC5-2C16-4308-A993-C3A84F3B4582}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Mono", "MediaBrowser.Server.Mono\MediaBrowser.Server.Mono.csproj", "{A7FE75CD-3CB4-4E71-A5BF-5347721EC8E0}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x86 = Debug|x86
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|x86.ActiveCfg = Debug|x86
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|x86.Build.0 = Debug|x86
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|x86.ActiveCfg = Release|x86
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|x86.Build.0 = Release|x86
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x86.Build.0 = Debug|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x86.ActiveCfg = Release|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x86.Build.0 = Release|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|x86.Build.0 = Debug|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|x86.ActiveCfg = Release|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|x86.Build.0 = Release|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|x86.Build.0 = Debug|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|x86.ActiveCfg = Release|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|x86.Build.0 = Release|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|x86.Build.0 = Debug|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.ActiveCfg = Release|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.Build.0 = Release|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|x86.Build.0 = Debug|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|x86.ActiveCfg = Release|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|x86.Build.0 = Release|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|x86.Build.0 = Debug|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|x86.ActiveCfg = Release|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|x86.Build.0 = Release|Any CPU
+ {A7FE75CD-3CB4-4E71-A5BF-5347721EC8E0}.Debug|x86.ActiveCfg = Debug|x86
+ {A7FE75CD-3CB4-4E71-A5BF-5347721EC8E0}.Debug|x86.Build.0 = Debug|x86
+ {A7FE75CD-3CB4-4E71-A5BF-5347721EC8E0}.Release|x86.ActiveCfg = Release|x86
+ {A7FE75CD-3CB4-4E71-A5BF-5347721EC8E0}.Release|x86.Build.0 = Release|x86
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|x86.Build.0 = Debug|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x86.ActiveCfg = Release|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = MediaBrowser.Server.Mono\MediaBrowser.Server.Mono.csproj
+ EndGlobalSection
+EndGlobal
diff --git a/MediaBrowser.Mono.userprefs b/MediaBrowser.Mono.userprefs
new file mode 100644
index 000000000..80da5915d
--- /dev/null
+++ b/MediaBrowser.Mono.userprefs
@@ -0,0 +1,19 @@
+<Properties>
+ <MonoDevelop.Ide.Workspace ActiveConfiguration="Debug|x86" />
+ <MonoDevelop.Ide.Workbench ActiveDocument="d:\Development\MediaBrowser\MediaBrowser.Server.Mono\Native\Sqlite.cs">
+ <Files>
+ <File FileName="MediaBrowser.Server.Mono\Program.cs" Line="1" Column="1" />
+ <File FileName="MediaBrowser.Server.Mono\MainWindow.cs" Line="8" Column="12" />
+ <File FileName="MediaBrowser.Server.Mono\Native\Autorun.cs" Line="17" Column="4" />
+ <File FileName="MediaBrowser.Server.Mono\Native\ServerAuthorization.cs" Line="23" Column="1" />
+ <File FileName="MediaBrowser.Server.Mono\FFMpeg\FFMpegDownloader.cs" Line="7" Column="14" />
+ <File FileName="MediaBrowser.ServerApplication\ApplicationHost.cs" Line="548" Column="61" />
+ <File FileName="MediaBrowser.Server.Mono\Native\NativeApp.cs" Line="22" Column="13" />
+ <File FileName="d:\Development\MediaBrowser\MediaBrowser.Server.Mono\Native\Sqlite.cs" Line="21" Column="14" />
+ </Files>
+ </MonoDevelop.Ide.Workbench>
+ <MonoDevelop.Ide.DebuggingService.Breakpoints>
+ <BreakpointStore />
+ </MonoDevelop.Ide.DebuggingService.Breakpoints>
+ <MonoDevelop.Ide.DebuggingService.PinnedWatches />
+</Properties> \ No newline at end of file
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 139c622fc..ef94d77d1 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -13,6 +13,8 @@
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -32,10 +34,6 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
- <Reference Include="MoreLinq, Version=1.0.16006.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll</HintPath>
- </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net" />
@@ -44,6 +42,9 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
+ <Reference Include="MoreLinq">
+ <HintPath>..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Extensions\XDocumentExtensions.cs" />
@@ -116,15 +117,15 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
- <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
+ <Project>{9142EEFA-7570-41E1-BFCC-468BB571AF2F}</Project>
<Name>MediaBrowser.Common</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
- <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
+ <Project>{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}</Project>
<Name>MediaBrowser.Controller</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
- <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
+ <Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfoProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfoProvider.cs
index 690c9b3ff..c28d06cbb 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfoProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfoProvider.cs
@@ -178,6 +178,7 @@ namespace MediaBrowser.Providers.MediaInfo
}
}
+ SetLastRefreshed(item, DateTime.UtcNow);
return true;
}
diff --git a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs
index fefcd8371..adc013699 100644
--- a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs
+++ b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs
@@ -1,5 +1,4 @@
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
diff --git a/MediaBrowser.Providers/Music/SoundtrackPostScanTask.cs b/MediaBrowser.Providers/Music/SoundtrackPostScanTask.cs
index 18868d3ea..e18351248 100644
--- a/MediaBrowser.Providers/Music/SoundtrackPostScanTask.cs
+++ b/MediaBrowser.Providers/Music/SoundtrackPostScanTask.cs
@@ -23,7 +23,9 @@ namespace MediaBrowser.Providers.Music
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
- return Task.Run(() => RunInternal(progress, cancellationToken));
+ RunInternal(progress, cancellationToken);
+
+ return Task.FromResult(true);
}
private void RunInternal(IProgress<double> progress, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs b/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs
index e6195c03e..bd63b5fbd 100644
--- a/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using System.Collections.Generic;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
@@ -58,7 +59,7 @@ namespace MediaBrowser.Providers.Savers
var xmlFilePath = GetSavePath(item);
- XmlSaverHelpers.Save(builder, xmlFilePath, new string[] { });
+ XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> { });
// Set last refreshed so that the provider doesn't trigger after the file save
PersonProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow);
diff --git a/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs b/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs
index 795e824fc..a27fb7363 100644
--- a/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using System.Collections.Generic;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
@@ -70,7 +71,7 @@ namespace MediaBrowser.Providers.Savers
var xmlFilePath = GetSavePath(item);
- XmlSaverHelpers.Save(builder, xmlFilePath, new string[] { });
+ XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> { });
// Set last refreshed so that the provider doesn't trigger after the file save
ArtistProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow);
diff --git a/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs b/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs
index f5fc37fe7..f09b34570 100644
--- a/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using System.Collections.Generic;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
@@ -57,7 +58,7 @@ namespace MediaBrowser.Providers.Savers
var xmlFilePath = GetSavePath(item);
- XmlSaverHelpers.Save(builder, xmlFilePath, new string[] { });
+ XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> { });
BoxSetProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow);
}
diff --git a/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs b/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs
index d90cb94c2..854c508b9 100644
--- a/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using System.Collections.Generic;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
@@ -87,7 +88,7 @@ namespace MediaBrowser.Providers.Savers
var xmlFilePath = GetSavePath(item);
- XmlSaverHelpers.Save(builder, xmlFilePath, new[]
+ XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
{
"FirstAired",
"SeasonNumber",
diff --git a/MediaBrowser.Providers/Savers/FolderXmlSaver.cs b/MediaBrowser.Providers/Savers/FolderXmlSaver.cs
index 23339ec75..6e95cc8c5 100644
--- a/MediaBrowser.Providers/Savers/FolderXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/FolderXmlSaver.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -77,7 +78,7 @@ namespace MediaBrowser.Providers.Savers
var xmlFilePath = GetSavePath(item);
- XmlSaverHelpers.Save(builder, xmlFilePath, new string[] { });
+ XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> { });
FolderProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow);
}
diff --git a/MediaBrowser.Providers/Savers/GameXmlSaver.cs b/MediaBrowser.Providers/Savers/GameXmlSaver.cs
index 41bd364c8..1e654f72f 100644
--- a/MediaBrowser.Providers/Savers/GameXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/GameXmlSaver.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using System.Collections.Generic;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Providers.Movies;
@@ -66,7 +67,7 @@ namespace MediaBrowser.Providers.Savers
if (!string.IsNullOrEmpty(game.GameSystem))
{
- builder.Append("<GameSystem><![CDATA[" + game.GameSystem + "]]></GameSystem>");
+ builder.Append("<GameSystem>" + SecurityElement.Escape(game.GameSystem) + "</GameSystem>");
}
XmlSaverHelpers.AddCommonNodes(item, builder);
@@ -75,7 +76,7 @@ namespace MediaBrowser.Providers.Savers
var xmlFilePath = GetSavePath(item);
- XmlSaverHelpers.Save(builder, xmlFilePath, new[]
+ XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
{
"Players",
"GameSystem"
diff --git a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs
index 2402bcd7f..761bcefd1 100644
--- a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using System.Collections.Generic;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
@@ -103,7 +104,7 @@ namespace MediaBrowser.Providers.Savers
var xmlFilePath = GetSavePath(item);
- XmlSaverHelpers.Save(builder, xmlFilePath, new[]
+ XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
{
"IMDBrating",
"Description",
diff --git a/MediaBrowser.Providers/Savers/PersonXmlSaver.cs b/MediaBrowser.Providers/Savers/PersonXmlSaver.cs
index 1b1377ac8..92f6db29b 100644
--- a/MediaBrowser.Providers/Savers/PersonXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/PersonXmlSaver.cs
@@ -1,4 +1,5 @@
-using System.Security;
+using System.Collections.Generic;
+using System.Security;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Providers.Movies;
@@ -57,7 +58,7 @@ namespace MediaBrowser.Providers.Savers
var xmlFilePath = GetSavePath(item);
- XmlSaverHelpers.Save(builder, xmlFilePath, new[]
+ XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
{
"PlaceOfBirth"
});
diff --git a/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs b/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs
index 97e8b671f..e484b3d39 100644
--- a/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
@@ -57,7 +58,7 @@ namespace MediaBrowser.Providers.Savers
var xmlFilePath = GetSavePath(item);
- XmlSaverHelpers.Save(builder, xmlFilePath, new string[] { });
+ XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> { });
SeasonProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow);
}
diff --git a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs
index 4e2f538c7..a4ff9c7d8 100644
--- a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using System.Collections.Generic;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
@@ -105,7 +106,7 @@ namespace MediaBrowser.Providers.Savers
var xmlFilePath = GetSavePath(item);
- XmlSaverHelpers.Save(builder, xmlFilePath, new[]
+ XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
{
"id",
"SeriesName",
@@ -113,7 +114,10 @@ namespace MediaBrowser.Providers.Savers
"Network",
"Airs_Time",
"Airs_DayOfWeek",
- "FirstAired"
+ "FirstAired",
+
+ // Don't preserve old series node
+ "Series"
});
// Set last refreshed so that the provider doesn't trigger after the file save
diff --git a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs
index cea7cf926..338447c10 100644
--- a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs
+++ b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs
@@ -29,13 +29,11 @@ namespace MediaBrowser.Providers.Savers
/// <param name="xml">The XML.</param>
/// <param name="path">The path.</param>
/// <param name="xmlTagsUsed">The XML tags used.</param>
- public static void Save(StringBuilder xml, string path, IEnumerable<string> xmlTagsUsed)
+ public static void Save(StringBuilder xml, string path, List<string> xmlTagsUsed)
{
if (File.Exists(path))
{
- var tags = xmlTagsUsed.ToList();
-
- tags.AddRange(new[]
+ xmlTagsUsed.AddRange(new[]
{
"MediaInfo",
"ContentRating",
@@ -88,7 +86,7 @@ namespace MediaBrowser.Providers.Savers
});
var position = xml.ToString().LastIndexOf("</", StringComparison.OrdinalIgnoreCase);
- xml.Insert(position, GetCustomTags(path, tags));
+ xml.Insert(position, GetCustomTags(path, xmlTagsUsed));
}
var xmlDocument = new XmlDocument();
@@ -142,17 +140,46 @@ namespace MediaBrowser.Providers.Savers
/// <param name="path">The path.</param>
/// <param name="xmlTagsUsed">The XML tags used.</param>
/// <returns>System.String.</returns>
- private static string GetCustomTags(string path, ICollection<string> xmlTagsUsed)
+ private static string GetCustomTags(string path, IEnumerable<string> xmlTagsUsed)
{
- var doc = new XmlDocument();
- doc.Load(path);
+ var settings = new XmlReaderSettings
+ {
+ CheckCharacters = false,
+ IgnoreProcessingInstructions = true,
+ IgnoreComments = true,
+ ValidationType = ValidationType.None
+ };
+
+ var tagsDictionary = xmlTagsUsed.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
- var nodes = doc.DocumentElement.ChildNodes.Cast<XmlNode>()
- .Where(i => !xmlTagsUsed.Contains(i.Name))
- .Select(i => i.OuterXml)
- .ToArray();
+ var builder = new StringBuilder();
+
+ using (var streamReader = new StreamReader(path, Encoding.UTF8))
+ {
+ // Use XmlReader for best performance
+ using (var reader = XmlReader.Create(streamReader, settings))
+ {
+ reader.MoveToContent();
- return string.Join(Environment.NewLine, nodes);
+ // Loop through each element
+ while (reader.Read())
+ {
+ if (reader.NodeType == XmlNodeType.Element)
+ {
+ if (!tagsDictionary.ContainsKey(reader.Name))
+ {
+ builder.AppendLine(reader.ReadOuterXml());
+ }
+ else
+ {
+ reader.Skip();
+ }
+ }
+ }
+ }
+ }
+
+ return builder.ToString();
}
/// <summary>
diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
index a781551de..2b73ba1f7 100644
--- a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
+++ b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
@@ -21,7 +21,9 @@ namespace MediaBrowser.Providers.TV
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
- return Task.Run(() => RunInternal(progress, cancellationToken));
+ RunInternal(progress, cancellationToken);
+
+ return Task.FromResult(true);
}
private void RunInternal(IProgress<double> progress, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
index 1f7361d2f..305bede56 100644
--- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
@@ -121,7 +121,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
}
catch (IOException)
{
- // Cache file doesn't exist or is currently being written ro
+ // Cache file doesn't exist or is currently being written to
}
var semaphore = GetLock(cacheFilePath);
@@ -129,21 +129,24 @@ namespace MediaBrowser.Server.Implementations.Drawing
await semaphore.WaitAsync().ConfigureAwait(false);
// Check again in case of lock contention
- if (File.Exists(cacheFilePath))
+ try
{
- try
- {
- using (var fileStream = new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
- {
- await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
- return;
- }
- }
- finally
+ using (var fileStream = new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
{
+ await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
semaphore.Release();
+ return;
}
}
+ catch (IOException)
+ {
+ // Cache file doesn't exist or is currently being written to
+ }
+ catch
+ {
+ semaphore.Release();
+ throw;
+ }
try
{
@@ -188,12 +191,10 @@ namespace MediaBrowser.Server.Implementations.Drawing
var bytes = outputMemoryStream.ToArray();
- var outputTask = toStream.WriteAsync(bytes, 0, bytes.Length);
+ await toStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
// kick off a task to cache the result
- var cacheTask = CacheResizedImage(cacheFilePath, bytes);
-
- await Task.WhenAll(outputTask, cacheTask).ConfigureAwait(false);
+ CacheResizedImage(cacheFilePath, bytes, semaphore);
}
}
}
@@ -202,13 +203,52 @@ namespace MediaBrowser.Server.Implementations.Drawing
}
}
}
- finally
+ catch
{
semaphore.Release();
+
+ throw;
}
}
/// <summary>
+ /// Caches the resized image.
+ /// </summary>
+ /// <param name="cacheFilePath">The cache file path.</param>
+ /// <param name="bytes">The bytes.</param>
+ /// <param name="semaphore">The semaphore.</param>
+ private void CacheResizedImage(string cacheFilePath, byte[] bytes, SemaphoreSlim semaphore)
+ {
+ Task.Run(async () =>
+ {
+ try
+ {
+ var parentPath = Path.GetDirectoryName(cacheFilePath);
+
+ if (!Directory.Exists(parentPath))
+ {
+ Directory.CreateDirectory(parentPath);
+ }
+
+ // Save to the cache location
+ using (var cacheFileStream = new FileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+ {
+ // Save to the filestream
+ await cacheFileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error writing to image cache file {0}", ex, cacheFilePath);
+ }
+ finally
+ {
+ semaphore.Release();
+ }
+ });
+ }
+
+ /// <summary>
/// Sets the color of the background.
/// </summary>
/// <param name="graphics">The graphics.</param>
@@ -364,28 +404,6 @@ namespace MediaBrowser.Server.Implementations.Drawing
}
/// <summary>
- /// Caches the resized image.
- /// </summary>
- /// <param name="cacheFilePath">The cache file path.</param>
- /// <param name="bytes">The bytes.</param>
- private async Task CacheResizedImage(string cacheFilePath, byte[] bytes)
- {
- var parentPath = Path.GetDirectoryName(cacheFilePath);
-
- if (!Directory.Exists(parentPath))
- {
- Directory.CreateDirectory(parentPath);
- }
-
- // Save to the cache location
- using (var cacheFileStream = new FileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
- {
- // Save to the filestream
- await cacheFileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
- }
- }
-
- /// <summary>
/// Gets the cache file path based on a set of parameters
/// </summary>
private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, ImageOutputFormat format, ImageOverlay? overlay, int percentPlayed, string backgroundColor)
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
index e5260004a..a5f54b938 100644
--- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs
+++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
@@ -237,7 +237,9 @@ namespace MediaBrowser.Server.Implementations.Dto
NowViewingItemId = session.NowViewingItemId,
NowViewingItemName = session.NowViewingItemName,
NowViewingItemType = session.NowViewingItemType,
- ApplicationVersion = session.ApplicationVersion
+ ApplicationVersion = session.ApplicationVersion,
+ CanSeek = session.CanSeek,
+ QueueableMediaTypes = session.QueueableMediaTypes
};
if (session.NowPlayingItem != null)
diff --git a/MediaBrowser.ServerApplication/EntryPoints/UdpServerEntryPoint.cs b/MediaBrowser.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
index 595d5c89f..9c1a953b1 100644
--- a/MediaBrowser.ServerApplication/EntryPoints/UdpServerEntryPoint.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Server.Implementations.Udp;
using System.Net.Sockets;
-namespace MediaBrowser.ServerApplication.EntryPoints
+namespace MediaBrowser.Server.Implementations.EntryPoints
{
/// <summary>
/// Class UdpServerEntryPoint
@@ -35,6 +35,8 @@ namespace MediaBrowser.ServerApplication.EntryPoints
/// </summary>
private readonly IHttpServer _httpServer;
+ public const int PortNumber = 7359;
+
/// <summary>
/// Initializes a new instance of the <see cref="UdpServerEntryPoint"/> class.
/// </summary>
@@ -59,7 +61,7 @@ namespace MediaBrowser.ServerApplication.EntryPoints
try
{
- udpServer.Start(ApplicationHost.UdpServerPort);
+ udpServer.Start(PortNumber);
UdpServer = udpServer;
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs
index f6547dec1..4f795fdd5 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs
@@ -314,6 +314,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// <param name="context">The CTX.</param>
private async void ProcessHttpRequestAsync(HttpListenerContext context)
{
+ var date = DateTime.Now;
+
LogHttpRequest(context);
if (context.Request.IsWebSocketRequest)
@@ -360,7 +362,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
var url = context.Request.Url.ToString();
var endPoint = context.Request.RemoteEndPoint;
- LogResponse(context, url, endPoint);
+ var duration = DateTime.Now - date;
+
+ LogResponse(context, url, endPoint, duration);
}
catch (Exception ex)
@@ -461,14 +465,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// <param name="ctx">The CTX.</param>
/// <param name="url">The URL.</param>
/// <param name="endPoint">The end point.</param>
- private void LogResponse(HttpListenerContext ctx, string url, IPEndPoint endPoint)
+ /// <param name="duration">The duration.</param>
+ private void LogResponse(HttpListenerContext ctx, string url, IPEndPoint endPoint, TimeSpan duration)
{
if (!EnableHttpRequestLogging)
{
return;
}
- var statusode = ctx.Response.StatusCode;
+ var statusCode = ctx.Response.StatusCode;
var log = new StringBuilder();
@@ -476,7 +481,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
log.AppendLine("Headers: " + string.Join(",", ctx.Response.Headers.AllKeys.Select(k => k + "=" + ctx.Response.Headers[k])));
- var msg = "Http Response Sent (" + statusode + ") to " + endPoint;
+ var responseTime = string.Format(". Response time: {0} ms", duration.TotalMilliseconds);
+
+ var msg = "Response code " + statusCode + " sent to " + endPoint + responseTime;
_logger.LogMultiline(msg, LogSeverity.Debug, log);
}
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index a5b792726..1bc3f1094 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -829,10 +829,6 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>Task.</returns>
public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
{
- const int maxTasks = 3;
-
- var tasks = new List<Task>();
-
var people = RootFolder.RecursiveChildren
.SelectMany(c => c.People)
.DistinctBy(p => p.Name, StringComparer.OrdinalIgnoreCase)
@@ -842,47 +838,27 @@ namespace MediaBrowser.Server.Implementations.Library
foreach (var person in people)
{
- if (tasks.Count > maxTasks)
+ cancellationToken.ThrowIfCancellationRequested();
+
+ try
{
- await Task.WhenAll(tasks).ConfigureAwait(false);
- tasks.Clear();
+ var item = GetPerson(person.Name);
- // Safe cancellation point, when there are no pending tasks
- cancellationToken.ThrowIfCancellationRequested();
+ await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
}
-
- // Avoid accessing the foreach variable within the closure
- var currentPerson = person;
-
- tasks.Add(Task.Run(async () =>
+ catch (IOException ex)
{
- cancellationToken.ThrowIfCancellationRequested();
-
- try
- {
- var item = GetPerson(currentPerson.Name);
-
- await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (IOException ex)
- {
- _logger.ErrorException("Error validating IBN entry {0}", ex, currentPerson.Name);
- }
+ _logger.ErrorException("Error validating IBN entry {0}", ex, person.Name);
+ }
- // Update progress
- lock (progress)
- {
- numComplete++;
- double percent = numComplete;
- percent /= people.Count;
+ // Update progress
+ numComplete++;
+ double percent = numComplete;
+ percent /= people.Count;
- progress.Report(100 * percent);
- }
- }));
+ progress.Report(100 * percent);
}
- await Task.WhenAll(tasks).ConfigureAwait(false);
-
progress.Report(100);
_logger.Info("People validation complete");
@@ -956,7 +932,9 @@ namespace MediaBrowser.Server.Implementations.Library
public Task ValidateMediaLibrary(IProgress<double> progress, CancellationToken cancellationToken)
{
// Just run the scheduled task so that the user can see it
- return Task.Run(() => _taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>());
+ _taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
+
+ return Task.FromResult(true);
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs
index eb89210ff..b9e033d23 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs
@@ -41,8 +41,6 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
- var allItems = _libraryManager.RootFolder.RecursiveChildren.OfType<Game>().ToList();
-
var userLibraries = _userManager.Users
.Select(i => new Tuple<Guid, List<Game>>(i.Id, i.RootFolder.GetRecursiveChildren(i).OfType<Game>().ToList()))
.ToList();
@@ -79,6 +77,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
{
await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false);
}
+ catch (OperationCanceledException)
+ {
+ // Don't clutter the log
+ }
catch (Exception ex)
{
_logger.ErrorException("Error updating counts for {0}", ex, name);
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs
index 9a34dd1b0..e4d989c33 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs
@@ -42,16 +42,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
- var allItems = _libraryManager.RootFolder.RecursiveChildren
- .Where(i => !(i is IHasMusicGenres) && !(i is Game))
- .ToList();
-
var userLibraries = _userManager.Users
.Select(i => new Tuple<Guid, List<BaseItem>>(i.Id, i.RootFolder.GetRecursiveChildren(i).Where(m => !(m is IHasMusicGenres) && !(m is Game)).ToList()))
.ToList();
- var allLibraryItems = allItems;
-
var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>>(StringComparer.OrdinalIgnoreCase);
// Populate counts of items
@@ -84,6 +78,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
{
await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false);
}
+ catch (OperationCanceledException)
+ {
+ // Don't clutter the log
+ }
catch (Exception ex)
{
_logger.ErrorException("Error updating counts for {0}", ex, name);
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs
index 1b211d5f4..1edc24762 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs
@@ -42,16 +42,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
- var allItems = _libraryManager.RootFolder.RecursiveChildren
- .Where(i => i is IHasMusicGenres)
- .ToList();
-
var userLibraries = _userManager.Users
.Select(i => new Tuple<Guid, List<BaseItem>>(i.Id, i.RootFolder.GetRecursiveChildren(i).Where(m => m is IHasMusicGenres).ToList()))
.ToList();
- var allLibraryItems = allItems;
-
var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>>(StringComparer.OrdinalIgnoreCase);
// Populate counts of items
@@ -84,6 +78,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
{
await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false);
}
+ catch (OperationCanceledException)
+ {
+ // Don't clutter the log
+ }
catch (Exception ex)
{
_logger.ErrorException("Error updating counts for {0}", ex, name);
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs
index efefaeba3..dc96632f6 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs
@@ -41,7 +41,9 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
/// <returns>Task.</returns>
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
- return Task.Run(() => RunInternal(progress, cancellationToken));
+ RunInternal(progress, cancellationToken);
+
+ return Task.FromResult(true);
}
private void RunInternal(IProgress<double> progress, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
index a4d880329..05689f8e5 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
@@ -41,14 +41,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
- var allItems = _libraryManager.RootFolder.RecursiveChildren.ToList();
-
var userLibraries = _userManager.Users
.Select(i => new Tuple<Guid, List<BaseItem>>(i.Id, i.RootFolder.GetRecursiveChildren(i).ToList()))
.ToList();
- var allLibraryItems = allItems;
-
var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>>(StringComparer.OrdinalIgnoreCase);
// Populate counts of items
@@ -81,6 +77,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
{
await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false);
}
+ catch (OperationCanceledException)
+ {
+ // Don't clutter the log
+ }
catch (Exception ex)
{
_logger.ErrorException("Error updating counts for {0}", ex, name);
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 9d2fc8c6b..f409b7205 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -13,6 +13,8 @@
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -35,77 +37,65 @@
<Reference Include="Alchemy">
<HintPath>..\packages\Alchemy.2.2.1\lib\net40\Alchemy.dll</HintPath>
</Reference>
- <Reference Include="BdInfo, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.2\lib\net45\BdInfo.dll</HintPath>
- </Reference>
<Reference Include="ICSharpCode.SharpZipLib">
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="Lucene.Net">
<HintPath>..\packages\Lucene.Net.3.0.3\lib\NET40\Lucene.Net.dll</HintPath>
</Reference>
- <Reference Include="MoreLinq, Version=1.0.16006.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Reactive.Core">
+ <HintPath>..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Reactive.Interfaces">
+ <HintPath>..\packages\Rx-Interfaces.2.1.30214.0\lib\Net45\System.Reactive.Interfaces.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Reactive.Linq">
+ <HintPath>..\packages\Rx-Linq.2.1.30214.0\lib\Net45\System.Reactive.Linq.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Runtime.Serialization" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Web" />
+ <Reference Include="System.Xml" />
+ <Reference Include="BDInfo">
+ <HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.2\lib\net45\BdInfo.dll</HintPath>
+ </Reference>
+ <Reference Include="MoreLinq">
<HintPath>..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack, Version=3.9.60.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="ServiceStack">
<HintPath>..\packages\ServiceStack.3.9.62\lib\net35\ServiceStack.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.Api.Swagger, Version=3.9.59.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="ServiceStack.Api.Swagger">
<HintPath>..\packages\ServiceStack.Api.Swagger.3.9.59\lib\net35\ServiceStack.Api.Swagger.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.Common, Version=3.9.60.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="ServiceStack.Common">
<HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Common.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.Interfaces, Version=3.9.60.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="ServiceStack.Interfaces">
<HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Interfaces.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.OrmLite.SqlServer, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="ServiceStack.OrmLite.SqlServer">
<HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.43\lib\ServiceStack.OrmLite.SqlServer.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.Redis, Version=3.9.43.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="ServiceStack.Redis">
<HintPath>..\packages\ServiceStack.Redis.3.9.43\lib\net35\ServiceStack.Redis.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.ServiceInterface, Version=3.9.60.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="ServiceStack.ServiceInterface">
<HintPath>..\packages\ServiceStack.3.9.62\lib\net35\ServiceStack.ServiceInterface.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.Text, Version=3.9.59.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="ServiceStack.Text">
<HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
</Reference>
- <Reference Include="System" />
- <Reference Include="System.Core" />
- <Reference Include="System.Data.SQLite, Version=1.0.88.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=x86">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="System.Data.SQLite">
<HintPath>..\packages\System.Data.SQLite.x86.1.0.88.0\lib\net45\System.Data.SQLite.dll</HintPath>
</Reference>
- <Reference Include="System.Data.SQLite.Linq, Version=1.0.88.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="System.Data.SQLite.Linq">
<HintPath>..\packages\System.Data.SQLite.x86.1.0.88.0\lib\net45\System.Data.SQLite.Linq.dll</HintPath>
</Reference>
- <Reference Include="System.Drawing" />
- <Reference Include="System.Reactive.Core">
- <HintPath>..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll</HintPath>
- </Reference>
- <Reference Include="System.Reactive.Interfaces">
- <HintPath>..\packages\Rx-Interfaces.2.1.30214.0\lib\Net45\System.Reactive.Interfaces.dll</HintPath>
- </Reference>
- <Reference Include="System.Reactive.Linq">
- <HintPath>..\packages\Rx-Linq.2.1.30214.0\lib\Net45\System.Reactive.Linq.dll</HintPath>
- </Reference>
- <Reference Include="System.Runtime.Serialization" />
- <Reference Include="Microsoft.CSharp" />
- <Reference Include="System.Data" />
- <Reference Include="System.Web" />
- <Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
@@ -123,6 +113,7 @@
<Compile Include="EntryPoints\Notifications\RemoteNotifications.cs" />
<Compile Include="EntryPoints\Notifications\WebSocketNotifier.cs" />
<Compile Include="EntryPoints\RefreshUsersMetadata.cs" />
+ <Compile Include="EntryPoints\UdpServerEntryPoint.cs" />
<Compile Include="EntryPoints\WebSocketEvents.cs" />
<Compile Include="HttpServer\HttpResultFactory.cs" />
<Compile Include="HttpServer\HttpServer.cs" />
@@ -183,6 +174,7 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="Session\SessionWebSocketListener.cs" />
+ <Compile Include="Session\WebSocketController.cs" />
<Compile Include="Sorting\AlbumArtistComparer.cs" />
<Compile Include="Sorting\AlbumComparer.cs" />
<Compile Include="Sorting\AlbumCountComparer.cs" />
@@ -222,19 +214,19 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MediaBrowser.Common.Implementations\MediaBrowser.Common.Implementations.csproj">
- <Project>{c4d2573a-3fd3-441f-81af-174ac4cd4e1d}</Project>
+ <Project>{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}</Project>
<Name>MediaBrowser.Common.Implementations</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
- <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
+ <Project>{9142EEFA-7570-41E1-BFCC-468BB571AF2F}</Project>
<Name>MediaBrowser.Common</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
- <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
+ <Project>{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}</Project>
<Name>MediaBrowser.Controller</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
- <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
+ <Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
index b24c9a5ca..2f353b8c0 100644
--- a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
+++ b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
@@ -57,7 +57,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
/// <summary>
/// The FF probe resource pool
/// </summary>
- private readonly SemaphoreSlim _ffProbeResourcePool = new SemaphoreSlim(2, 2);
+ private readonly SemaphoreSlim _ffProbeResourcePool = new SemaphoreSlim(1, 1);
public string FFMpegPath { get; private set; }
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
index f4f5f08e4..9c5cf6f1c 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
@@ -333,17 +333,16 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// <returns>Task.</returns>
public Task SaveCriticReviews(Guid itemId, IEnumerable<ItemReview> criticReviews)
{
- return Task.Run(() =>
+ if (!Directory.Exists(_criticReviewsPath))
{
- if (!Directory.Exists(_criticReviewsPath))
- {
- Directory.CreateDirectory(_criticReviewsPath);
- }
+ Directory.CreateDirectory(_criticReviewsPath);
+ }
- var path = Path.Combine(_criticReviewsPath, itemId + ".json");
+ var path = Path.Combine(_criticReviewsPath, itemId + ".json");
+
+ _jsonSerializer.SerializeToFile(criticReviews.ToList(), path);
- _jsonSerializer.SerializeToFile(criticReviews.ToList(), path);
- });
+ return Task.FromResult(true);
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs b/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs
index 608738f7f..d8872f318 100644
--- a/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs
+++ b/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs
@@ -102,6 +102,18 @@ namespace MediaBrowser.Server.Implementations.Providers
using (source)
{
+ // If the file is currently hidden we'll have to remove that or the save will fail
+ var file = new FileInfo(path);
+
+ // This will fail if the file is hidden
+ if (file.Exists)
+ {
+ if ((file.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
+ {
+ file.Attributes &= ~FileAttributes.Hidden;
+ }
+ }
+
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
{
await source.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
index d9b88368b..4829dc405 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
@@ -159,6 +159,10 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
{
previouslyFailedImages = new List<string>();
}
+ catch (DirectoryNotFoundException)
+ {
+ previouslyFailedImages = new List<string>();
+ }
foreach (var video in videos)
{
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index ce757d142..79dfbc8a5 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -6,6 +7,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Session;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -75,6 +77,12 @@ namespace MediaBrowser.Server.Implementations.Session
_userRepository = userRepository;
}
+ private List<ISessionRemoteController> _remoteControllers;
+ public void AddParts(IEnumerable<ISessionRemoteController> remoteControllers)
+ {
+ _remoteControllers = remoteControllers.ToList();
+ }
+
/// <summary>
/// Gets all connections.
/// </summary>
@@ -122,7 +130,7 @@ namespace MediaBrowser.Server.Implementations.Session
var activityDate = DateTime.UtcNow;
var session = GetSessionInfo(clientType, appVersion, deviceId, deviceName, user);
-
+
session.LastActivityDate = activityDate;
if (user == null)
@@ -207,25 +215,33 @@ namespace MediaBrowser.Server.Implementations.Session
/// <summary>
/// Used to report that playback has started for an item
/// </summary>
- /// <param name="item">The item.</param>
- /// <param name="sessionId">The session id.</param>
+ /// <param name="info">The info.</param>
/// <returns>Task.</returns>
- /// <exception cref="System.ArgumentNullException"></exception>
- public async Task OnPlaybackStart(BaseItem item, Guid sessionId)
+ /// <exception cref="System.ArgumentNullException">info</exception>
+ public async Task OnPlaybackStart(PlaybackInfo info)
{
- if (item == null)
+ if (info == null)
{
- throw new ArgumentNullException();
+ throw new ArgumentNullException("info");
+ }
+ if (info.SessionId == Guid.Empty)
+ {
+ throw new ArgumentNullException("info");
}
- var session = Sessions.First(i => i.Id.Equals(sessionId));
+ var session = Sessions.First(i => i.Id.Equals(info.SessionId));
+
+ var item = info.Item;
UpdateNowPlayingItem(session, item, false, false);
+ session.CanSeek = info.CanSeek;
+ session.QueueableMediaTypes = info.QueueableMediaTypes;
+
var key = item.GetUserDataKey();
var user = session.User;
-
+
var data = _userDataRepository.GetUserData(user.Id, key);
data.PlayCount++;
@@ -313,7 +329,7 @@ namespace MediaBrowser.Server.Implementations.Session
{
throw new ArgumentOutOfRangeException("positionTicks");
}
-
+
var session = Sessions.First(i => i.Id.Equals(sessionId));
RemoveNowPlayingItem(session, item);
@@ -321,7 +337,7 @@ namespace MediaBrowser.Server.Implementations.Session
var key = item.GetUserDataKey();
var user = session.User;
-
+
var data = _userDataRepository.GetUserData(user.Id, key);
if (positionTicks.HasValue)
@@ -400,5 +416,118 @@ namespace MediaBrowser.Server.Implementations.Session
data.PlaybackPositionTicks = positionTicks;
}
+
+ /// <summary>
+ /// Gets the session for remote control.
+ /// </summary>
+ /// <param name="sessionId">The session id.</param>
+ /// <returns>SessionInfo.</returns>
+ /// <exception cref="ResourceNotFoundException"></exception>
+ private SessionInfo GetSessionForRemoteControl(Guid sessionId)
+ {
+ var session = Sessions.First(i => i.Id.Equals(sessionId));
+
+ if (session == null)
+ {
+ throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId));
+ }
+
+ if (!session.SupportsRemoteControl)
+ {
+ throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id));
+ }
+
+ return session;
+ }
+
+ /// <summary>
+ /// Gets the controllers.
+ /// </summary>
+ /// <param name="session">The session.</param>
+ /// <returns>IEnumerable{ISessionRemoteController}.</returns>
+ private IEnumerable<ISessionRemoteController> GetControllers(SessionInfo session)
+ {
+ return _remoteControllers.Where(i => i.Supports(session));
+ }
+
+ /// <summary>
+ /// Sends the system command.
+ /// </summary>
+ /// <param name="sessionId">The session id.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ public Task SendSystemCommand(Guid sessionId, SystemCommand command, CancellationToken cancellationToken)
+ {
+ var session = GetSessionForRemoteControl(sessionId);
+
+ var tasks = GetControllers(session).Select(i => i.SendSystemCommand(session, command, cancellationToken));
+
+ return Task.WhenAll(tasks);
+ }
+
+ /// <summary>
+ /// Sends the message command.
+ /// </summary>
+ /// <param name="sessionId">The session id.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ public Task SendMessageCommand(Guid sessionId, MessageCommand command, CancellationToken cancellationToken)
+ {
+ var session = GetSessionForRemoteControl(sessionId);
+
+ var tasks = GetControllers(session).Select(i => i.SendMessageCommand(session, command, cancellationToken));
+
+ return Task.WhenAll(tasks);
+ }
+
+ /// <summary>
+ /// Sends the play command.
+ /// </summary>
+ /// <param name="sessionId">The session id.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ public Task SendPlayCommand(Guid sessionId, PlayRequest command, CancellationToken cancellationToken)
+ {
+ var session = GetSessionForRemoteControl(sessionId);
+
+ var tasks = GetControllers(session).Select(i => i.SendPlayCommand(session, command, cancellationToken));
+
+ return Task.WhenAll(tasks);
+ }
+
+ /// <summary>
+ /// Sends the browse command.
+ /// </summary>
+ /// <param name="sessionId">The session id.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ public Task SendBrowseCommand(Guid sessionId, BrowseRequest command, CancellationToken cancellationToken)
+ {
+ var session = GetSessionForRemoteControl(sessionId);
+
+ var tasks = GetControllers(session).Select(i => i.SendBrowseCommand(session, command, cancellationToken));
+
+ return Task.WhenAll(tasks);
+ }
+
+ /// <summary>
+ /// Sends the playstate command.
+ /// </summary>
+ /// <param name="sessionId">The session id.</param>
+ /// <param name="command">The command.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ public Task SendPlaystateCommand(Guid sessionId, PlaystateRequest command, CancellationToken cancellationToken)
+ {
+ var session = GetSessionForRemoteControl(sessionId);
+
+ var tasks = GetControllers(session).Select(i => i.SendPlaystateCommand(session, command, cancellationToken));
+
+ return Task.WhenAll(tasks);
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
index 2a4361e61..95eb5948f 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
@@ -101,16 +101,7 @@ namespace MediaBrowser.Server.Implementations.Session
}
else if (string.Equals(message.MessageType, "PlaybackStart", StringComparison.OrdinalIgnoreCase))
{
- _logger.Debug("Received PlaybackStart message");
-
- var session = _sessionManager.Sessions.FirstOrDefault(i => i.WebSockets.Contains(message.Connection));
-
- if (session != null && session.User != null)
- {
- var item = _dtoService.GetItemByDtoId(message.Data);
-
- _sessionManager.OnPlaybackStart(item, session.Id);
- }
+ ReportPlaybackStart(message);
}
else if (string.Equals(message.MessageType, "PlaybackProgress", StringComparison.OrdinalIgnoreCase))
{
@@ -170,5 +161,46 @@ namespace MediaBrowser.Server.Implementations.Session
return _trueTaskResult;
}
+
+ /// <summary>
+ /// Reports the playback start.
+ /// </summary>
+ /// <param name="message">The message.</param>
+ private void ReportPlaybackStart(WebSocketMessageInfo message)
+ {
+ _logger.Debug("Received PlaybackStart message");
+
+ var session = _sessionManager.Sessions
+ .FirstOrDefault(i => i.WebSockets.Contains(message.Connection));
+
+ if (session != null && session.User != null)
+ {
+ var vals = message.Data.Split('|');
+
+ var item = _dtoService.GetItemByDtoId(vals[0]);
+
+ var queueableMediaTypes = string.Empty;
+ var canSeek = true;
+
+ if (vals.Length > 1)
+ {
+ canSeek = string.Equals(vals[1], "true", StringComparison.OrdinalIgnoreCase);
+ }
+ if (vals.Length > 2)
+ {
+ queueableMediaTypes = vals[2];
+ }
+
+ var info = new PlaybackInfo
+ {
+ CanSeek = canSeek,
+ Item = item,
+ SessionId = session.Id,
+ QueueableMediaTypes = queueableMediaTypes.Split(',').ToList()
+ };
+
+ _sessionManager.OnPlaybackStart(info);
+ }
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
new file mode 100644
index 000000000..6915cfc64
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
@@ -0,0 +1,92 @@
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Net;
+using MediaBrowser.Model.Session;
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Session
+{
+ public class WebSocketController : ISessionRemoteController
+ {
+ public bool Supports(SessionInfo session)
+ {
+ return session.WebSockets.Any(i => i.State == WebSocketState.Open);
+ }
+
+ private IWebSocketConnection GetSocket(SessionInfo session)
+ {
+ var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open);
+
+
+ if (socket == null)
+ {
+ throw new InvalidOperationException("The requested session does not have an open web socket.");
+ }
+
+ return socket;
+ }
+
+ public Task SendSystemCommand(SessionInfo session, SystemCommand command, CancellationToken cancellationToken)
+ {
+ var socket = GetSocket(session);
+
+ return socket.SendAsync(new WebSocketMessage<string>
+ {
+ MessageType = "SystemCommand",
+ Data = command.ToString()
+
+ }, cancellationToken);
+ }
+
+ public Task SendMessageCommand(SessionInfo session, MessageCommand command, CancellationToken cancellationToken)
+ {
+ var socket = GetSocket(session);
+
+ return socket.SendAsync(new WebSocketMessage<MessageCommand>
+ {
+ MessageType = "MessageCommand",
+ Data = command
+
+ }, cancellationToken);
+ }
+
+ public Task SendPlayCommand(SessionInfo session, PlayRequest command, CancellationToken cancellationToken)
+ {
+ var socket = GetSocket(session);
+
+ return socket.SendAsync(new WebSocketMessage<PlayRequest>
+ {
+ MessageType = "Play",
+ Data = command
+
+ }, cancellationToken);
+ }
+
+ public Task SendBrowseCommand(SessionInfo session, BrowseRequest command, CancellationToken cancellationToken)
+ {
+ var socket = GetSocket(session);
+
+ return socket.SendAsync(new WebSocketMessage<BrowseRequest>
+ {
+ MessageType = "Browse",
+ Data = command
+
+ }, cancellationToken);
+ }
+
+ public Task SendPlaystateCommand(SessionInfo session, PlaystateRequest command, CancellationToken cancellationToken)
+ {
+ var socket = GetSocket(session);
+
+ return socket.SendAsync(new WebSocketMessage<PlaystateRequest>
+ {
+ MessageType = "Playstate",
+ Data = command
+
+ }, cancellationToken);
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/WebSocket/AlchemyWebSocket.cs b/MediaBrowser.Server.Implementations/WebSocket/AlchemyWebSocket.cs
index 958201625..de998254c 100644
--- a/MediaBrowser.Server.Implementations/WebSocket/AlchemyWebSocket.cs
+++ b/MediaBrowser.Server.Implementations/WebSocket/AlchemyWebSocket.cs
@@ -92,7 +92,9 @@ namespace MediaBrowser.Server.Implementations.WebSocket
/// <returns>Task.</returns>
public Task SendAsync(byte[] bytes, WebSocketMessageType type, bool endOfMessage, CancellationToken cancellationToken)
{
- return Task.Run(() => UserContext.Send(bytes));
+ UserContext.Send(bytes);
+
+ return Task.FromResult(true);
}
/// <summary>
diff --git a/MediaBrowser.Server.Mono/FFMpeg/FFMpegDownloader.cs b/MediaBrowser.Server.Mono/FFMpeg/FFMpegDownloader.cs
new file mode 100644
index 000000000..cc268ef07
--- /dev/null
+++ b/MediaBrowser.Server.Mono/FFMpeg/FFMpegDownloader.cs
@@ -0,0 +1,36 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Net;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.ServerApplication.FFMpeg
+{
+ public class FFMpegDownloader
+ {
+ private readonly IHttpClient _httpClient;
+ private readonly IApplicationPaths _appPaths;
+ private readonly ILogger _logger;
+ private readonly IZipClient _zipClient;
+
+ public FFMpegDownloader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient)
+ {
+ _logger = logger;
+ _appPaths = appPaths;
+ _httpClient = httpClient;
+ _zipClient = zipClient;
+ }
+
+ public Task<FFMpegInfo> GetFFMpegInfo()
+ {
+ return Task.FromResult (new FFMpegInfo());
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Mono/MainWindow.cs b/MediaBrowser.Server.Mono/MainWindow.cs
new file mode 100644
index 000000000..229f44dab
--- /dev/null
+++ b/MediaBrowser.Server.Mono/MainWindow.cs
@@ -0,0 +1,16 @@
+using System;
+using Gtk;
+
+public partial class MainWindow: Gtk.Window
+{
+ public MainWindow (): base (Gtk.WindowType.Toplevel)
+ {
+ Build ();
+ }
+
+ protected void OnDeleteEvent (object sender, DeleteEventArgs a)
+ {
+ Application.Quit ();
+ a.RetVal = true;
+ }
+}
diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
new file mode 100644
index 000000000..1c369daac
--- /dev/null
+++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{A7FE75CD-3CB4-4E71-A5BF-5347721EC8E0}</ProjectGuid>
+ <OutputType>WinExe</OutputType>
+ <RootNamespace>MediaBrowser.Server.Mono</RootNamespace>
+ <AssemblyName>MediaBrowser.Server.Mono</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <PlatformTarget>x86</PlatformTarget>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <DebugType>full</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <PlatformTarget>x86</PlatformTarget>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="Mono.Posix, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
+ <Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+ <Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+ <Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+ <Reference Include="glade-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+ <Reference Include="pango-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+ <Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Data" />
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="gtk-gui\gui.stetic">
+ <LogicalName>gui.stetic</LogicalName>
+ </EmbeddedResource>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="gtk-gui\generated.cs" />
+ <Compile Include="MainWindow.cs" />
+ <Compile Include="gtk-gui\MainWindow.cs" />
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="..\MediaBrowser.ServerApplication\EntryPoints\StartupWizard.cs">
+ <Link>EntryPoints\StartupWizard.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.ServerApplication\Native\BrowserLauncher.cs">
+ <Link>Native\BrowserLauncher.cs</Link>
+ </Compile>
+ <Compile Include="Native\Autorun.cs" />
+ <Compile Include="Native\ServerAuthorization.cs" />
+ <Compile Include="FFMpeg\FFMpegDownloader.cs" />
+ <Compile Include="..\MediaBrowser.ServerApplication\FFMpeg\FFMpegInfo.cs">
+ <Link>FFMpeg\FFMpegInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.ServerApplication\ApplicationHost.cs">
+ <Link>ApplicationHost.cs</Link>
+ </Compile>
+ <Compile Include="Native\HttpMessageHandlerFactory.cs" />
+ <Compile Include="Native\Assemblies.cs" />
+ <Compile Include="Native\Sqlite.cs" />
+ <Compile Include="Native\NativeApp.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ItemGroup>
+ <ProjectReference Include="..\MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj">
+ <Project>{5624B7B5-B5A7-41D8-9F10-CC5611109619}</Project>
+ <Name>MediaBrowser.WebDashboard</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj">
+ <Project>{2E781478-814D-4A48-9D80-BFF206441A65}</Project>
+ <Name>MediaBrowser.Server.Implementations</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Providers\MediaBrowser.Providers.csproj">
+ <Project>{442B5058-DCAF-4263-BB6A-F21E31120A1B}</Project>
+ <Name>MediaBrowser.Providers</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
+ <Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
+ <Name>MediaBrowser.Model</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
+ <Project>{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}</Project>
+ <Name>MediaBrowser.Controller</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Common.Implementations\MediaBrowser.Common.Implementations.csproj">
+ <Project>{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}</Project>
+ <Name>MediaBrowser.Common.Implementations</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
+ <Project>{9142EEFA-7570-41E1-BFCC-468BB571AF2F}</Project>
+ <Name>MediaBrowser.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Api\MediaBrowser.Api.csproj">
+ <Project>{4FD51AC5-2C16-4308-A993-C3A84F3B4582}</Project>
+ <Name>MediaBrowser.Api</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="EntryPoints\" />
+ <Folder Include="Implementations\" />
+ <Folder Include="Native\" />
+ <Folder Include="FFMpeg\" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/MediaBrowser.Server.Mono/Native/Assemblies.cs b/MediaBrowser.Server.Mono/Native/Assemblies.cs
new file mode 100644
index 000000000..eae6366e1
--- /dev/null
+++ b/MediaBrowser.Server.Mono/Native/Assemblies.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ /// <summary>
+ /// Class Assemblies
+ /// </summary>
+ public static class Assemblies
+ {
+ /// <summary>
+ /// Gets the assemblies with parts.
+ /// </summary>
+ /// <returns>List{Assembly}.</returns>
+ public static List<Assembly> GetAssembliesWithParts()
+ {
+ var list = new List<Assembly>();
+
+ return list;
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Mono/Native/Autorun.cs b/MediaBrowser.Server.Mono/Native/Autorun.cs
new file mode 100644
index 000000000..ee33c5967
--- /dev/null
+++ b/MediaBrowser.Server.Mono/Native/Autorun.cs
@@ -0,0 +1,20 @@
+using System;
+using System.IO;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ /// <summary>
+ /// Class Autorun
+ /// </summary>
+ public static class Autorun
+ {
+ /// <summary>
+ /// Configures the specified autorun.
+ /// </summary>
+ /// <param name="autorun">if set to <c>true</c> [autorun].</param>
+ public static void Configure(bool autorun)
+ {
+
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Mono/Native/HttpMessageHandlerFactory.cs b/MediaBrowser.Server.Mono/Native/HttpMessageHandlerFactory.cs
new file mode 100644
index 000000000..5823a7e51
--- /dev/null
+++ b/MediaBrowser.Server.Mono/Native/HttpMessageHandlerFactory.cs
@@ -0,0 +1,25 @@
+using System.Net;
+using System.Net.Cache;
+using System.Net.Http;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ /// <summary>
+ /// Class HttpMessageHandlerFactory
+ /// </summary>
+ public static class HttpMessageHandlerFactory
+ {
+ /// <summary>
+ /// Gets the HTTP message handler.
+ /// </summary>
+ /// <param name="enableHttpCompression">if set to <c>true</c> [enable HTTP compression].</param>
+ /// <returns>HttpMessageHandler.</returns>
+ public static HttpMessageHandler GetHttpMessageHandler(bool enableHttpCompression)
+ {
+ return new HttpClientHandler
+ {
+ AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None
+ };
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Mono/Native/NativeApp.cs b/MediaBrowser.Server.Mono/Native/NativeApp.cs
new file mode 100644
index 000000000..bb47f6ea4
--- /dev/null
+++ b/MediaBrowser.Server.Mono/Native/NativeApp.cs
@@ -0,0 +1,25 @@
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ /// <summary>
+ /// Class NativeApp
+ /// </summary>
+ public static class NativeApp
+ {
+ /// <summary>
+ /// Shutdowns this instance.
+ /// </summary>
+ public static void Shutdown()
+ {
+
+ }
+
+ /// <summary>
+ /// Restarts this instance.
+ /// </summary>
+ public static void Restart()
+ {
+
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Mono/Native/ServerAuthorization.cs b/MediaBrowser.Server.Mono/Native/ServerAuthorization.cs
new file mode 100644
index 000000000..6f43a12c0
--- /dev/null
+++ b/MediaBrowser.Server.Mono/Native/ServerAuthorization.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ /// <summary>
+ /// Class Authorization
+ /// </summary>
+ public static class ServerAuthorization
+ {
+ /// <summary>
+ /// Authorizes the server.
+ /// </summary>
+ /// <param name="httpServerPort">The HTTP server port.</param>
+ /// <param name="httpServerUrlPrefix">The HTTP server URL prefix.</param>
+ /// <param name="webSocketPort">The web socket port.</param>
+ /// <param name="udpPort">The UDP port.</param>
+ /// <param name="tempDirectory">The temp directory.</param>
+ public static void AuthorizeServer(int httpServerPort, string httpServerUrlPrefix, int webSocketPort, int udpPort, string tempDirectory)
+ {
+
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Mono/Native/Sqlite.cs b/MediaBrowser.Server.Mono/Native/Sqlite.cs
new file mode 100644
index 000000000..cc20952d7
--- /dev/null
+++ b/MediaBrowser.Server.Mono/Native/Sqlite.cs
@@ -0,0 +1,36 @@
+using System.Data;
+using System.Data.SQLite;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ /// <summary>
+ /// Class Sqlite
+ /// </summary>
+ public static class Sqlite
+ {
+ /// <summary>
+ /// Connects to db.
+ /// </summary>
+ /// <param name="dbPath">The db path.</param>
+ /// <returns>Task{IDbConnection}.</returns>
+ /// <exception cref="System.ArgumentNullException">dbPath</exception>
+ public static async Task<IDbConnection> OpenDatabase(string dbPath)
+ {
+ var connectionstr = new SQLiteConnectionStringBuilder
+ {
+ PageSize = 4096,
+ CacheSize = 4096,
+ SyncMode = SynchronizationModes.Normal,
+ DataSource = dbPath,
+ JournalMode = SQLiteJournalModeEnum.Wal
+ };
+
+ var connection = new SQLiteConnection(connectionstr.ConnectionString);
+
+ await connection.OpenAsync().ConfigureAwait(false);
+
+ return connection;
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs
new file mode 100644
index 000000000..72dee1162
--- /dev/null
+++ b/MediaBrowser.Server.Mono/Program.cs
@@ -0,0 +1,16 @@
+using System;
+using Gtk;
+
+namespace MediaBrowser.Server.Mono
+{
+ class MainClass
+ {
+ public static void Main (string[] args)
+ {
+ Application.Init ();
+ MainWindow win = new MainWindow ();
+ win.Show ();
+ Application.Run ();
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Mono/Properties/AssemblyInfo.cs b/MediaBrowser.Server.Mono/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..0a2e93220
--- /dev/null
+++ b/MediaBrowser.Server.Mono/Properties/AssemblyInfo.cs
@@ -0,0 +1,22 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+[assembly: AssemblyTitle ("MediaBrowser.Server.Mono")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("Luke")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+[assembly: AssemblyVersion ("1.0.*")]
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/MediaBrowser.Server.Mono/gtk-gui/MainWindow.cs b/MediaBrowser.Server.Mono/gtk-gui/MainWindow.cs
new file mode 100644
index 000000000..c481dfc8c
--- /dev/null
+++ b/MediaBrowser.Server.Mono/gtk-gui/MainWindow.cs
@@ -0,0 +1,20 @@
+
+// This file has been generated by the GUI designer. Do not modify.
+public partial class MainWindow
+{
+ protected virtual void Build ()
+ {
+ global::Stetic.Gui.Initialize (this);
+ // Widget MainWindow
+ this.Name = "MainWindow";
+ this.Title = global::Mono.Unix.Catalog.GetString ("MainWindow");
+ this.WindowPosition = ((global::Gtk.WindowPosition)(4));
+ if ((this.Child != null)) {
+ this.Child.ShowAll ();
+ }
+ this.DefaultWidth = 400;
+ this.DefaultHeight = 300;
+ this.Show ();
+ this.DeleteEvent += new global::Gtk.DeleteEventHandler (this.OnDeleteEvent);
+ }
+}
diff --git a/MediaBrowser.Server.Mono/gtk-gui/generated.cs b/MediaBrowser.Server.Mono/gtk-gui/generated.cs
new file mode 100644
index 000000000..9ef336398
--- /dev/null
+++ b/MediaBrowser.Server.Mono/gtk-gui/generated.cs
@@ -0,0 +1,29 @@
+
+// This file has been generated by the GUI designer. Do not modify.
+namespace Stetic
+{
+ internal class Gui
+ {
+ private static bool initialized;
+
+ internal static void Initialize (Gtk.Widget iconRenderer)
+ {
+ if ((Stetic.Gui.initialized == false)) {
+ Stetic.Gui.initialized = true;
+ }
+ }
+ }
+
+ internal class ActionGroups
+ {
+ public static Gtk.ActionGroup GetActionGroup (System.Type type)
+ {
+ return Stetic.ActionGroups.GetActionGroup (type.FullName);
+ }
+
+ public static Gtk.ActionGroup GetActionGroup (string name)
+ {
+ return null;
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Mono/gtk-gui/gui.stetic b/MediaBrowser.Server.Mono/gtk-gui/gui.stetic
new file mode 100644
index 000000000..81685442c
--- /dev/null
+++ b/MediaBrowser.Server.Mono/gtk-gui/gui.stetic
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<stetic-interface>
+ <configuration>
+ <images-root-path>..</images-root-path>
+ <target-gtk-version>2.12</target-gtk-version>
+ </configuration>
+ <import>
+ <widget-library name="glade-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+ <widget-library name="../bin/Debug/MediaBrowser.Server.Mono.exe" internal="true" />
+ </import>
+ <widget class="Gtk.Window" id="MainWindow" design-size="400 300">
+ <property name="MemberName" />
+ <property name="Title" translatable="yes">MainWindow</property>
+ <property name="WindowPosition">CenterOnParent</property>
+ <signal name="DeleteEvent" handler="OnDeleteEvent" />
+ <child>
+ <placeholder />
+ </child>
+ </widget>
+</stetic-interface> \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/App.xaml.cs b/MediaBrowser.ServerApplication/App.xaml.cs
index 69de391a4..706206d3a 100644
--- a/MediaBrowser.ServerApplication/App.xaml.cs
+++ b/MediaBrowser.ServerApplication/App.xaml.cs
@@ -154,58 +154,5 @@ namespace MediaBrowser.ServerApplication
{
Dispatcher.Invoke(Shutdown);
}
-
- /// <summary>
- /// Opens the dashboard page.
- /// </summary>
- /// <param name="page">The page.</param>
- /// <param name="loggedInUser">The logged in user.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="appHost">The app host.</param>
- public static void OpenDashboardPage(string page, User loggedInUser, IServerConfigurationManager configurationManager, IServerApplicationHost appHost)
- {
- var url = "http://localhost:" + configurationManager.Configuration.HttpServerPortNumber + "/" +
- appHost.WebApplicationName + "/dashboard/" + page;
-
- OpenUrl(url);
- }
-
- /// <summary>
- /// Opens the URL.
- /// </summary>
- /// <param name="url">The URL.</param>
- public static void OpenUrl(string url)
- {
- var process = new Process
- {
- StartInfo = new ProcessStartInfo
- {
- FileName = url
- },
-
- EnableRaisingEvents = true
- };
-
- process.Exited += ProcessExited;
-
- try
- {
- process.Start();
- }
- catch (Exception ex)
- {
- MessageBox.Show("There was an error launching your web browser. Please check your defualt browser settings.");
- }
- }
-
- /// <summary>
- /// Processes the exited.
- /// </summary>
- /// <param name="sender">The sender.</param>
- /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
- static void ProcessExited(object sender, EventArgs e)
- {
- ((Process)sender).Dispose();
- }
}
}
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 5cae99785..d0f7da73d 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -24,7 +24,6 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.Sorting;
-using MediaBrowser.IsoMounter;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
@@ -36,6 +35,7 @@ using MediaBrowser.Server.Implementations.BdInfo;
using MediaBrowser.Server.Implementations.Configuration;
using MediaBrowser.Server.Implementations.Drawing;
using MediaBrowser.Server.Implementations.Dto;
+using MediaBrowser.Server.Implementations.EntryPoints;
using MediaBrowser.Server.Implementations.HttpServer;
using MediaBrowser.Server.Implementations.IO;
using MediaBrowser.Server.Implementations.Library;
@@ -46,16 +46,14 @@ using MediaBrowser.Server.Implementations.Providers;
using MediaBrowser.Server.Implementations.ServerManager;
using MediaBrowser.Server.Implementations.Session;
using MediaBrowser.Server.Implementations.WebSocket;
-using MediaBrowser.ServerApplication.Implementations;
+using MediaBrowser.ServerApplication.FFMpeg;
+using MediaBrowser.ServerApplication.Native;
using MediaBrowser.WebDashboard.Api;
using System;
using System.Collections.Generic;
-using System.Data.SQLite;
-using System.Diagnostics;
+using System.Data;
using System.IO;
using System.Linq;
-using System.Net;
-using System.Net.Cache;
using System.Net.Http;
using System.Reflection;
using System.Threading;
@@ -68,8 +66,6 @@ namespace MediaBrowser.ServerApplication
/// </summary>
public class ApplicationHost : BaseApplicationHost<ServerApplicationPaths>, IServerApplicationHost
{
- internal const int UdpServerPort = 7359;
-
/// <summary>
/// Gets the server kernel.
/// </summary>
@@ -142,11 +138,6 @@ namespace MediaBrowser.ServerApplication
/// <value>The provider manager.</value>
private IProviderManager ProviderManager { get; set; }
/// <summary>
- /// Gets or sets the zip client.
- /// </summary>
- /// <value>The zip client.</value>
- private IZipClient ZipClient { get; set; }
- /// <summary>
/// Gets or sets the HTTP server.
/// </summary>
/// <value>The HTTP server.</value>
@@ -161,6 +152,7 @@ namespace MediaBrowser.ServerApplication
private IMediaEncoder MediaEncoder { get; set; }
private IIsoManager IsoManager { get; set; }
+ private ISessionManager SessionManager { get; set; }
private ILocalizationManager LocalizationManager { get; set; }
@@ -174,14 +166,6 @@ namespace MediaBrowser.ServerApplication
private IItemRepository ItemRepository { get; set; }
private INotificationsRepository NotificationsRepository { get; set; }
- /// <summary>
- /// The full path to our startmenu shortcut
- /// </summary>
- protected override string ProductShortcutPath
- {
- get { return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Media Browser 3", "Media Browser Server.lnk"); }
- }
-
private Task<IHttpServer> _httpServerCreationTask;
/// <summary>
@@ -255,8 +239,7 @@ namespace MediaBrowser.ServerApplication
RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer());
- ZipClient = new DotNetZipClient();
- RegisterSingleInstance(ZipClient);
+ var mediaEncoderTask = RegisterMediaEncoder();
UserDataRepository = new SqliteUserDataRepository(ApplicationPaths, JsonSerializer, LogManager);
RegisterSingleInstance(UserDataRepository);
@@ -284,10 +267,8 @@ namespace MediaBrowser.ServerApplication
RegisterSingleInstance<ILibrarySearchEngine>(() => new LuceneSearchEngine(ApplicationPaths, LogManager, LibraryManager));
- await RegisterMediaEncoder().ConfigureAwait(false);
-
- var clientConnectionManager = new SessionManager(UserDataRepository, ServerConfigurationManager, Logger, UserRepository);
- RegisterSingleInstance<ISessionManager>(clientConnectionManager);
+ SessionManager = new SessionManager(UserDataRepository, ServerConfigurationManager, Logger, UserRepository);
+ RegisterSingleInstance<ISessionManager>(SessionManager);
HttpServer = await _httpServerCreationTask.ConfigureAwait(false);
RegisterSingleInstance(HttpServer, false);
@@ -310,7 +291,7 @@ namespace MediaBrowser.ServerApplication
await ConfigureNotificationsRepository().ConfigureAwait(false);
- await Task.WhenAll(itemsTask, displayPreferencesTask, userdataTask).ConfigureAwait(false);
+ await Task.WhenAll(itemsTask, displayPreferencesTask, userdataTask, mediaEncoderTask).ConfigureAwait(false);
SetKernelProperties();
}
@@ -406,27 +387,14 @@ namespace MediaBrowser.ServerApplication
/// <param name="dbPath">The db path.</param>
/// <returns>Task{IDbConnection}.</returns>
/// <exception cref="System.ArgumentNullException">dbPath</exception>
- private static async Task<SQLiteConnection> ConnectToDb(string dbPath)
+ private static Task<IDbConnection> ConnectToDb(string dbPath)
{
if (string.IsNullOrEmpty(dbPath))
{
throw new ArgumentNullException("dbPath");
}
- var connectionstr = new SQLiteConnectionStringBuilder
- {
- PageSize = 4096,
- CacheSize = 4096,
- SyncMode = SynchronizationModes.Normal,
- DataSource = dbPath,
- JournalMode = SQLiteJournalModeEnum.Wal
- };
-
- var connection = new SQLiteConnection(connectionstr.ConnectionString);
-
- await connection.OpenAsync().ConfigureAwait(false);
-
- return connection;
+ return Sqlite.OpenDatabase(dbPath);
}
/// <summary>
@@ -477,6 +445,8 @@ namespace MediaBrowser.ServerApplication
IsoManager.AddParts(GetExports<IIsoMounter>());
+ SessionManager.AddParts(GetExports<ISessionRemoteController>());
+
ImageProcessor.AddParts(GetExports<IImageEnhancer>());
}
@@ -527,7 +497,6 @@ namespace MediaBrowser.ServerApplication
{
NotifyPendingRestart();
}
-
}
/// <summary>
@@ -544,7 +513,7 @@ namespace MediaBrowser.ServerApplication
Logger.ErrorException("Error sending server restart web socket message", ex);
}
- MainStartup.Restart();
+ NativeApp.Restart();
}
/// <summary>
@@ -568,44 +537,44 @@ namespace MediaBrowser.ServerApplication
/// <returns>IEnumerable{Assembly}.</returns>
protected override IEnumerable<Assembly> GetComposablePartAssemblies()
{
+ var list = Directory.EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly)
+ .Select(LoadAssembly)
+ .Where(a => a != null)
+ .ToList();
+
// Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that
// This will prevent the .dll file from getting locked, and allow us to replace it when needed
- foreach (var pluginAssembly in Directory
- .EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly)
- .Select(LoadAssembly).Where(a => a != null))
- {
- yield return pluginAssembly;
- }
// Include composable parts in the Api assembly
- yield return typeof(ApiEntryPoint).Assembly;
+ list.Add(typeof(ApiEntryPoint).Assembly);
// Include composable parts in the Dashboard assembly
- yield return typeof(DashboardInfo).Assembly;
+ list.Add(typeof(DashboardInfo).Assembly);
// Include composable parts in the Model assembly
- yield return typeof(SystemInfo).Assembly;
+ list.Add(typeof(SystemInfo).Assembly);
// Include composable parts in the Common assembly
- yield return typeof(IApplicationHost).Assembly;
+ list.Add(typeof(IApplicationHost).Assembly);
// Include composable parts in the Controller assembly
- yield return typeof(Kernel).Assembly;
+ list.Add(typeof(Kernel).Assembly);
// Include composable parts in the Providers assembly
- yield return typeof(ImagesByNameProvider).Assembly;
+ list.Add(typeof(ImagesByNameProvider).Assembly);
// Common implementations
- yield return typeof(TaskManager).Assembly;
+ list.Add(typeof(TaskManager).Assembly);
// Server implementations
- yield return typeof(ServerApplicationPaths).Assembly;
+ list.Add(typeof(ServerApplicationPaths).Assembly);
- // Pismo
- yield return typeof(PismoIsoManager).Assembly;
+ list.AddRange(Assemblies.GetAssembliesWithParts());
// Include composable parts in the running assembly
- yield return GetType().Assembly;
+ list.Add(GetType().Assembly);
+
+ return list;
}
private readonly string _systemId = Environment.MachineName.GetMD5().ToString();
@@ -664,7 +633,7 @@ namespace MediaBrowser.ServerApplication
Logger.ErrorException("Error sending server shutdown web socket message", ex);
}
- MainStartup.Shutdown();
+ NativeApp.Shutdown();
}
/// <summary>
@@ -674,36 +643,16 @@ namespace MediaBrowser.ServerApplication
{
Logger.Info("Requesting administrative access to authorize http server");
- // Create a temp file path to extract the bat file to
- var tmpFile = Path.Combine(ConfigurationManager.CommonApplicationPaths.TempDirectory, Guid.NewGuid() + ".bat");
-
- // Extract the bat file
- using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MediaBrowser.ServerApplication.RegisterServer.bat"))
+ try
{
- using (var fileStream = File.Create(tmpFile))
- {
- stream.CopyTo(fileStream);
- }
+ ServerAuthorization.AuthorizeServer(ServerConfigurationManager.Configuration.HttpServerPortNumber,
+ HttpServerUrlPrefix, ServerConfigurationManager.Configuration.LegacyWebSocketPortNumber,
+ UdpServerEntryPoint.PortNumber,
+ ConfigurationManager.CommonApplicationPaths.TempDirectory);
}
-
- var startInfo = new ProcessStartInfo
- {
- FileName = tmpFile,
-
- Arguments = string.Format("{0} {1} {2} {3}", ServerConfigurationManager.Configuration.HttpServerPortNumber,
- HttpServerUrlPrefix,
- UdpServerPort,
- ServerConfigurationManager.Configuration.LegacyWebSocketPortNumber),
-
- CreateNoWindow = true,
- WindowStyle = ProcessWindowStyle.Hidden,
- Verb = "runas",
- ErrorDialog = false
- };
-
- using (var process = Process.Start(startInfo))
+ catch (Exception ex)
{
- process.WaitForExit();
+ Logger.ErrorException("Error authorizing server", ex);
}
}
@@ -713,8 +662,7 @@ namespace MediaBrowser.ServerApplication
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task{CheckForUpdateResult}.</returns>
- public override async Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken,
- IProgress<double> progress)
+ public override async Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress)
{
var availablePackages = await InstallationManager.GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
@@ -745,11 +693,12 @@ namespace MediaBrowser.ServerApplication
/// <returns>HttpMessageHandler.</returns>
protected override HttpMessageHandler GetHttpMessageHandler(bool enableHttpCompression)
{
- return new WebRequestHandler
- {
- CachePolicy = new RequestCachePolicy(RequestCacheLevel.Revalidate),
- AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None
- };
+ return HttpMessageHandlerFactory.GetHttpMessageHandler(enableHttpCompression);
+ }
+
+ protected override void ConfigureAutoRunAtStartup(bool autorun)
+ {
+ Autorun.Configure(autorun);
}
}
}
diff --git a/MediaBrowser.ServerApplication/EntryPoints/StartupWizard.cs b/MediaBrowser.ServerApplication/EntryPoints/StartupWizard.cs
index 87578ef84..1a5f9e2c3 100644
--- a/MediaBrowser.ServerApplication/EntryPoints/StartupWizard.cs
+++ b/MediaBrowser.ServerApplication/EntryPoints/StartupWizard.cs
@@ -3,9 +3,10 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Logging;
-using System.ComponentModel;
+using System;
using System.Linq;
-using System.Windows;
+using System.Windows.Forms;
+using MediaBrowser.ServerApplication.Native;
namespace MediaBrowser.ServerApplication.EntryPoints
{
@@ -31,9 +32,10 @@ namespace MediaBrowser.ServerApplication.EntryPoints
/// </summary>
/// <param name="appHost">The app host.</param>
/// <param name="userManager">The user manager.</param>
- public StartupWizard(IServerApplicationHost appHost, IUserManager userManager, IServerConfigurationManager configurationManager)
+ public StartupWizard(IServerApplicationHost appHost, IUserManager userManager, IServerConfigurationManager configurationManager, ILogger logger)
{
_appHost = appHost;
+ _logger = logger;
_userManager = userManager;
_configurationManager = configurationManager;
}
@@ -58,9 +60,9 @@ namespace MediaBrowser.ServerApplication.EntryPoints
try
{
- App.OpenDashboardPage("wizardstart.html", user, _configurationManager, _appHost);
+ BrowserLauncher.OpenDashboardPage("wizardstart.html", user, _configurationManager, _appHost, _logger);
}
- catch (Win32Exception ex)
+ catch (Exception ex)
{
_logger.ErrorException("Error launching startup wizard", ex);
@@ -75,4 +77,4 @@ namespace MediaBrowser.ServerApplication.EntryPoints
{
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs b/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs
new file mode 100644
index 000000000..926767f5b
--- /dev/null
+++ b/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs
@@ -0,0 +1,302 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Net;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.ServerApplication.FFMpeg
+{
+ public class FFMpegDownloader
+ {
+ private readonly IHttpClient _httpClient;
+ private readonly IApplicationPaths _appPaths;
+ private readonly ILogger _logger;
+ private readonly IZipClient _zipClient;
+
+ private const string Version = "ffmpeg20130904";
+
+ private readonly string[] _fontUrls = new[]
+ {
+ "https://www.dropbox.com/s/pj847twf7riq0j7/ARIALUNI.7z?dl=1"
+ };
+
+ private readonly string[] _ffMpegUrls = new[]
+ {
+ "https://github.com/MediaBrowser/MediaBrowser/raw/master/MediaBrowser.ServerApplication/FFMpeg/ffmpeg-20130904-git-f974289-win32-static.7z",
+
+ "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20130904-git-f974289-win32-static.7z",
+ "https://www.dropbox.com/s/a81cb2ob23fwcfs/ffmpeg-20130904-git-f974289-win32-static.7z?dl=1"
+ };
+
+ public FFMpegDownloader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient)
+ {
+ _logger = logger;
+ _appPaths = appPaths;
+ _httpClient = httpClient;
+ _zipClient = zipClient;
+ }
+
+ public async Task<FFMpegInfo> GetFFMpegInfo()
+ {
+ var versionedDirectoryPath = Path.Combine(GetMediaToolsPath(true), Version);
+
+ var info = new FFMpegInfo
+ {
+ ProbePath = Path.Combine(versionedDirectoryPath, "ffprobe.exe"),
+ Path = Path.Combine(versionedDirectoryPath, "ffmpeg.exe"),
+ Version = Version
+ };
+
+ if (!Directory.Exists(versionedDirectoryPath))
+ {
+ Directory.CreateDirectory(versionedDirectoryPath);
+ }
+
+ var tasks = new List<Task>();
+
+ if (!File.Exists(info.ProbePath) || !File.Exists(info.Path))
+ {
+ tasks.Add(DownloadFFMpeg(info));
+ }
+
+ tasks.Add(DownloadFonts(versionedDirectoryPath));
+
+ await Task.WhenAll(tasks).ConfigureAwait(false);
+
+ return info;
+ }
+
+ private async Task DownloadFFMpeg(FFMpegInfo info)
+ {
+ foreach (var url in _ffMpegUrls)
+ {
+ try
+ {
+ var tempFile = await DownloadFFMpeg(info, url).ConfigureAwait(false);
+
+ ExtractFFMpeg(tempFile, Path.GetDirectoryName(info.Path));
+ return;
+ }
+ catch (HttpException ex)
+ {
+
+ }
+ }
+
+ throw new ApplicationException("Unable to download required components. Please try again later.");
+ }
+
+ private Task<string> DownloadFFMpeg(FFMpegInfo info, string url)
+ {
+ return _httpClient.GetTempFile(new HttpRequestOptions
+ {
+ Url = url,
+ CancellationToken = CancellationToken.None,
+ Progress = new Progress<double>(),
+
+ // Make it look like a browser
+ // Try to hide that we're direct linking
+ UserAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.47 Safari/537.36"
+ });
+ }
+
+ private void ExtractFFMpeg(string tempFile, string targetFolder)
+ {
+ _logger.Debug("Extracting ffmpeg from {0}", tempFile);
+
+ var tempFolder = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString());
+
+ if (!Directory.Exists(tempFolder))
+ {
+ Directory.CreateDirectory(tempFolder);
+ }
+
+ try
+ {
+ Extract7zArchive(tempFile, tempFolder);
+
+ var files = Directory.EnumerateFiles(tempFolder, "*.exe", SearchOption.AllDirectories).ToList();
+
+ foreach (var file in files)
+ {
+ File.Copy(file, Path.Combine(targetFolder, Path.GetFileName(file)));
+ }
+ }
+ finally
+ {
+ DeleteFile(tempFile);
+ }
+ }
+
+ private void Extract7zArchive(string archivePath, string targetPath)
+ {
+ _zipClient.ExtractAllFrom7z(archivePath, targetPath, true);
+ }
+
+ private void DeleteFile(string path)
+ {
+ try
+ {
+ File.Delete(path);
+ }
+ catch (IOException ex)
+ {
+ _logger.ErrorException("Error deleting temp file {0}", ex, path);
+ }
+ }
+
+ /// <summary>
+ /// Extracts the fonts.
+ /// </summary>
+ /// <param name="targetPath">The target path.</param>
+ private async Task DownloadFonts(string targetPath)
+ {
+ try
+ {
+ var fontsDirectory = Path.Combine(targetPath, "fonts");
+
+ if (!Directory.Exists(fontsDirectory))
+ {
+ Directory.CreateDirectory(fontsDirectory);
+ }
+
+ const string fontFilename = "ARIALUNI.TTF";
+
+ var fontFile = Path.Combine(fontsDirectory, fontFilename);
+
+ if (!File.Exists(fontFile))
+ {
+ await DownloadFontFile(fontsDirectory, fontFilename).ConfigureAwait(false);
+ }
+
+ await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false);
+ }
+ catch (HttpException ex)
+ {
+ // Don't let the server crash because of this
+ _logger.ErrorException("Error downloading ffmpeg font files", ex);
+ }
+ catch (Exception ex)
+ {
+ // Don't let the server crash because of this
+ _logger.ErrorException("Error writing ffmpeg font files", ex);
+ }
+ }
+
+ /// <summary>
+ /// Downloads the font file.
+ /// </summary>
+ /// <param name="fontsDirectory">The fonts directory.</param>
+ /// <param name="fontFilename">The font filename.</param>
+ /// <returns>Task.</returns>
+ private async Task DownloadFontFile(string fontsDirectory, string fontFilename)
+ {
+ var existingFile = Directory
+ .EnumerateFiles(_appPaths.ProgramDataPath, fontFilename, SearchOption.AllDirectories)
+ .FirstOrDefault();
+
+ if (existingFile != null)
+ {
+ try
+ {
+ File.Copy(existingFile, Path.Combine(fontsDirectory, fontFilename), true);
+ return;
+ }
+ catch (IOException ex)
+ {
+ // Log this, but don't let it fail the operation
+ _logger.ErrorException("Error copying file", ex);
+ }
+ }
+
+ string tempFile = null;
+
+ foreach (var url in _fontUrls)
+ {
+ try
+ {
+ tempFile = await _httpClient.GetTempFile(new HttpRequestOptions
+ {
+ Url = url,
+ Progress = new Progress<double>()
+
+ }).ConfigureAwait(false);
+
+ break;
+ }
+ catch (Exception ex)
+ {
+ // The core can function without the font file, so handle this
+ _logger.ErrorException("Failed to download ffmpeg font file from {0}", ex, url);
+ }
+ }
+
+ if (string.IsNullOrEmpty(tempFile))
+ {
+ return;
+ }
+
+ Extract7zArchive(tempFile, fontsDirectory);
+
+ try
+ {
+ File.Delete(tempFile);
+ }
+ catch (IOException ex)
+ {
+ // Log this, but don't let it fail the operation
+ _logger.ErrorException("Error deleting temp file {0}", ex, tempFile);
+ }
+ }
+
+ /// <summary>
+ /// Writes the font config file.
+ /// </summary>
+ /// <param name="fontsDirectory">The fonts directory.</param>
+ /// <returns>Task.</returns>
+ private async Task WriteFontConfigFile(string fontsDirectory)
+ {
+ const string fontConfigFilename = "fonts.conf";
+ var fontConfigFile = Path.Combine(fontsDirectory, fontConfigFilename);
+
+ if (!File.Exists(fontConfigFile))
+ {
+ var contents = string.Format("<?xml version=\"1.0\"?><fontconfig><dir>{0}</dir><alias><family>Arial</family><prefer>Arial Unicode MS</prefer></alias></fontconfig>", fontsDirectory);
+
+ var bytes = Encoding.UTF8.GetBytes(contents);
+
+ using (var fileStream = new FileStream(fontConfigFile, FileMode.Create, FileAccess.Write,
+ FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize,
+ FileOptions.Asynchronous))
+ {
+ await fileStream.WriteAsync(bytes, 0, bytes.Length);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets the media tools path.
+ /// </summary>
+ /// <param name="create">if set to <c>true</c> [create].</param>
+ /// <returns>System.String.</returns>
+ private string GetMediaToolsPath(bool create)
+ {
+ var path = Path.Combine(_appPaths.ProgramDataPath, "ffmpeg");
+
+ if (create && !Directory.Exists(path))
+ {
+ Directory.CreateDirectory(path);
+ }
+
+ return path;
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/FFMpeg/FFMpegInfo.cs b/MediaBrowser.ServerApplication/FFMpeg/FFMpegInfo.cs
new file mode 100644
index 000000000..147a9f771
--- /dev/null
+++ b/MediaBrowser.ServerApplication/FFMpeg/FFMpegInfo.cs
@@ -0,0 +1,24 @@
+namespace MediaBrowser.ServerApplication.FFMpeg
+{
+ /// <summary>
+ /// Class FFMpegInfo
+ /// </summary>
+ public class FFMpegInfo
+ {
+ /// <summary>
+ /// Gets or sets the path.
+ /// </summary>
+ /// <value>The path.</value>
+ public string Path { get; set; }
+ /// <summary>
+ /// Gets or sets the probe path.
+ /// </summary>
+ /// <value>The probe path.</value>
+ public string ProbePath { get; set; }
+ /// <summary>
+ /// Gets or sets the version.
+ /// </summary>
+ /// <value>The version.</value>
+ public string Version { get; set; }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/FFMpeg/ffmpeg-20130904-git-f974289-win32-static.7z.REMOVED.git-id b/MediaBrowser.ServerApplication/FFMpeg/ffmpeg-20130904-git-f974289-win32-static.7z.REMOVED.git-id
new file mode 100644
index 000000000..9f83b949b
--- /dev/null
+++ b/MediaBrowser.ServerApplication/FFMpeg/ffmpeg-20130904-git-f974289-win32-static.7z.REMOVED.git-id
@@ -0,0 +1 @@
+8f1dfd62d31e48c31bef4b9ccc0e514f46650a79 \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/Implementations/DotNetZipClient.cs b/MediaBrowser.ServerApplication/Implementations/DotNetZipClient.cs
deleted file mode 100644
index 3b174a9b2..000000000
--- a/MediaBrowser.ServerApplication/Implementations/DotNetZipClient.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using Ionic.Zip;
-using MediaBrowser.Model.IO;
-using System.IO;
-
-namespace MediaBrowser.ServerApplication.Implementations
-{
- /// <summary>
- /// Class DotNetZipClient
- /// </summary>
- public class DotNetZipClient : IZipClient
- {
- /// <summary>
- /// Extracts all.
- /// </summary>
- /// <param name="sourceFile">The source file.</param>
- /// <param name="targetPath">The target path.</param>
- /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
- public void ExtractAll(string sourceFile, string targetPath, bool overwriteExistingFiles)
- {
- using (var fileStream = File.OpenRead(sourceFile))
- {
- using (var zipFile = ZipFile.Read(fileStream))
- {
- zipFile.ExtractAll(targetPath, overwriteExistingFiles ? ExtractExistingFileAction.OverwriteSilently : ExtractExistingFileAction.DoNotOverwrite);
- }
- }
- }
-
- /// <summary>
- /// Extracts all.
- /// </summary>
- /// <param name="source">The source.</param>
- /// <param name="targetPath">The target path.</param>
- /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
- public void ExtractAll(Stream source, string targetPath, bool overwriteExistingFiles)
- {
- using (var zipFile = ZipFile.Read(source))
- {
- zipFile.ExtractAll(targetPath, overwriteExistingFiles ? ExtractExistingFileAction.OverwriteSilently : ExtractExistingFileAction.DoNotOverwrite);
- }
- }
- }
-}
diff --git a/MediaBrowser.ServerApplication/Implementations/FFMpegDownloader.cs b/MediaBrowser.ServerApplication/Implementations/FFMpegDownloader.cs
deleted file mode 100644
index 7fd0acddd..000000000
--- a/MediaBrowser.ServerApplication/Implementations/FFMpegDownloader.cs
+++ /dev/null
@@ -1,205 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.ServerApplication.Implementations
-{
- public class FFMpegDownloader
- {
- private readonly IZipClient _zipClient;
- private readonly IHttpClient _httpClient;
- private readonly IApplicationPaths _appPaths;
- private readonly ILogger _logger;
-
- public FFMpegDownloader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient)
- {
- _logger = logger;
- _appPaths = appPaths;
- _httpClient = httpClient;
- _zipClient = zipClient;
- }
-
- public async Task<FFMpegInfo> GetFFMpegInfo()
- {
- var assembly = GetType().Assembly;
-
- var prefix = GetType().Namespace + ".";
-
- var srch = prefix + "ffmpeg";
-
- var resource = assembly.GetManifestResourceNames().First(r => r.StartsWith(srch));
-
- var filename =
- resource.Substring(resource.IndexOf(prefix, StringComparison.OrdinalIgnoreCase) + prefix.Length);
-
- var versionedDirectoryPath = Path.Combine(GetMediaToolsPath(true),
- Path.GetFileNameWithoutExtension(filename));
-
- if (!Directory.Exists(versionedDirectoryPath))
- {
- Directory.CreateDirectory(versionedDirectoryPath);
- }
-
- await ExtractTools(assembly, resource, versionedDirectoryPath).ConfigureAwait(false);
-
- return new FFMpegInfo
- {
- ProbePath = Path.Combine(versionedDirectoryPath, "ffprobe.exe"),
- Path = Path.Combine(versionedDirectoryPath, "ffmpeg.exe"),
- Version = Path.GetFileNameWithoutExtension(versionedDirectoryPath)
- };
- }
-
- /// <summary>
- /// Extracts the tools.
- /// </summary>
- /// <param name="assembly">The assembly.</param>
- /// <param name="zipFileResourcePath">The zip file resource path.</param>
- /// <param name="targetPath">The target path.</param>
- private async Task ExtractTools(Assembly assembly, string zipFileResourcePath, string targetPath)
- {
- using (var resourceStream = assembly.GetManifestResourceStream(zipFileResourcePath))
- {
- _zipClient.ExtractAll(resourceStream, targetPath, false);
- }
-
- try
- {
- await DownloadFonts(targetPath).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting ffmpeg font files", ex);
- }
- }
-
- private const string FontUrl = "https://www.dropbox.com/s/9nb76tybcsw5xrk/ARIALUNI.zip?dl=1";
-
- /// <summary>
- /// Extracts the fonts.
- /// </summary>
- /// <param name="targetPath">The target path.</param>
- private async Task DownloadFonts(string targetPath)
- {
- var fontsDirectory = Path.Combine(targetPath, "fonts");
-
- if (!Directory.Exists(fontsDirectory))
- {
- Directory.CreateDirectory(fontsDirectory);
- }
-
- const string fontFilename = "ARIALUNI.TTF";
-
- var fontFile = Path.Combine(fontsDirectory, fontFilename);
-
- if (!File.Exists(fontFile))
- {
- await DownloadFontFile(fontsDirectory, fontFilename).ConfigureAwait(false);
- }
-
- await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false);
- }
-
- /// <summary>
- /// Downloads the font file.
- /// </summary>
- /// <param name="fontsDirectory">The fonts directory.</param>
- /// <param name="fontFilename">The font filename.</param>
- /// <returns>Task.</returns>
- private async Task DownloadFontFile(string fontsDirectory, string fontFilename)
- {
- var existingFile = Directory
- .EnumerateFiles(_appPaths.ProgramDataPath, fontFilename, SearchOption.AllDirectories)
- .FirstOrDefault();
-
- if (existingFile != null)
- {
- try
- {
- File.Copy(existingFile, Path.Combine(fontsDirectory, fontFilename), true);
- return;
- }
- catch (IOException ex)
- {
- // Log this, but don't let it fail the operation
- _logger.ErrorException("Error copying file", ex);
- }
- }
-
- var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions
- {
- Url = FontUrl,
- Progress = new Progress<double>()
- });
-
- _zipClient.ExtractAll(tempFile, fontsDirectory, true);
-
- try
- {
- File.Delete(tempFile);
- }
- catch (IOException ex)
- {
- // Log this, but don't let it fail the operation
- _logger.ErrorException("Error deleting temp file {0}", ex, tempFile);
- }
- }
-
- /// <summary>
- /// Writes the font config file.
- /// </summary>
- /// <param name="fontsDirectory">The fonts directory.</param>
- /// <returns>Task.</returns>
- private async Task WriteFontConfigFile(string fontsDirectory)
- {
- const string fontConfigFilename = "fonts.conf";
- var fontConfigFile = Path.Combine(fontsDirectory, fontConfigFilename);
-
- if (!File.Exists(fontConfigFile))
- {
- var contents = string.Format("<?xml version=\"1.0\"?><fontconfig><dir>{0}</dir><alias><family>Arial</family><prefer>Arial Unicode MS</prefer></alias></fontconfig>", fontsDirectory);
-
- var bytes = Encoding.UTF8.GetBytes(contents);
-
- using (var fileStream = new FileStream(fontConfigFile, FileMode.Create, FileAccess.Write,
- FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize,
- FileOptions.Asynchronous))
- {
- await fileStream.WriteAsync(bytes, 0, bytes.Length);
- }
- }
- }
-
- /// <summary>
- /// Gets the media tools path.
- /// </summary>
- /// <param name="create">if set to <c>true</c> [create].</param>
- /// <returns>System.String.</returns>
- private string GetMediaToolsPath(bool create)
- {
- var path = Path.Combine(_appPaths.ProgramDataPath, "ffmpeg");
-
- if (create && !Directory.Exists(path))
- {
- Directory.CreateDirectory(path);
- }
-
- return path;
- }
- }
-
- public class FFMpegInfo
- {
- public string Path { get; set; }
- public string ProbePath { get; set; }
- public string Version { get; set; }
- }
-}
diff --git a/MediaBrowser.ServerApplication/Implementations/ffmpeg20130904.zip.REMOVED.git-id b/MediaBrowser.ServerApplication/Implementations/ffmpeg20130904.zip.REMOVED.git-id
deleted file mode 100644
index e99d115a4..000000000
--- a/MediaBrowser.ServerApplication/Implementations/ffmpeg20130904.zip.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-3496b2cde22e7c4cb56b480dd2da637167d51e78 \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/Implementations/readme.txt b/MediaBrowser.ServerApplication/Implementations/readme.txt
deleted file mode 100644
index b32dd9aec..000000000
--- a/MediaBrowser.ServerApplication/Implementations/readme.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is the 32-bit static build of ffmpeg, located at:
-
-http://ffmpeg.zeranoe.com/builds/
-
-The zip file contains both ffmpeg and ffprobe, and is suffixed with the date of the build. \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index e9c1fdc99..55fa60ed2 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -11,7 +11,6 @@ using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Threading;
-using System.Threading.Tasks;
using System.Windows;
namespace MediaBrowser.ServerApplication
diff --git a/MediaBrowser.ServerApplication/MainWindow.xaml.cs b/MediaBrowser.ServerApplication/MainWindow.xaml.cs
index 4c9c065e6..c22c35be8 100644
--- a/MediaBrowser.ServerApplication/MainWindow.xaml.cs
+++ b/MediaBrowser.ServerApplication/MainWindow.xaml.cs
@@ -12,6 +12,7 @@ using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Threading;
+using MediaBrowser.ServerApplication.Native;
namespace MediaBrowser.ServerApplication
{
@@ -188,19 +189,19 @@ namespace MediaBrowser.ServerApplication
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
void cmdApiDocs_Click(object sender, EventArgs e)
{
- App.OpenUrl("http://localhost:" + _configurationManager.Configuration.HttpServerPortNumber + "/" +
- _appHost.WebApplicationName + "/metadata");
+ BrowserLauncher.OpenUrl("http://localhost:" + _configurationManager.Configuration.HttpServerPortNumber + "/" +
+ _appHost.WebApplicationName + "/metadata", _logger);
}
void cmdSwaggerApiDocs_Click(object sender, EventArgs e)
{
- App.OpenUrl("http://localhost:" + _configurationManager.Configuration.HttpServerPortNumber + "/" +
- _appHost.WebApplicationName + "/swagger-ui/index.html");
+ BrowserLauncher.OpenUrl("http://localhost:" + _configurationManager.Configuration.HttpServerPortNumber + "/" +
+ _appHost.WebApplicationName + "/swagger-ui/index.html", _logger);
}
void cmdGithubWiki_Click(object sender, EventArgs e)
{
- App.OpenUrl("https://github.com/MediaBrowser/MediaBrowser/wiki");
+ BrowserLauncher.OpenUrl("https://github.com/MediaBrowser/MediaBrowser/wiki", _logger);
}
/// <summary>
@@ -254,7 +255,7 @@ namespace MediaBrowser.ServerApplication
/// </summary>
private void OpenDashboard(User loggedInUser)
{
- App.OpenDashboardPage("dashboard.html", loggedInUser, _configurationManager, _appHost);
+ BrowserLauncher.OpenDashboardPage("dashboard.html", loggedInUser, _configurationManager, _appHost, _logger);
}
/// <summary>
@@ -264,7 +265,7 @@ namespace MediaBrowser.ServerApplication
/// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
private void cmVisitCT_click(object sender, RoutedEventArgs e)
{
- App.OpenUrl("http://community.mediabrowser.tv/");
+ BrowserLauncher.OpenUrl("http://community.mediabrowser.tv/", _logger);
}
/// <summary>
@@ -275,7 +276,7 @@ namespace MediaBrowser.ServerApplication
private void cmdBrowseLibrary_click(object sender, RoutedEventArgs e)
{
var user = _userManager.Users.FirstOrDefault(u => u.Configuration.IsAdministrator);
- App.OpenDashboardPage("index.html", user, _configurationManager, _appHost);
+ BrowserLauncher.OpenDashboardPage("index.html", user, _configurationManager, _appHost, _logger);
}
/// <summary>
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 043d5c18f..61ec19dd5 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -130,10 +130,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MediaBrowser.IsoMounting.3.0.56\lib\net45\MediaBrowser.IsoMounter.dll</HintPath>
</Reference>
- <Reference Include="MoreLinq, Version=1.0.16006.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll</HintPath>
- </Reference>
<Reference Include="NLog, Version=2.0.1.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\NLog.2.0.1.2\lib\net45\NLog.dll</HintPath>
@@ -187,7 +183,6 @@
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.WebRequest" />
- <Reference Include="System.Runtime.Remoting" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
@@ -209,12 +204,19 @@
<SubType>Component</SubType>
</Compile>
<Compile Include="EntryPoints\StartupWizard.cs" />
- <Compile Include="EntryPoints\UdpServerEntryPoint.cs" />
- <Compile Include="Implementations\FFMpegDownloader.cs" />
+ <Compile Include="FFMpeg\FFMpegInfo.cs" />
+ <Compile Include="Native\Assemblies.cs" />
+ <Compile Include="Native\HttpMessageHandlerFactory.cs" />
+ <Compile Include="Native\NativeApp.cs" />
+ <Compile Include="Native\ServerAuthorization.cs" />
+ <Compile Include="Native\Autorun.cs" />
+ <Compile Include="Native\BrowserLauncher.cs" />
+ <Compile Include="FFMpeg\FFMpegDownloader.cs" />
<Compile Include="MainStartup.cs" />
<Compile Include="BackgroundServiceInstaller.cs">
<SubType>Component</SubType>
</Compile>
+ <Compile Include="Native\Sqlite.cs" />
<Compile Include="Splash\SplashWindow.xaml.cs">
<DependentUpon>SplashWindow.xaml</DependentUpon>
</Compile>
@@ -242,7 +244,6 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="ApplicationHost.cs" />
- <Compile Include="Implementations\DotNetZipClient.cs" />
<Compile Include="LibraryExplorer.xaml.cs">
<DependentUpon>LibraryExplorer.xaml</DependentUpon>
</Compile>
@@ -278,14 +279,15 @@
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="app.manifest" />
- <EmbeddedResource Include="Implementations\ffmpeg20130904.zip" />
+ <None Include="FFMpeg\ARIALUNI.7z" />
+ <None Include="FFMpeg\ffmpeg-20130904-git-f974289-win32-static.7z" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
- <EmbeddedResource Include="RegisterServer.bat" />
+ <EmbeddedResource Include="Native\RegisterServer.bat" />
</ItemGroup>
<ItemGroup>
<None Include="App.config">
@@ -390,9 +392,6 @@
<ItemGroup>
<Resource Include="Resources\Images\mb3logo800.png" />
</ItemGroup>
- <ItemGroup>
- <EmbeddedResource Include="Implementations\readme.txt" />
- </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>if $(ConfigurationName) == Release (
diff --git a/MediaBrowser.ServerApplication/Native/Assemblies.cs b/MediaBrowser.ServerApplication/Native/Assemblies.cs
new file mode 100644
index 000000000..b43dc1a10
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Native/Assemblies.cs
@@ -0,0 +1,25 @@
+using MediaBrowser.IsoMounter;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ /// <summary>
+ /// Class Assemblies
+ /// </summary>
+ public static class Assemblies
+ {
+ /// <summary>
+ /// Gets the assemblies with parts.
+ /// </summary>
+ /// <returns>List{Assembly}.</returns>
+ public static List<Assembly> GetAssembliesWithParts()
+ {
+ var list = new List<Assembly>();
+
+ list.Add(typeof(PismoIsoManager).Assembly);
+
+ return list;
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/Native/Autorun.cs b/MediaBrowser.ServerApplication/Native/Autorun.cs
new file mode 100644
index 000000000..d1c02db84
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Native/Autorun.cs
@@ -0,0 +1,31 @@
+using System;
+using System.IO;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ /// <summary>
+ /// Class Autorun
+ /// </summary>
+ public static class Autorun
+ {
+ /// <summary>
+ /// Configures the specified autorun.
+ /// </summary>
+ /// <param name="autorun">if set to <c>true</c> [autorun].</param>
+ public static void Configure(bool autorun)
+ {
+ var shortcutPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Media Browser 3", "Media Browser Server.lnk");
+
+ if (autorun)
+ {
+ //Copy our shortut into the startup folder for this user
+ File.Copy(shortcutPath, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), Path.GetFileName(shortcutPath) ?? "MBstartup.lnk"), true);
+ }
+ else
+ {
+ //Remove our shortcut from the startup folder for this user
+ File.Delete(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), Path.GetFileName(shortcutPath) ?? "MBstartup.lnk"));
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/Native/BrowserLauncher.cs b/MediaBrowser.ServerApplication/Native/BrowserLauncher.cs
new file mode 100644
index 000000000..e7d041d15
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Native/BrowserLauncher.cs
@@ -0,0 +1,68 @@
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Logging;
+using System;
+using System.Diagnostics;
+using System.Windows.Forms;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ public static class BrowserLauncher
+ {
+ /// <summary>
+ /// Opens the dashboard page.
+ /// </summary>
+ /// <param name="page">The page.</param>
+ /// <param name="loggedInUser">The logged in user.</param>
+ /// <param name="configurationManager">The configuration manager.</param>
+ /// <param name="appHost">The app host.</param>
+ public static void OpenDashboardPage(string page, User loggedInUser, IServerConfigurationManager configurationManager, IServerApplicationHost appHost, ILogger logger)
+ {
+ var url = "http://localhost:" + configurationManager.Configuration.HttpServerPortNumber + "/" +
+ appHost.WebApplicationName + "/dashboard/" + page;
+
+ OpenUrl(url, logger);
+ }
+
+ /// <summary>
+ /// Opens the URL.
+ /// </summary>
+ /// <param name="url">The URL.</param>
+ public static void OpenUrl(string url, ILogger logger)
+ {
+ var process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ FileName = url
+ },
+
+ EnableRaisingEvents = true
+ };
+
+ process.Exited += ProcessExited;
+
+ try
+ {
+ process.Start();
+ }
+ catch (Exception ex)
+ {
+ logger.ErrorException("Error launching url: {0}", ex, url);
+
+ MessageBox.Show("There was an error launching your web browser. Please check your default browser settings.");
+ }
+ }
+
+ /// <summary>
+ /// Processes the exited.
+ /// </summary>
+ /// <param name="sender">The sender.</param>
+ /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
+ private static void ProcessExited(object sender, EventArgs e)
+ {
+ ((Process)sender).Dispose();
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/Native/HttpMessageHandlerFactory.cs b/MediaBrowser.ServerApplication/Native/HttpMessageHandlerFactory.cs
new file mode 100644
index 000000000..4bbcc9ea0
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Native/HttpMessageHandlerFactory.cs
@@ -0,0 +1,26 @@
+using System.Net;
+using System.Net.Cache;
+using System.Net.Http;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ /// <summary>
+ /// Class HttpMessageHandlerFactory
+ /// </summary>
+ public static class HttpMessageHandlerFactory
+ {
+ /// <summary>
+ /// Gets the HTTP message handler.
+ /// </summary>
+ /// <param name="enableHttpCompression">if set to <c>true</c> [enable HTTP compression].</param>
+ /// <returns>HttpMessageHandler.</returns>
+ public static HttpMessageHandler GetHttpMessageHandler(bool enableHttpCompression)
+ {
+ return new WebRequestHandler
+ {
+ CachePolicy = new RequestCachePolicy(RequestCacheLevel.Revalidate),
+ AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None
+ };
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/Native/NativeApp.cs b/MediaBrowser.ServerApplication/Native/NativeApp.cs
new file mode 100644
index 000000000..ea4218afc
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Native/NativeApp.cs
@@ -0,0 +1,25 @@
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ /// <summary>
+ /// Class NativeApp
+ /// </summary>
+ public static class NativeApp
+ {
+ /// <summary>
+ /// Shutdowns this instance.
+ /// </summary>
+ public static void Shutdown()
+ {
+ MainStartup.Shutdown();
+ }
+
+ /// <summary>
+ /// Restarts this instance.
+ /// </summary>
+ public static void Restart()
+ {
+ MainStartup.Restart();
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/RegisterServer.bat b/MediaBrowser.ServerApplication/Native/RegisterServer.bat
index d762dfaf7..d762dfaf7 100644
--- a/MediaBrowser.ServerApplication/RegisterServer.bat
+++ b/MediaBrowser.ServerApplication/Native/RegisterServer.bat
diff --git a/MediaBrowser.ServerApplication/Native/ServerAuthorization.cs b/MediaBrowser.ServerApplication/Native/ServerAuthorization.cs
new file mode 100644
index 000000000..91f0974eb
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Native/ServerAuthorization.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ /// <summary>
+ /// Class Authorization
+ /// </summary>
+ public static class ServerAuthorization
+ {
+ /// <summary>
+ /// Authorizes the server.
+ /// </summary>
+ /// <param name="httpServerPort">The HTTP server port.</param>
+ /// <param name="httpServerUrlPrefix">The HTTP server URL prefix.</param>
+ /// <param name="webSocketPort">The web socket port.</param>
+ /// <param name="udpPort">The UDP port.</param>
+ /// <param name="tempDirectory">The temp directory.</param>
+ public static void AuthorizeServer(int httpServerPort, string httpServerUrlPrefix, int webSocketPort, int udpPort, string tempDirectory)
+ {
+ // Create a temp file path to extract the bat file to
+ var tmpFile = Path.Combine(tempDirectory, Guid.NewGuid() + ".bat");
+
+ // Extract the bat file
+ using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(typeof(ServerAuthorization).Namespace + ".RegisterServer.bat"))
+ {
+ using (var fileStream = File.Create(tmpFile))
+ {
+ stream.CopyTo(fileStream);
+ }
+ }
+
+ var startInfo = new ProcessStartInfo
+ {
+ FileName = tmpFile,
+
+ Arguments = string.Format("{0} {1} {2} {3}", httpServerPort,
+ httpServerUrlPrefix,
+ udpPort,
+ webSocketPort),
+
+ CreateNoWindow = true,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ Verb = "runas",
+ ErrorDialog = false
+ };
+
+ using (var process = Process.Start(startInfo))
+ {
+ process.WaitForExit();
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/Native/Sqlite.cs b/MediaBrowser.ServerApplication/Native/Sqlite.cs
new file mode 100644
index 000000000..cc20952d7
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Native/Sqlite.cs
@@ -0,0 +1,36 @@
+using System.Data;
+using System.Data.SQLite;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ /// <summary>
+ /// Class Sqlite
+ /// </summary>
+ public static class Sqlite
+ {
+ /// <summary>
+ /// Connects to db.
+ /// </summary>
+ /// <param name="dbPath">The db path.</param>
+ /// <returns>Task{IDbConnection}.</returns>
+ /// <exception cref="System.ArgumentNullException">dbPath</exception>
+ public static async Task<IDbConnection> OpenDatabase(string dbPath)
+ {
+ var connectionstr = new SQLiteConnectionStringBuilder
+ {
+ PageSize = 4096,
+ CacheSize = 4096,
+ SyncMode = SynchronizationModes.Normal,
+ DataSource = dbPath,
+ JournalMode = SQLiteJournalModeEnum.Wal
+ };
+
+ var connection = new SQLiteConnection(connectionstr.ConnectionString);
+
+ await connection.OpenAsync().ConfigureAwait(false);
+
+ return connection;
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/Resources/Images/mb3logo800.png b/MediaBrowser.ServerApplication/Resources/Images/mb3logo800.png
index fbc769a6f..12db84679 100644
--- a/MediaBrowser.ServerApplication/Resources/Images/mb3logo800.png
+++ b/MediaBrowser.ServerApplication/Resources/Images/mb3logo800.png
Binary files differ
diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config
index 8c1821ca5..e680b556f 100644
--- a/MediaBrowser.ServerApplication/packages.config
+++ b/MediaBrowser.ServerApplication/packages.config
@@ -4,7 +4,6 @@
<package id="Hardcodet.Wpf.TaskbarNotification" version="1.0.4.0" targetFramework="net45" />
<package id="MahApps.Metro" version="0.11.0.17-ALPHA" targetFramework="net45" />
<package id="MediaBrowser.IsoMounting" version="3.0.56" targetFramework="net45" />
- <package id="morelinq" version="1.0.16006" targetFramework="net45" />
<package id="NLog" version="2.0.1.2" targetFramework="net45" />
<package id="ServiceStack" version="3.9.62" targetFramework="net45" />
<package id="ServiceStack.Common" version="3.9.62" targetFramework="net45" />
diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js
index d139adfc3..189812a3c 100644
--- a/MediaBrowser.WebDashboard/ApiClient.js
+++ b/MediaBrowser.WebDashboard/ApiClient.js
@@ -3200,7 +3200,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
* @param {String} userId
* @param {String} itemId
*/
- self.reportPlaybackStart = function (userId, itemId) {
+ self.reportPlaybackStart = function (userId, itemId, canSeek, queueableMediaTypes) {
if (!userId) {
throw new Error("null userId");
@@ -3210,17 +3210,26 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
throw new Error("null itemId");
}
+ canSeek = canSeek || false;
+ queueableMediaTypes = queueableMediaTypes || '';
+
if (self.isWebSocketOpen()) {
var deferred = $.Deferred();
- self.sendWebSocketMessage("PlaybackStart", itemId);
+ var msg = [itemId, canSeek, queueableMediaTypes];
+
+ self.sendWebSocketMessage("PlaybackStart", msg.join('|'));
deferred.resolveWith(null, []);
return deferred.promise();
}
- var url = self.getUrl("Users/" + userId + "/PlayingItems/" + itemId);
+ var url = self.getUrl("Users/" + userId + "/PlayingItems/" + itemId, {
+
+ CanSeek: canSeek,
+ QueueableMediaTypes: queueableMediaTypes
+ });
return self.ajax({
type: "POST",
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 06f930238..6a599da45 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -13,6 +13,8 @@
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -35,24 +37,21 @@
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
- <Reference Include="ServiceStack.Common, Version=3.9.60.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Common.dll</HintPath>
- </Reference>
- <Reference Include="ServiceStack.Interfaces, Version=3.9.60.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Interfaces.dll</HintPath>
- </Reference>
- <Reference Include="ServiceStack.Text, Version=3.9.59.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
- </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
+ <Reference Include="ServiceStack.Common">
+ <HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Common.dll</HintPath>
+ </Reference>
+ <Reference Include="ServiceStack.Interfaces">
+ <HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Interfaces.dll</HintPath>
+ </Reference>
+ <Reference Include="ServiceStack.Text">
+ <HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
@@ -67,15 +66,15 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
- <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
+ <Project>{9142EEFA-7570-41E1-BFCC-468BB571AF2F}</Project>
<Name>MediaBrowser.Common</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
- <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
+ <Project>{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}</Project>
<Name>MediaBrowser.Controller</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
- <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
+ <Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
@@ -255,10 +254,10 @@
<Content Include="dashboard-ui\css\images\userdata\thumbs_up_on.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\userdata\unplayed.png">
+ <Content Include="dashboard-ui\css\images\userdata\playedoff.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\userdata\played.png">
+ <Content Include="dashboard-ui\css\images\userdata\playedon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\views\games.png">
diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config
index 25b4f7b47..1c5a0f818 100644
--- a/MediaBrowser.WebDashboard/packages.config
+++ b/MediaBrowser.WebDashboard/packages.config
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="MediaBrowser.ApiClient.Javascript" version="3.0.175" targetFramework="net45" />
+ <package id="MediaBrowser.ApiClient.Javascript" version="3.0.176" targetFramework="net45" />
<package id="ServiceStack.Common" version="3.9.62" targetFramework="net45" />
<package id="ServiceStack.Text" version="3.9.62" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index 1d104c45b..eb846cd2f 100644
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ b/Nuget/MediaBrowser.Common.Internal.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common.Internal</id>
- <version>3.0.206</version>
+ <version>3.0.208</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.206" />
+ <dependency id="MediaBrowser.Common" version="3.0.208" />
<dependency id="NLog" version="2.0.1.2" />
<dependency id="ServiceStack.Text" version="3.9.58" />
<dependency id="SimpleInjector" version="2.3.2" />
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index 0670bcacf..ba211c3d6 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common</id>
- <version>3.0.206</version>
+ <version>3.0.208</version>
<title>MediaBrowser.Common</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index f5aa2d460..c6f801a9b 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Server.Core</id>
- <version>3.0.206</version>
+ <version>3.0.208</version>
<title>Media Browser.Server.Core</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Media Browser Server.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.206" />
+ <dependency id="MediaBrowser.Common" version="3.0.208" />
</dependencies>
</metadata>
<files>