aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2014-10-11 16:38:13 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2014-10-11 16:38:13 -0400
commitf3539686bd7ff6c748a0a9441086538081fa8903 (patch)
tree84b6a6e89fddb206d3b8cc503423876e45100fa9
parent2486cffa7171629d09857981b8987727642f6f02 (diff)
add device upload options
-rw-r--r--MediaBrowser.Api/Devices/DeviceService.cs107
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj1
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs19
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs2
-rw-r--r--MediaBrowser.Api/Session/SessionsService.cs9
-rw-r--r--MediaBrowser.Api/UserService.cs1
-rw-r--r--MediaBrowser.Common/Net/MimeTypes.cs15
-rw-r--r--MediaBrowser.Controller/Devices/IDeviceManager.cs71
-rw-r--r--MediaBrowser.Controller/Devices/IDeviceRepository.cs66
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj2
-rw-r--r--MediaBrowser.Controller/Session/ISessionManager.cs2
-rw-r--r--MediaBrowser.Controller/Sync/ISyncManager.cs4
-rw-r--r--MediaBrowser.Dlna/DlnaManager.cs2
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToManager.cs22
-rw-r--r--MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj18
-rw-r--r--MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj15
-rw-r--r--MediaBrowser.Model/ApiClient/IApiClient.cs35
-rw-r--r--MediaBrowser.Model/ApiClient/IDevice.cs44
-rw-r--r--MediaBrowser.Model/Devices/ContentUploadHistory.cs15
-rw-r--r--MediaBrowser.Model/Devices/DeviceInfo.cs44
-rw-r--r--MediaBrowser.Model/Devices/DevicesOptions.cs14
-rw-r--r--MediaBrowser.Model/Devices/LocalFileInfo.cs11
-rw-r--r--MediaBrowser.Model/Dlna/Profiles/AndroidProfile.cs6
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs6
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs12
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj6
-rw-r--r--MediaBrowser.Model/Session/ClientCapabilities.cs7
-rw-r--r--MediaBrowser.Model/Session/SessionCapabilities.cs21
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs60
-rw-r--r--MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs68
-rw-r--r--MediaBrowser.Server.Implementations/Devices/DeviceManager.cs149
-rw-r--r--MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs176
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserViewManager.cs26
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json9
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/server.json10
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj3
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs80
-rw-r--r--MediaBrowser.Server.Implementations/Session/WebSocketController.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncManager.cs4
-rw-r--r--MediaBrowser.Server.Mono/app.config10
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs20
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs2
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj15
-rw-r--r--MediaBrowser.WebDashboard/app.config1
-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.Model.Signed.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec4
-rw-r--r--SharedVersion.cs3
50 files changed, 1025 insertions, 204 deletions
diff --git a/MediaBrowser.Api/Devices/DeviceService.cs b/MediaBrowser.Api/Devices/DeviceService.cs
new file mode 100644
index 000000000..55980bc00
--- /dev/null
+++ b/MediaBrowser.Api/Devices/DeviceService.cs
@@ -0,0 +1,107 @@
+using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Net;
+using MediaBrowser.Model.Devices;
+using ServiceStack;
+using ServiceStack.Web;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Api.Devices
+{
+ [Route("/Devices", "GET", Summary = "Gets all devices")]
+ public class GetDevices : IReturn<List<DeviceInfo>>
+ {
+ [ApiMember(Name = "SupportsContentUploading", Description = "SupportsContentUploading", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public bool? SupportsContentUploading { get; set; }
+ }
+
+ [Route("/Devices", "DELETE", Summary = "Deletes a device")]
+ public class DeleteDevice
+ {
+ [ApiMember(Name = "Id", Description = "Device Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
+ public string Id { get; set; }
+ }
+
+ [Route("/Devices/CameraUploads", "GET", Summary = "Gets camera upload history for a device")]
+ public class GetCameraUploads : IReturn<ContentUploadHistory>
+ {
+ [ApiMember(Name = "Id", Description = "Device Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string DeviceId { get; set; }
+ }
+
+ [Route("/Devices/CameraUploads", "POST", Summary = "Uploads content")]
+ public class PostCameraUpload : IRequiresRequestStream, IReturnVoid
+ {
+ [ApiMember(Name = "Id", Description = "Device Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string DeviceId { get; set; }
+
+ [ApiMember(Name = "Album", Description = "Album", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string Album { get; set; }
+
+ [ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string Name { get; set; }
+
+ [ApiMember(Name = "FullPath", Description = "FullPath", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string FullPath { get; set; }
+
+ public Stream RequestStream { get; set; }
+ }
+
+ [Authenticated]
+ public class DeviceService : BaseApiService
+ {
+ private readonly IDeviceManager _deviceManager;
+
+ public DeviceService(IDeviceManager deviceManager)
+ {
+ _deviceManager = deviceManager;
+ }
+
+ public object Get(GetDevices request)
+ {
+ var devices = _deviceManager.GetDevices();
+
+ if (request.SupportsContentUploading.HasValue)
+ {
+ var val = request.SupportsContentUploading.Value;
+
+ devices = devices.Where(i => i.Capabilities.SupportsContentUploading == val);
+ }
+
+ return ToOptimizedResult(devices.ToList());
+ }
+
+ public object Get(GetCameraUploads request)
+ {
+ return ToOptimizedResult(_deviceManager.GetCameraUploadHistory(request.DeviceId));
+ }
+
+ public void Delete(DeleteDevice request)
+ {
+ var task = _deviceManager.DeleteDevice(request.Id);
+
+ Task.WaitAll(task);
+ }
+
+ public void Post(PostCameraUpload request)
+ {
+ var deviceId = request.DeviceId;
+
+ var album = Request.QueryString["Album"];
+ var fullPath = Request.QueryString["FullPath"];
+ var name = Request.QueryString["Name"];
+
+ var task = _deviceManager.AcceptCameraUpload(deviceId, request.RequestStream, new LocalFileInfo
+ {
+ MimeType = Request.ContentType,
+ Album = album,
+ Name = name,
+ FullPath = fullPath
+ });
+
+ Task.WaitAll(task);
+ }
+ }
+}
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index db939366a..732d602c6 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -71,6 +71,7 @@
<Compile Include="BrandingService.cs" />
<Compile Include="ChannelService.cs" />
<Compile Include="ConnectService.cs" />
+ <Compile Include="Devices\DeviceService.cs" />
<Compile Include="Dlna\DlnaServerService.cs" />
<Compile Include="Dlna\DlnaService.cs" />
<Compile Include="Library\ChapterService.cs" />
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 50929e6f3..94cf984d2 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -316,17 +316,22 @@ namespace MediaBrowser.Api.Playback.Progressive
CancellationToken = cancellationTokenSource.Token
};
- var response = await HttpClient.GetResponse(options).ConfigureAwait(false);
-
- responseHeaders["Accept-Ranges"] = "none";
+ if (!string.IsNullOrWhiteSpace(Request.QueryString["Range"]))
+ {
+ options.RequestHeaders["Range"] = Request.QueryString["Range"];
+ }
- var length = response.Headers["Content-Length"];
+ var response = await HttpClient.GetResponse(options).ConfigureAwait(false);
- if (!string.IsNullOrEmpty(length))
+ foreach (var name in new[] { "Content-Length", "Content-Range", "Accept-Ranges" })
{
- responseHeaders["Content-Length"] = length;
+ var val = response.Headers[name];
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ responseHeaders[name] = val;
+ }
}
-
+
if (isHeadRequest)
{
using (response.Content)
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index af3cb25ee..a64866d68 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -32,6 +32,7 @@ namespace MediaBrowser.Api.Playback.Progressive
[Route("/Videos/{Id}/stream.3gp", "GET")]
[Route("/Videos/{Id}/stream.wmv", "GET")]
[Route("/Videos/{Id}/stream.wtv", "GET")]
+ [Route("/Videos/{Id}/stream.mov", "GET")]
[Route("/Videos/{Id}/stream", "GET")]
[Route("/Videos/{Id}/stream.ts", "HEAD")]
[Route("/Videos/{Id}/stream.webm", "HEAD")]
@@ -48,6 +49,7 @@ namespace MediaBrowser.Api.Playback.Progressive
[Route("/Videos/{Id}/stream.wmv", "HEAD")]
[Route("/Videos/{Id}/stream.wtv", "HEAD")]
[Route("/Videos/{Id}/stream.m2ts", "HEAD")]
+ [Route("/Videos/{Id}/stream.mov", "HEAD")]
[Route("/Videos/{Id}/stream", "HEAD")]
[Api(Description = "Gets a video stream")]
public class GetVideoStream : VideoStreamRequest
diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs
index e2c10c0c8..014bedbd9 100644
--- a/MediaBrowser.Api/Session/SessionsService.cs
+++ b/MediaBrowser.Api/Session/SessionsService.cs
@@ -235,6 +235,9 @@ namespace MediaBrowser.Api.Session
[ApiMember(Name = "SupportsMediaControl", Description = "Determines whether media can be played remotely.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
public bool SupportsMediaControl { get; set; }
+
+ [ApiMember(Name = "SupportsContentUploading", Description = "Determines whether camera upload is supported.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
+ public bool SupportsContentUploading { get; set; }
}
[Route("/Sessions/Logout", "POST", Summary = "Reports that a session has ended")]
@@ -494,7 +497,7 @@ namespace MediaBrowser.Api.Session
{
request.Id = GetSession().Id;
}
- _sessionManager.ReportCapabilities(request.Id, new SessionCapabilities
+ _sessionManager.ReportCapabilities(request.Id, new ClientCapabilities
{
PlayableMediaTypes = request.PlayableMediaTypes.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(),
@@ -502,7 +505,9 @@ namespace MediaBrowser.Api.Session
SupportsMediaControl = request.SupportsMediaControl,
- MessageCallbackUrl = request.MessageCallbackUrl
+ MessageCallbackUrl = request.MessageCallbackUrl,
+
+ SupportsContentUploading = request.SupportsContentUploading
});
}
}
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index 2c504bee1..10595d926 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -179,7 +179,6 @@ namespace MediaBrowser.Api
/// <param name="userManager">The user manager.</param>
/// <param name="dtoService">The dto service.</param>
/// <param name="sessionMananger">The session mananger.</param>
- /// <exception cref="System.ArgumentNullException">xmlSerializer</exception>
public UserService(IUserManager userManager, IDtoService dtoService, ISessionManager sessionMananger, IServerConfigurationManager config, INetworkManager networkManager)
{
_userManager = userManager;
diff --git a/MediaBrowser.Common/Net/MimeTypes.cs b/MediaBrowser.Common/Net/MimeTypes.cs
index 1503d0b43..a135dfa30 100644
--- a/MediaBrowser.Common/Net/MimeTypes.cs
+++ b/MediaBrowser.Common/Net/MimeTypes.cs
@@ -315,5 +315,20 @@ namespace MediaBrowser.Common.Net
throw new ArgumentException("Argument not supported: " + path);
}
+
+ private static readonly Dictionary<string, string> MimeExtensions =
+ new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
+ {
+ {"image/jpeg", "jpg"},
+ {"image/jpg", "jpg"},
+ {"image/png", "png"},
+ {"image/gif", "gif"},
+ {"image/webp", "webp"}
+ };
+
+ public static string ToExtension(string mimeType)
+ {
+ return "." + MimeExtensions[mimeType];
+ }
}
}
diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs
new file mode 100644
index 000000000..b82c39eff
--- /dev/null
+++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs
@@ -0,0 +1,71 @@
+using MediaBrowser.Model.Devices;
+using MediaBrowser.Model.Session;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Devices
+{
+ public interface IDeviceManager
+ {
+ /// <summary>
+ /// Registers the device.
+ /// </summary>
+ /// <param name="reportedId">The reported identifier.</param>
+ /// <param name="name">The name.</param>
+ /// <param name="usedByUserId">The used by user identifier.</param>
+ /// <returns>Task.</returns>
+ Task RegisterDevice(string reportedId, string name, string usedByUserId);
+
+ /// <summary>
+ /// Saves the capabilities.
+ /// </summary>
+ /// <param name="reportedId">The reported identifier.</param>
+ /// <param name="capabilities">The capabilities.</param>
+ /// <returns>Task.</returns>
+ Task SaveCapabilities(string reportedId, ClientCapabilities capabilities);
+
+ /// <summary>
+ /// Gets the capabilities.
+ /// </summary>
+ /// <param name="reportedId">The reported identifier.</param>
+ /// <returns>ClientCapabilities.</returns>
+ ClientCapabilities GetCapabilities(string reportedId);
+
+ /// <summary>
+ /// Gets the device information.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <returns>DeviceInfo.</returns>
+ DeviceInfo GetDevice(string id);
+
+ /// <summary>
+ /// Gets the devices.
+ /// </summary>
+ /// <returns>IEnumerable&lt;DeviceInfo&gt;.</returns>
+ IEnumerable<DeviceInfo> GetDevices();
+
+ /// <summary>
+ /// Deletes the device.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <returns>Task.</returns>
+ Task DeleteDevice(string id);
+
+ /// <summary>
+ /// Gets the upload history.
+ /// </summary>
+ /// <param name="deviceId">The device identifier.</param>
+ /// <returns>ContentUploadHistory.</returns>
+ ContentUploadHistory GetCameraUploadHistory(string deviceId);
+
+ /// <summary>
+ /// Accepts the upload.
+ /// </summary>
+ /// <param name="deviceId">The device identifier.</param>
+ /// <param name="stream">The stream.</param>
+ /// <param name="file">The file.</param>
+ /// <returns>Task.</returns>
+ Task AcceptCameraUpload(string deviceId, Stream stream, LocalFileInfo file);
+ }
+}
diff --git a/MediaBrowser.Controller/Devices/IDeviceRepository.cs b/MediaBrowser.Controller/Devices/IDeviceRepository.cs
new file mode 100644
index 000000000..736504da3
--- /dev/null
+++ b/MediaBrowser.Controller/Devices/IDeviceRepository.cs
@@ -0,0 +1,66 @@
+using MediaBrowser.Model.Devices;
+using MediaBrowser.Model.Session;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Devices
+{
+ public interface IDeviceRepository
+ {
+ /// <summary>
+ /// Registers the device.
+ /// </summary>
+ /// <param name="device">The device.</param>
+ /// <returns>Task.</returns>
+ Task SaveDevice(DeviceInfo device);
+
+ /// <summary>
+ /// Saves the capabilities.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <param name="capabilities">The capabilities.</param>
+ /// <returns>Task.</returns>
+ Task SaveCapabilities(string id, ClientCapabilities capabilities);
+
+ /// <summary>
+ /// Gets the capabilities.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <returns>ClientCapabilities.</returns>
+ ClientCapabilities GetCapabilities(string id);
+
+ /// <summary>
+ /// Gets the device information.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <returns>DeviceInfo.</returns>
+ DeviceInfo GetDevice(string id);
+
+ /// <summary>
+ /// Gets the devices.
+ /// </summary>
+ /// <returns>IEnumerable&lt;DeviceInfo&gt;.</returns>
+ IEnumerable<DeviceInfo> GetDevices();
+
+ /// <summary>
+ /// Deletes the device.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <returns>Task.</returns>
+ Task DeleteDevice(string id);
+
+ /// <summary>
+ /// Gets the upload history.
+ /// </summary>
+ /// <param name="deviceId">The device identifier.</param>
+ /// <returns>ContentUploadHistory.</returns>
+ ContentUploadHistory GetCameraUploadHistory(string deviceId);
+
+ /// <summary>
+ /// Saves the camera upload history.
+ /// </summary>
+ /// <param name="deviceId">The device identifier.</param>
+ /// <param name="file">The file.</param>
+ void AddCameraUpload(string deviceId, LocalFileInfo file);
+ }
+}
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index d966d4df5..a49d00e87 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -102,6 +102,8 @@
<Compile Include="Connect\ConnectUser.cs" />
<Compile Include="Connect\IConnectManager.cs" />
<Compile Include="Connect\UserLinkResult.cs" />
+ <Compile Include="Devices\IDeviceManager.cs" />
+ <Compile Include="Devices\IDeviceRepository.cs" />
<Compile Include="Dlna\ControlRequest.cs" />
<Compile Include="Dlna\ControlResponse.cs" />
<Compile Include="Dlna\DlnaIconResponse.cs" />
diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs
index f715ce770..c048e3fab 100644
--- a/MediaBrowser.Controller/Session/ISessionManager.cs
+++ b/MediaBrowser.Controller/Session/ISessionManager.cs
@@ -232,7 +232,7 @@ namespace MediaBrowser.Controller.Session
/// </summary>
/// <param name="sessionId">The session identifier.</param>
/// <param name="capabilities">The capabilities.</param>
- void ReportCapabilities(string sessionId, SessionCapabilities capabilities);
+ void ReportCapabilities(string sessionId, ClientCapabilities capabilities);
/// <summary>
/// Reports the transcoding information.
diff --git a/MediaBrowser.Controller/Sync/ISyncManager.cs b/MediaBrowser.Controller/Sync/ISyncManager.cs
index 1d5ab7d3e..1e744a087 100644
--- a/MediaBrowser.Controller/Sync/ISyncManager.cs
+++ b/MediaBrowser.Controller/Sync/ISyncManager.cs
@@ -1,4 +1,6 @@
-using MediaBrowser.Controller.Entities;
+using System.IO;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Devices;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Sync;
using System.Collections.Generic;
diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs
index cd1457169..1a5269b9d 100644
--- a/MediaBrowser.Dlna/DlnaManager.cs
+++ b/MediaBrowser.Dlna/DlnaManager.cs
@@ -79,7 +79,7 @@ namespace MediaBrowser.Dlna
new Windows81Profile(),
//new WindowsMediaCenterProfile(),
new WindowsPhoneProfile(),
- new AndroidProfile(true, true),
+ new AndroidProfile(true, true, new[]{"baseline", "constrained baseline"}),
new DirectTvProfile(),
new DishHopperJoeyProfile(),
new DefaultProfile()
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
index f570209ad..a60b5efa4 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
@@ -117,21 +117,21 @@ namespace MediaBrowser.Dlna.PlayTo
var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ??
_dlnaManager.GetDefaultProfile();
- _sessionManager.ReportCapabilities(sessionInfo.Id, new SessionCapabilities
+ _sessionManager.ReportCapabilities(sessionInfo.Id, new ClientCapabilities
{
PlayableMediaTypes = profile.GetSupportedMediaTypes(),
SupportedCommands = new List<string>
- {
- GeneralCommandType.VolumeDown.ToString(),
- GeneralCommandType.VolumeUp.ToString(),
- GeneralCommandType.Mute.ToString(),
- GeneralCommandType.Unmute.ToString(),
- GeneralCommandType.ToggleMute.ToString(),
- GeneralCommandType.SetVolume.ToString(),
- GeneralCommandType.SetAudioStreamIndex.ToString(),
- GeneralCommandType.SetSubtitleStreamIndex.ToString()
- },
+ {
+ GeneralCommandType.VolumeDown.ToString(),
+ GeneralCommandType.VolumeUp.ToString(),
+ GeneralCommandType.Mute.ToString(),
+ GeneralCommandType.Unmute.ToString(),
+ GeneralCommandType.ToggleMute.ToString(),
+ GeneralCommandType.SetVolume.ToString(),
+ GeneralCommandType.SetAudioStreamIndex.ToString(),
+ GeneralCommandType.SetSubtitleStreamIndex.ToString()
+ },
SupportsMediaControl = true
});
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index e74ab9b7a..f8d2de85a 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -95,6 +95,9 @@
<Compile Include="..\MediaBrowser.Model\ApiClient\IConnectionManager.cs">
<Link>ApiClient\IConnectionManager.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\ApiClient\IDevice.cs">
+ <Link>ApiClient\IDevice.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\ApiClient\IServerEvents.cs">
<Link>ApiClient\IServerEvents.cs</Link>
</Compile>
@@ -212,6 +215,18 @@
<Compile Include="..\MediaBrowser.Model\Connect\UserLinkType.cs">
<Link>Connect\UserLinkType.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Devices\ContentUploadHistory.cs">
+ <Link>Devices\ContentUploadHistory.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Devices\DeviceInfo.cs">
+ <Link>Devices\DeviceInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Devices\DevicesOptions.cs">
+ <Link>Devices\DevicesOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Devices\LocalFileInfo.cs">
+ <Link>Devices\LocalFileInfo.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Dlna\AudioOptions.cs">
<Link>Dlna\AudioOptions.cs</Link>
</Compile>
@@ -932,9 +947,6 @@
<Compile Include="..\MediaBrowser.Model\Session\PlaystateRequest.cs">
<Link>Session\PlaystateRequest.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Session\SessionCapabilities.cs">
- <Link>Session\SessionCapabilities.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Session\SessionInfoDto.cs">
<Link>Session\SessionInfoDto.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index e9f79a503..901862740 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -184,6 +184,18 @@
<Compile Include="..\mediabrowser.model\connect\UserLinkType.cs">
<Link>Connect\UserLinkType.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Devices\ContentUploadHistory.cs">
+ <Link>Devices\ContentUploadHistory.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Devices\DeviceInfo.cs">
+ <Link>Devices\DeviceInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Devices\DevicesOptions.cs">
+ <Link>Devices\DevicesOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Devices\LocalFileInfo.cs">
+ <Link>Devices\LocalFileInfo.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Dlna\AudioOptions.cs">
<Link>Dlna\AudioOptions.cs</Link>
</Compile>
@@ -898,9 +910,6 @@
<Compile Include="..\MediaBrowser.Model\Session\PlaystateRequest.cs">
<Link>Session\PlaystateRequest.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Session\SessionCapabilities.cs">
- <Link>Session\SessionCapabilities.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Session\SessionInfoDto.cs">
<Link>Session\SessionInfoDto.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs
index 9f22de3ac..1d2145b3a 100644
--- a/MediaBrowser.Model/ApiClient/IApiClient.cs
+++ b/MediaBrowser.Model/ApiClient/IApiClient.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Devices;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events;
@@ -794,16 +795,22 @@ namespace MediaBrowser.Model.ApiClient
string ClientName { get; set; }
/// <summary>
+ /// Gets the device.
+ /// </summary>
+ /// <value>The device.</value>
+ IDevice Device { get; }
+
+ /// <summary>
/// Gets or sets the name of the device.
/// </summary>
/// <value>The name of the device.</value>
- string DeviceName { get; set; }
+ string DeviceName { get; }
/// <summary>
/// Gets or sets the device id.
/// </summary>
/// <value>The device id.</value>
- string DeviceId { get; set; }
+ string DeviceId { get; }
/// <summary>
/// Gets or sets the current user id.
@@ -1319,5 +1326,29 @@ namespace MediaBrowser.Model.ApiClient
/// <returns>Task.</returns>
Task SendContextMessageAsync(string itemType, string itemId, string itemName, string context,
CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the content upload history.
+ /// </summary>
+ /// <param name="deviceId">The device identifier.</param>
+ /// <returns>Task&lt;ContentUploadHistory&gt;.</returns>
+ Task<ContentUploadHistory> GetContentUploadHistory(string deviceId);
+
+ /// <summary>
+ /// Uploads the file.
+ /// </summary>
+ /// <param name="stream">The stream.</param>
+ /// <param name="file">The file.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task UploadFile(Stream stream,
+ LocalFileInfo file,
+ CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the devices options options.
+ /// </summary>
+ /// <returns>Task&lt;DevicesOptions&gt;.</returns>
+ Task<DevicesOptions> GetDevicesOptions();
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/ApiClient/IDevice.cs b/MediaBrowser.Model/ApiClient/IDevice.cs
new file mode 100644
index 000000000..0c0f55f9b
--- /dev/null
+++ b/MediaBrowser.Model/ApiClient/IDevice.cs
@@ -0,0 +1,44 @@
+using MediaBrowser.Model.Devices;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Model.ApiClient
+{
+ public interface IDevice
+ {
+ /// <summary>
+ /// Occurs when [resume from sleep].
+ /// </summary>
+ event EventHandler<EventArgs> ResumeFromSleep;
+ /// <summary>
+ /// Gets the name of the device.
+ /// </summary>
+ /// <value>The name of the device.</value>
+ string DeviceName { get; }
+ /// <summary>
+ /// Gets the device identifier.
+ /// </summary>
+ /// <value>The device identifier.</value>
+ string DeviceId { get; }
+ /// <summary>
+ /// Gets the local images.
+ /// </summary>
+ /// <returns>IEnumerable&lt;LocalFileInfo&gt;.</returns>
+ IEnumerable<LocalFileInfo> GetLocalPhotos();
+ /// <summary>
+ /// Gets the local videos.
+ /// </summary>
+ /// <returns>IEnumerable&lt;LocalFileInfo&gt;.</returns>
+ IEnumerable<LocalFileInfo> GetLocalVideos();
+ /// <summary>
+ /// Uploads the file.
+ /// </summary>
+ /// <param name="file">The file.</param>
+ /// <param name="apiClient">The API client.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task UploadFile(LocalFileInfo file, IApiClient apiClient, CancellationToken cancellationToken);
+ }
+}
diff --git a/MediaBrowser.Model/Devices/ContentUploadHistory.cs b/MediaBrowser.Model/Devices/ContentUploadHistory.cs
new file mode 100644
index 000000000..cd4858d90
--- /dev/null
+++ b/MediaBrowser.Model/Devices/ContentUploadHistory.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+
+namespace MediaBrowser.Model.Devices
+{
+ public class ContentUploadHistory
+ {
+ public string DeviceId { get; set; }
+ public List<LocalFileInfo> FilesUploaded { get; set; }
+
+ public ContentUploadHistory()
+ {
+ FilesUploaded = new List<LocalFileInfo>();
+ }
+ }
+}
diff --git a/MediaBrowser.Model/Devices/DeviceInfo.cs b/MediaBrowser.Model/Devices/DeviceInfo.cs
new file mode 100644
index 000000000..cc622af27
--- /dev/null
+++ b/MediaBrowser.Model/Devices/DeviceInfo.cs
@@ -0,0 +1,44 @@
+using System;
+using MediaBrowser.Model.Session;
+
+namespace MediaBrowser.Model.Devices
+{
+ public class DeviceInfo
+ {
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ public string Name { get; set; }
+ /// <summary>
+ /// Gets or sets the identifier.
+ /// </summary>
+ /// <value>The identifier.</value>
+ public string Id { get; set; }
+ /// <summary>
+ /// Gets or sets the last name of the user.
+ /// </summary>
+ /// <value>The last name of the user.</value>
+ public string LastUserName { get; set; }
+ /// <summary>
+ /// Gets or sets the last user identifier.
+ /// </summary>
+ /// <value>The last user identifier.</value>
+ public string LastUserId { get; set; }
+ /// <summary>
+ /// Gets or sets the date last modified.
+ /// </summary>
+ /// <value>The date last modified.</value>
+ public DateTime DateLastModified { get; set; }
+ /// <summary>
+ /// Gets or sets the capabilities.
+ /// </summary>
+ /// <value>The capabilities.</value>
+ public ClientCapabilities Capabilities { get; set; }
+
+ public DeviceInfo()
+ {
+ Capabilities = new ClientCapabilities();
+ }
+ }
+}
diff --git a/MediaBrowser.Model/Devices/DevicesOptions.cs b/MediaBrowser.Model/Devices/DevicesOptions.cs
new file mode 100644
index 000000000..6c2082e8d
--- /dev/null
+++ b/MediaBrowser.Model/Devices/DevicesOptions.cs
@@ -0,0 +1,14 @@
+
+namespace MediaBrowser.Model.Devices
+{
+ public class DevicesOptions
+ {
+ public string[] EnabledCameraUploadDevices { get; set; }
+ public string CameraUploadPath { get; set; }
+
+ public DevicesOptions()
+ {
+ EnabledCameraUploadDevices = new string[] { };
+ }
+ }
+}
diff --git a/MediaBrowser.Model/Devices/LocalFileInfo.cs b/MediaBrowser.Model/Devices/LocalFileInfo.cs
new file mode 100644
index 000000000..f7704e087
--- /dev/null
+++ b/MediaBrowser.Model/Devices/LocalFileInfo.cs
@@ -0,0 +1,11 @@
+
+namespace MediaBrowser.Model.Devices
+{
+ public class LocalFileInfo
+ {
+ public string Name { get; set; }
+ public string FullPath { get; set; }
+ public string Album { get; set; }
+ public string MimeType { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Dlna/Profiles/AndroidProfile.cs b/MediaBrowser.Model/Dlna/Profiles/AndroidProfile.cs
index dfe14f1c7..0d060cda8 100644
--- a/MediaBrowser.Model/Dlna/Profiles/AndroidProfile.cs
+++ b/MediaBrowser.Model/Dlna/Profiles/AndroidProfile.cs
@@ -6,7 +6,9 @@ namespace MediaBrowser.Model.Dlna.Profiles
[XmlRoot("Profile")]
public class AndroidProfile : DefaultProfile
{
- public AndroidProfile(bool supportsHls, bool supportsMpegDash)
+ public AndroidProfile(bool supportsHls,
+ bool supportsMpegDash,
+ string[] supportedH264Profiles)
{
Name = "Android";
@@ -102,7 +104,7 @@ namespace MediaBrowser.Model.Dlna.Profiles
Conditions = new []
{
- new ProfileCondition(ProfileConditionType.EqualsAny, ProfileConditionValue.VideoProfile, "baseline|constrained baseline"),
+ new ProfileCondition(ProfileConditionType.EqualsAny, ProfileConditionValue.VideoProfile, string.Join("|", supportedH264Profiles)),
new ProfileCondition(ProfileConditionType.LessThanEqual, ProfileConditionValue.Width, "1920"),
new ProfileCondition(ProfileConditionType.LessThanEqual, ProfileConditionValue.Height, "1080"),
new ProfileCondition(ProfileConditionType.LessThanEqual, ProfileConditionValue.VideoBitDepth, "8"),
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 2c49198b7..815e8e20b 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -733,12 +733,6 @@ namespace MediaBrowser.Model.Dlna
private bool IsVideoDirectPlaySupported(DirectPlayProfile profile, MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream)
{
- // Only plain video files can be direct played
- if (item.VideoType != VideoType.VideoFile)
- {
- return false;
- }
-
if (profile.Container.Length > 0)
{
// Check container type
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index 9abf44616..36dc611f2 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -76,7 +76,10 @@ namespace MediaBrowser.Model.Dlna
public bool IsDirectStream
{
- get { return PlayMethod == PlayMethod.DirectStream; }
+ get {
+ return PlayMethod == PlayMethod.DirectStream ||
+ PlayMethod == PlayMethod.DirectPlay;
+ }
}
public string ToUrl(string baseUrl)
@@ -91,13 +94,6 @@ namespace MediaBrowser.Model.Dlna
throw new ArgumentNullException(baseUrl);
}
- if (IsDirectStream && MediaSource != null && MediaSource.Protocol == MediaProtocol.Http)
- {
- if (MediaSource.RequiredHttpHeaders.Count == 0)
- {
- }
- }
-
string dlnaCommand = BuildDlnaParam(this);
string extension = string.IsNullOrEmpty(Container) ? string.Empty : "." + Container;
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index ae71f2987..e1ce7ecca 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -67,6 +67,7 @@
<Compile Include="ApiClient\IApiClient.cs" />
<Compile Include="ApiClient\ApiClientExtensions.cs" />
<Compile Include="ApiClient\IConnectionManager.cs" />
+ <Compile Include="ApiClient\IDevice.cs" />
<Compile Include="ApiClient\IServerEvents.cs" />
<Compile Include="ApiClient\GeneralCommandEventArgs.cs" />
<Compile Include="ApiClient\ServerDiscoveryInfo.cs" />
@@ -95,6 +96,9 @@
<Compile Include="Configuration\XbmcMetadataOptions.cs" />
<Compile Include="Configuration\SubtitlePlaybackMode.cs" />
<Compile Include="Connect\UserLinkType.cs" />
+ <Compile Include="Devices\LocalFileInfo.cs" />
+ <Compile Include="Devices\DeviceInfo.cs" />
+ <Compile Include="Devices\DevicesOptions.cs" />
<Compile Include="Dlna\EncodingContext.cs" />
<Compile Include="Dlna\Profiles\AndroidProfile.cs" />
<Compile Include="Dlna\Profiles\DefaultProfile.cs" />
@@ -331,11 +335,11 @@
<Compile Include="Serialization\IJsonSerializer.cs" />
<Compile Include="Serialization\IXmlSerializer.cs" />
<Compile Include="Session\PlaystateRequest.cs" />
- <Compile Include="Session\SessionCapabilities.cs" />
<Compile Include="Session\SessionInfoDto.cs" />
<Compile Include="Session\SessionUserInfo.cs" />
<Compile Include="Session\TranscodingInfo.cs" />
<Compile Include="Session\UserDataChangeInfo.cs" />
+ <Compile Include="Devices\ContentUploadHistory.cs" />
<Compile Include="Sync\SyncJob.cs" />
<Compile Include="Sync\SyncJobCreationResult.cs" />
<Compile Include="Sync\SyncJobItem.cs" />
diff --git a/MediaBrowser.Model/Session/ClientCapabilities.cs b/MediaBrowser.Model/Session/ClientCapabilities.cs
index 5bee06087..cbc1501d2 100644
--- a/MediaBrowser.Model/Session/ClientCapabilities.cs
+++ b/MediaBrowser.Model/Session/ClientCapabilities.cs
@@ -5,8 +5,15 @@ namespace MediaBrowser.Model.Session
public class ClientCapabilities
{
public List<string> PlayableMediaTypes { get; set; }
+
public List<string> SupportedCommands { get; set; }
+ public bool SupportsMediaControl { get; set; }
+
+ public string MessageCallbackUrl { get; set; }
+
+ public bool SupportsContentUploading { get; set; }
+
public ClientCapabilities()
{
PlayableMediaTypes = new List<string>();
diff --git a/MediaBrowser.Model/Session/SessionCapabilities.cs b/MediaBrowser.Model/Session/SessionCapabilities.cs
deleted file mode 100644
index 767df8f1c..000000000
--- a/MediaBrowser.Model/Session/SessionCapabilities.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System.Collections.Generic;
-
-namespace MediaBrowser.Model.Session
-{
- public class SessionCapabilities
- {
- public List<string> PlayableMediaTypes { get; set; }
-
- public List<string> SupportedCommands { get; set; }
-
- public bool SupportsMediaControl { get; set; }
-
- public string MessageCallbackUrl { get; set; }
-
- public SessionCapabilities()
- {
- PlayableMediaTypes = new List<string>();
- SupportedCommands = new List<string>();
- }
- }
-}
diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
index fd32dabb2..664eff004 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
@@ -265,10 +265,6 @@ namespace MediaBrowser.Providers.Music
}
/// <summary>
- /// The _last music brainz request
- /// </summary>
- private DateTime _lastRequestDate = DateTime.MinValue;
- /// <summary>
/// The _music brainz resource pool
/// </summary>
private readonly SemaphoreSlim _musicBrainzResourcePool = new SemaphoreSlim(1, 1);
@@ -282,51 +278,35 @@ namespace MediaBrowser.Providers.Music
/// <returns>Task{XmlDocument}.</returns>
internal async Task<XmlDocument> GetMusicBrainzResponse(string url, bool isSearch, CancellationToken cancellationToken)
{
- await _musicBrainzResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- var diff = 1500 - (DateTime.Now - _lastRequestDate).TotalMilliseconds;
-
- // MusicBrainz is extremely adamant about limiting to one request per second
+ // MusicBrainz is extremely adamant about limiting to one request per second
- if (diff > 0)
- {
- _logger.Debug("Throttling musicbrainz by {0} ms", diff);
- await Task.Delay(Convert.ToInt32(diff), cancellationToken).ConfigureAwait(false);
- }
+ await Task.Delay(800, cancellationToken).ConfigureAwait(false);
- var doc = new XmlDocument();
+ var doc = new XmlDocument();
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- UserAgent = _appHost.Name + "/" + _appHost.ApplicationVersion
- };
+ var options = new HttpRequestOptions
+ {
+ Url = url,
+ CancellationToken = cancellationToken,
+ UserAgent = _appHost.Name + "/" + _appHost.ApplicationVersion,
+ ResourcePool = _musicBrainzResourcePool
+ };
- if (!isSearch)
- {
- options.CacheMode = CacheMode.Unconditional;
- options.CacheLength = TimeSpan.FromDays(7);
- }
+ if (!isSearch)
+ {
+ options.CacheMode = CacheMode.Unconditional;
+ options.CacheLength = TimeSpan.FromDays(7);
+ }
- using (var xml = await _httpClient.Get(options).ConfigureAwait(false))
+ using (var xml = await _httpClient.Get(options).ConfigureAwait(false))
+ {
+ using (var oReader = new StreamReader(xml, Encoding.UTF8))
{
- using (var oReader = new StreamReader(xml, Encoding.UTF8))
- {
- doc.Load(oReader);
- }
+ doc.Load(oReader);
}
-
- return doc;
}
- finally
- {
- _lastRequestDate = DateTime.Now;
- _musicBrainzResourcePool.Release();
- }
+ return doc;
}
public int Order
diff --git a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
new file mode 100644
index 000000000..37f72472b
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
@@ -0,0 +1,68 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Entities;
+using System.IO;
+using System.Linq;
+
+namespace MediaBrowser.Server.Implementations.Devices
+{
+ public class CameraUploadsFolder : BasePluginFolder
+ {
+ public CameraUploadsFolder()
+ {
+ Name = "Camera Uploads";
+ DisplayMediaType = "CollectionFolder";
+ }
+
+ public override bool IsVisible(User user)
+ {
+ return GetChildren(user, true).Any() &&
+ base.IsVisible(user);
+ }
+
+ public override bool IsHidden
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ public override bool IsHiddenFromUser(User user)
+ {
+ return false;
+ }
+
+ public override string CollectionType
+ {
+ get { return Model.Entities.CollectionType.Photos; }
+ }
+
+ public override string GetClientTypeName()
+ {
+ return typeof(CollectionFolder).Name;
+ }
+ }
+
+ public class CameraUploadsDynamicFolder : IVirtualFolderCreator
+ {
+ private readonly IApplicationPaths _appPaths;
+
+ public CameraUploadsDynamicFolder(IApplicationPaths appPaths)
+ {
+ _appPaths = appPaths;
+ }
+
+ public BasePluginFolder GetFolder()
+ {
+ var path = Path.Combine(_appPaths.DataPath, "camerauploads");
+
+ Directory.CreateDirectory(path);
+
+ return new CameraUploadsFolder
+ {
+ Path = path
+ };
+ }
+ }
+
+}
diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
new file mode 100644
index 000000000..55425ad7e
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
@@ -0,0 +1,149 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Devices;
+using MediaBrowser.Model.Session;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Devices
+{
+ public class DeviceManager : IDeviceManager
+ {
+ private readonly IDeviceRepository _repo;
+ private readonly IUserManager _userManager;
+ private readonly IFileSystem _fileSystem;
+ private readonly ILibraryMonitor _libraryMonitor;
+ private readonly IConfigurationManager _config;
+
+ public DeviceManager(IDeviceRepository repo, IUserManager userManager, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IConfigurationManager config)
+ {
+ _repo = repo;
+ _userManager = userManager;
+ _fileSystem = fileSystem;
+ _libraryMonitor = libraryMonitor;
+ _config = config;
+ }
+
+ public Task RegisterDevice(string reportedId, string name, string usedByUserId)
+ {
+ var device = GetDevice(reportedId) ?? new DeviceInfo
+ {
+ Id = reportedId
+ };
+
+ device.Name = name;
+
+ if (!string.IsNullOrWhiteSpace(usedByUserId))
+ {
+ var user = _userManager.GetUserById(usedByUserId);
+
+ device.LastUserId = user.Id.ToString("N");
+ device.LastUserName = user.Name;
+ }
+
+ device.DateLastModified = DateTime.UtcNow;
+
+ return _repo.SaveDevice(device);
+ }
+
+ public Task SaveCapabilities(string reportedId, ClientCapabilities capabilities)
+ {
+ return _repo.SaveCapabilities(reportedId, capabilities);
+ }
+
+ public ClientCapabilities GetCapabilities(string reportedId)
+ {
+ return _repo.GetCapabilities(reportedId);
+ }
+
+ public DeviceInfo GetDevice(string id)
+ {
+ return _repo.GetDevice(id);
+ }
+
+ public IEnumerable<DeviceInfo> GetDevices()
+ {
+ return _repo.GetDevices().OrderByDescending(i => i.DateLastModified);
+ }
+
+ public Task DeleteDevice(string id)
+ {
+ return _repo.DeleteDevice(id);
+ }
+
+ public ContentUploadHistory GetCameraUploadHistory(string deviceId)
+ {
+ return _repo.GetCameraUploadHistory(deviceId);
+ }
+
+ public async Task AcceptCameraUpload(string deviceId, Stream stream, LocalFileInfo file)
+ {
+ var path = GetUploadPath(deviceId);
+
+ if (!string.IsNullOrWhiteSpace(file.Album))
+ {
+ path = Path.Combine(path, _fileSystem.GetValidFilename(file.Album));
+ }
+
+ Directory.CreateDirectory(path);
+
+ path = Path.Combine(path, file.Name);
+
+ _libraryMonitor.ReportFileSystemChangeBeginning(path);
+
+ try
+ {
+ using (var fs = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
+ {
+ await stream.CopyToAsync(fs).ConfigureAwait(false);
+ }
+
+ _repo.AddCameraUpload(deviceId, file);
+ }
+ finally
+ {
+ _libraryMonitor.ReportFileSystemChangeComplete(path, true);
+ }
+ }
+
+ private string GetUploadPath(string deviceId)
+ {
+ var config = _config.GetUploadOptions();
+
+ if (!string.IsNullOrWhiteSpace(config.CameraUploadPath))
+ {
+ return config.CameraUploadPath;
+ }
+
+ return Path.Combine(_config.CommonApplicationPaths.DataPath, "camerauploads");
+ }
+ }
+
+ public class DevicesConfigStore : IConfigurationFactory
+ {
+ public IEnumerable<ConfigurationStore> GetConfigurations()
+ {
+ return new List<ConfigurationStore>
+ {
+ new ConfigurationStore
+ {
+ Key = "devices",
+ ConfigurationType = typeof(DevicesOptions)
+ }
+ };
+ }
+ }
+
+ public static class UploadConfigExtension
+ {
+ public static DevicesOptions GetUploadOptions(this IConfigurationManager config)
+ {
+ return config.GetConfiguration<DevicesOptions>("devices");
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs b/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs
new file mode 100644
index 000000000..eac08686f
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs
@@ -0,0 +1,176 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Devices;
+using MediaBrowser.Model.Devices;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Session;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Devices
+{
+ public class DeviceRepository : IDeviceRepository
+ {
+ private readonly object _syncLock = new object();
+
+ private readonly IApplicationPaths _appPaths;
+ private readonly IJsonSerializer _json;
+
+ private ConcurrentBag<DeviceInfo> _devices;
+
+ public DeviceRepository(IApplicationPaths appPaths, IJsonSerializer json)
+ {
+ _appPaths = appPaths;
+ _json = json;
+ }
+
+ private string GetDevicesPath()
+ {
+ return Path.Combine(_appPaths.DataPath, "devices");
+ }
+
+ private string GetDevicePath(string id)
+ {
+ return Path.Combine(GetDevicesPath(), id.GetMD5().ToString("N"));
+ }
+
+ public Task SaveDevice(DeviceInfo device)
+ {
+ var path = Path.Combine(GetDevicePath(device.Id), "device.json");
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+
+ lock (_syncLock)
+ {
+ _json.SerializeToFile(device, path);
+ _devices = null;
+ }
+ return Task.FromResult(true);
+ }
+
+ public Task SaveCapabilities(string reportedId, ClientCapabilities capabilities)
+ {
+ var device = GetDevice(reportedId);
+ device.Capabilities = capabilities;
+ SaveDevice(device);
+
+ return Task.FromResult(true);
+ }
+
+ public ClientCapabilities GetCapabilities(string reportedId)
+ {
+ var device = GetDevice(reportedId);
+
+ return device == null ? null : device.Capabilities;
+ }
+
+ public DeviceInfo GetDevice(string id)
+ {
+ return GetDevices().FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
+ }
+
+ public IEnumerable<DeviceInfo> GetDevices()
+ {
+ if (_devices == null)
+ {
+ lock (_syncLock)
+ {
+ if (_devices == null)
+ {
+ _devices = new ConcurrentBag<DeviceInfo>(LoadDevices());
+ }
+ }
+ }
+ return _devices.ToList();
+ }
+
+ private IEnumerable<DeviceInfo> LoadDevices()
+ {
+ var path = GetDevicesPath();
+
+ try
+ {
+ return new DirectoryInfo(path)
+ .EnumerateFiles("*", SearchOption.AllDirectories)
+ .Where(i => string.Equals(i.Name, "device.json", StringComparison.OrdinalIgnoreCase))
+ .Select(i => _json.DeserializeFromFile<DeviceInfo>(i.FullName))
+ .ToList();
+ }
+ catch (IOException)
+ {
+ return new List<DeviceInfo>();
+ }
+ }
+
+ public Task DeleteDevice(string id)
+ {
+ var path = GetDevicePath(id);
+
+ lock (_syncLock)
+ {
+ try
+ {
+ Directory.Delete(path, true);
+ }
+ catch (DirectoryNotFoundException)
+ {
+ }
+
+ _devices = null;
+ }
+
+ return Task.FromResult(true);
+ }
+
+ public ContentUploadHistory GetCameraUploadHistory(string deviceId)
+ {
+ var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json");
+
+ lock (_syncLock)
+ {
+ try
+ {
+ return _json.DeserializeFromFile<ContentUploadHistory>(path);
+ }
+ catch (IOException)
+ {
+ return new ContentUploadHistory
+ {
+ DeviceId = deviceId
+ };
+ }
+ }
+ }
+
+ public void AddCameraUpload(string deviceId, LocalFileInfo file)
+ {
+ var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json");
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+
+ lock (_syncLock)
+ {
+ ContentUploadHistory history;
+
+ try
+ {
+ history = _json.DeserializeFromFile<ContentUploadHistory>(path);
+ }
+ catch (IOException)
+ {
+ history = new ContentUploadHistory
+ {
+ DeviceId = deviceId
+ };
+ }
+
+ history.DeviceId = deviceId;
+ history.FilesUploaded.Add(file);
+
+ _json.SerializeToFile(history, path);
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
index 4beb34e4f..b12ae32a8 100644
--- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
@@ -60,41 +60,45 @@ namespace MediaBrowser.Server.Implementations.Library
var standaloneFolders = folders.Where(i => UserView.IsExcludedFromGrouping(i) || excludeFolderIds.Contains(i.Id)).ToList();
- list.AddRange(standaloneFolders);
-
- var recursiveChildren = folders
+ var foldersWithViewTypes = folders
.Except(standaloneFolders)
- .SelectMany(i => i.GetRecursiveChildren(user, false))
+ .OfType<ICollectionFolder>()
.ToList();
- if (recursiveChildren.OfType<Series>().Any())
+ list.AddRange(standaloneFolders);
+
+ if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) ||
+ foldersWithViewTypes.Any(i => string.IsNullOrWhiteSpace(i.CollectionType)))
{
list.Add(await GetUserView(CollectionType.TvShows, user, string.Empty, cancellationToken).ConfigureAwait(false));
}
- if (recursiveChildren.OfType<MusicAlbum>().Any() ||
- recursiveChildren.OfType<MusicVideo>().Any())
+ if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase)) ||
+ foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)))
{
list.Add(await GetUserView(CollectionType.Music, user, string.Empty, cancellationToken).ConfigureAwait(false));
}
- if (recursiveChildren.OfType<Movie>().Any())
+ if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) ||
+ foldersWithViewTypes.Any(i => string.IsNullOrWhiteSpace(i.CollectionType)))
{
list.Add(await GetUserView(CollectionType.Movies, user, string.Empty, cancellationToken).ConfigureAwait(false));
}
- if (recursiveChildren.OfType<Game>().Any())
+ if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Games, StringComparison.OrdinalIgnoreCase)))
{
list.Add(await GetUserView(CollectionType.Games, user, string.Empty, cancellationToken).ConfigureAwait(false));
}
if (user.Configuration.DisplayCollectionsView &&
- recursiveChildren.OfType<BoxSet>().Any())
+ folders
+ .Except(standaloneFolders)
+ .SelectMany(i => i.GetRecursiveChildren(user, false)).OfType<BoxSet>().Any())
{
list.Add(await GetUserView(CollectionType.BoxSets, user, string.Empty, cancellationToken).ConfigureAwait(false));
}
- if (recursiveChildren.OfType<Playlist>().Any())
+ if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)))
{
list.Add(_playlists.GetPlaylistsFolder(user.Id.ToString("N")));
}
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
index 9c49d22d7..c1e9ff5cd 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
@@ -602,5 +602,12 @@
"DashboardTourNotifications": "Automatically send notifications of server events to your mobile device, email and more.",
"DashboardTourScheduledTasks": "Easily manage long running operations with scheduled tasks. Decide when they run, and how often.",
"DashboardTourMobile": "The Media Browser dashboard works great on smartphones and tablets. Manage your server from the palm of your hand anytime, anywhere.",
- "MessageRefreshQueued": "Refresh queued"
+ "MessageRefreshQueued": "Refresh queued",
+ "TabDevices": "Devices",
+ "DeviceLastUsedByUserName": "Last used by {0}",
+ "HeaderDeleteDevice": "Delete Device",
+ "DeleteDeviceConfirmation": "Are you sure you with to delete this device? It will reappear the next time a user signs in with it.",
+ "LabelEnableCameraUploadFor": "Enable camera upload for:",
+ "HeaderSelectUploadPath": "Select Upload Path",
+ "LabelEnableCameraUploadForHelp": "Uploads will occur automatically in the background when signed into Media Browser."
}
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json
index ceea000de..fe1f84ef3 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/server.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json
@@ -1215,5 +1215,13 @@
"OptionDateAddedImportTime": "Use date scanned into the library",
"OptionDateAddedFileTime": "Use file creation date",
"LabelDateAddedBehaviorHelp": "If a metadata value is present it will always be used before either of these options.",
- "LabelNumberTrailerToPlay": "Number of trailers to play:"
+ "LabelNumberTrailerToPlay": "Number of trailers to play:",
+ "TitleDevices": "Devices",
+ "TabCameraUpload": "Camera Upload",
+ "TabDevices": "Devices",
+ "TitleDevices": "Devices",
+ "HeaderCameraUploadHelp": "Automatically upload photos and videos taken from your mobile devices into Media Browser.",
+ "MessageNoDevicesSupportCameraUpload": "You currently don't have any devices that support camera upload.",
+ "LabelUploadPath": "Upload path:",
+ "LabelUploadPathHelp": "Select a custom upload path, if desired. If unspecified an internal data folder will be used."
}
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index c90c1c029..2d6e32a34 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -119,6 +119,9 @@
<Compile Include="Connect\ConnectData.cs" />
<Compile Include="Connect\ConnectManager.cs" />
<Compile Include="Connect\Responses.cs" />
+ <Compile Include="Devices\DeviceManager.cs" />
+ <Compile Include="Devices\DeviceRepository.cs" />
+ <Compile Include="Devices\CameraUploadsFolder.cs" />
<Compile Include="Drawing\ImageHeader.cs" />
<Compile Include="Drawing\PercentPlayedDrawer.cs" />
<Compile Include="Drawing\PlayedIndicatorDrawer.cs" />
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 58a6f649c..10c89c613 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -64,6 +65,7 @@ namespace MediaBrowser.Server.Implementations.Session
private readonly IServerApplicationHost _appHost;
private readonly IAuthenticationRepository _authRepo;
+ private readonly IDeviceManager _deviceManager;
/// <summary>
/// Gets or sets the configuration manager.
@@ -80,7 +82,7 @@ namespace MediaBrowser.Server.Implementations.Session
public event EventHandler<GenericEventArgs<AuthenticationRequest>> AuthenticationFailed;
public event EventHandler<GenericEventArgs<AuthenticationRequest>> AuthenticationSucceeded;
-
+
/// <summary>
/// Occurs when [playback start].
/// </summary>
@@ -111,7 +113,7 @@ namespace MediaBrowser.Server.Implementations.Session
/// <param name="logger">The logger.</param>
/// <param name="userRepository">The user repository.</param>
/// <param name="libraryManager">The library manager.</param>
- public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo)
+ public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo, IDeviceManager deviceManager)
{
_userDataRepository = userDataRepository;
_configurationManager = configurationManager;
@@ -127,6 +129,7 @@ namespace MediaBrowser.Server.Implementations.Session
_appHost = appHost;
_httpClient = httpClient;
_authRepo = authRepo;
+ _deviceManager = deviceManager;
}
/// <summary>
@@ -394,7 +397,9 @@ namespace MediaBrowser.Server.Implementations.Session
try
{
- var connection = _activeConnections.GetOrAdd(key, keyName =>
+ SessionInfo connection;
+
+ if (!_activeConnections.TryGetValue(key, out connection))
{
var sessionInfo = new SessionInfo
{
@@ -411,8 +416,15 @@ namespace MediaBrowser.Server.Implementations.Session
OnSessionStarted(sessionInfo);
- return sessionInfo;
- });
+ _activeConnections.TryAdd(key, sessionInfo);
+ connection = sessionInfo;
+
+ if (!string.IsNullOrEmpty(deviceId))
+ {
+ var userIdString = userId.HasValue ? userId.Value.ToString("N") : null;
+ await _deviceManager.RegisterDevice(deviceId, deviceName, userIdString).ConfigureAwait(false);
+ }
+ }
connection.DeviceName = deviceName;
connection.UserId = userId;
@@ -1226,7 +1238,7 @@ namespace MediaBrowser.Server.Implementations.Session
var token = await GetAuthorizationToken(user.Id.ToString("N"), request.DeviceId, request.App, request.DeviceName).ConfigureAwait(false);
EventHelper.FireEventIfNotNull(AuthenticationSucceeded, this, new GenericEventArgs<AuthenticationRequest>(request), _logger);
-
+
var session = await LogSessionActivity(request.App,
request.AppVersion,
request.DeviceId,
@@ -1234,7 +1246,7 @@ namespace MediaBrowser.Server.Implementations.Session
request.RemoteEndPoint,
user)
.ConfigureAwait(false);
-
+
return new AuthenticationResult
{
User = _userManager.GetUserDto(user, request.RemoteEndPoint),
@@ -1339,7 +1351,7 @@ namespace MediaBrowser.Server.Implementations.Session
/// </summary>
/// <param name="sessionId">The session identifier.</param>
/// <param name="capabilities">The capabilities.</param>
- public void ReportCapabilities(string sessionId, SessionCapabilities capabilities)
+ public void ReportCapabilities(string sessionId, ClientCapabilities capabilities)
{
var session = GetSession(sessionId);
@@ -1347,7 +1359,7 @@ namespace MediaBrowser.Server.Implementations.Session
}
private async void ReportCapabilities(SessionInfo session,
- SessionCapabilities capabilities,
+ ClientCapabilities capabilities,
bool saveCapabilities)
{
session.PlayableMediaTypes = capabilities.PlayableMediaTypes;
@@ -1375,56 +1387,14 @@ namespace MediaBrowser.Server.Implementations.Session
}
}
- private string GetCapabilitiesFilePath(string deviceId)
+ private ClientCapabilities GetSavedCapabilities(string deviceId)
{
- var filename = deviceId.GetMD5().ToString("N") + ".json";
-
- return Path.Combine(_configurationManager.ApplicationPaths.CachePath, "devices", filename);
- }
-
- private SessionCapabilities GetSavedCapabilities(string deviceId)
- {
- var path = GetCapabilitiesFilePath(deviceId);
-
- try
- {
- return _jsonSerializer.DeserializeFromFile<SessionCapabilities>(path);
- }
- catch (DirectoryNotFoundException)
- {
- return null;
- }
- catch (FileNotFoundException)
- {
- return null;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting saved capabilities", ex);
- return null;
- }
+ return _deviceManager.GetCapabilities(deviceId);
}
- private readonly SemaphoreSlim _capabilitiesLock = new SemaphoreSlim(1, 1);
- private async Task SaveCapabilities(string deviceId, SessionCapabilities capabilities)
+ private Task SaveCapabilities(string deviceId, ClientCapabilities capabilities)
{
- var path = GetCapabilitiesFilePath(deviceId);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
-
- await _capabilitiesLock.WaitAsync().ConfigureAwait(false);
-
- try
- {
- _jsonSerializer.SerializeToFile(capabilities, path);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving to {0}", ex, path);
- }
- finally
- {
- _capabilitiesLock.Release();
- }
+ return _deviceManager.SaveCapabilities(deviceId, capabilities);
}
public SessionInfoDto GetSessionInfoDto(SessionInfo session)
diff --git a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
index 2d5a30f3d..0756aa1ec 100644
--- a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
+++ b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
@@ -75,7 +75,7 @@ namespace MediaBrowser.Server.Implementations.Session
}
else
{
- var capabilities = new SessionCapabilities
+ var capabilities = new ClientCapabilities
{
PlayableMediaTypes = Session.PlayableMediaTypes,
SupportedCommands = Session.SupportedCommands,
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
index b5e13e306..263bfb6ad 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
@@ -1,9 +1,11 @@
-using MediaBrowser.Common.Extensions;
+using System.IO;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Sync;
+using MediaBrowser.Model.Devices;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Querying;
diff --git a/MediaBrowser.Server.Mono/app.config b/MediaBrowser.Server.Mono/app.config
index c5abd3a20..f70540a76 100644
--- a/MediaBrowser.Server.Mono/app.config
+++ b/MediaBrowser.Server.Mono/app.config
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
@@ -10,4 +10,12 @@
<add key="DebugProgramDataPath" value="ProgramData-Server" />
<add key="ReleaseProgramDataPath" value="ProgramData-Server" />
</appSettings>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Data.SQLite" publicKeyToken="db937bc2d44ff139" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.0.91.0" newVersion="1.0.91.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
</configuration>
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 17c5b108a..8e41ef03e 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -14,6 +14,7 @@ using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Connect;
+using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
@@ -59,6 +60,7 @@ using MediaBrowser.Server.Implementations.Channels;
using MediaBrowser.Server.Implementations.Collections;
using MediaBrowser.Server.Implementations.Configuration;
using MediaBrowser.Server.Implementations.Connect;
+using MediaBrowser.Server.Implementations.Devices;
using MediaBrowser.Server.Implementations.Drawing;
using MediaBrowser.Server.Implementations.Dto;
using MediaBrowser.Server.Implementations.EntryPoints;
@@ -212,6 +214,7 @@ namespace MediaBrowser.ServerApplication
private INotificationManager NotificationManager { get; set; }
private ISubtitleManager SubtitleManager { get; set; }
private IChapterManager ChapterManager { get; set; }
+ private IDeviceManager DeviceManager { get; set; }
internal IUserViewManager UserViewManager { get; set; }
@@ -316,8 +319,6 @@ namespace MediaBrowser.ServerApplication
PerformVersionMigration();
await base.Init(progress).ConfigureAwait(false);
-
- MigrateModularConfigurations();
}
private void PerformVersionMigration()
@@ -325,16 +326,6 @@ namespace MediaBrowser.ServerApplication
DeleteDeprecatedModules();
}
- private void MigrateModularConfigurations()
- {
- var saveConfig = false;
-
- if (saveConfig)
- {
- ServerConfigurationManager.SaveConfiguration();
- }
- }
-
private void DeleteDeprecatedModules()
{
try
@@ -469,7 +460,10 @@ namespace MediaBrowser.ServerApplication
ConnectManager = new ConnectManager(LogManager.GetLogger("Connect"), ApplicationPaths, JsonSerializer, encryptionManager, HttpClient, this, ServerConfigurationManager, UserManager);
RegisterSingleInstance(ConnectManager);
- SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository, JsonSerializer, this, HttpClient, AuthenticationRepository);
+ DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer), UserManager, FileSystemManager, LibraryMonitor, ConfigurationManager);
+ RegisterSingleInstance(DeviceManager);
+
+ SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager);
RegisterSingleInstance(SessionManager);
var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 4b1f39bf4..9c31e2940 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -564,6 +564,8 @@ namespace MediaBrowser.WebDashboard.Api
"dashboardgeneral.js",
"dashboardpage.js",
"dashboardsync.js",
+ "devices.js",
+ "devicesupload.js",
"directorybrowser.js",
"dlnaprofile.js",
"dlnaprofiles.js",
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 292200bfa..65fc46978 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -58,8 +58,7 @@
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath>
</Reference>
<Reference Include="WebMarkupMin.Core">
- <HintPath>..\packages\WebMarkupMin.Core.0.9.6\lib\net40\WebMarkupMin.Core.dll</HintPath>
- <Private>True</Private>
+ <HintPath>..\packages\WebMarkupMin.Core.0.9.7\lib\net40\WebMarkupMin.Core.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@@ -368,6 +367,12 @@
<Content Include="dashboard-ui\dashboardsync.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\devices.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\devicesupload.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\dlnaprofile.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -692,6 +697,12 @@
<Content Include="dashboard-ui\scripts\dashboardsync.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\devices.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\scripts\devicesupload.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\dlnaprofile.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
diff --git a/MediaBrowser.WebDashboard/app.config b/MediaBrowser.WebDashboard/app.config
index 8d7ee4f17..d66f0b626 100644
--- a/MediaBrowser.WebDashboard/app.config
+++ b/MediaBrowser.WebDashboard/app.config
@@ -9,6 +9,7 @@
+
<webMarkupMin xmlns="http://tempuri.org/WebMarkupMin.Configuration.xsd">
<core>
<css>
diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config
index 7a472fe0d..573abbdbd 100644
--- a/MediaBrowser.WebDashboard/packages.config
+++ b/MediaBrowser.WebDashboard/packages.config
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="MediaBrowser.ApiClient.Javascript" version="3.0.249" targetFramework="net45" />
- <package id="WebMarkupMin.Core" version="0.9.6" targetFramework="net45" />
+ <package id="WebMarkupMin.Core" version="0.9.7" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index b27b010d4..41f99f47d 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.467</version>
+ <version>3.0.476</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.467" />
+ <dependency id="MediaBrowser.Common" version="3.0.476" />
<dependency id="NLog" version="3.1.0.0" />
<dependency id="SimpleInjector" version="2.5.2" />
<dependency id="sharpcompress" version="0.10.2" />
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index f40d4377d..962eae0c8 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.467</version>
+ <version>3.0.476</version>
<title>MediaBrowser.Common</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec
index 904ec7896..992d2f2d0 100644
--- a/Nuget/MediaBrowser.Model.Signed.nuspec
+++ b/Nuget/MediaBrowser.Model.Signed.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Model.Signed</id>
- <version>3.0.467</version>
+ <version>3.0.476</version>
<title>MediaBrowser.Model - Signed Edition</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 45d05c282..7c65bf3e7 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.467</version>
+ <version>3.0.476</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.467" />
+ <dependency id="MediaBrowser.Common" version="3.0.476" />
</dependencies>
</metadata>
<files>
diff --git a/SharedVersion.cs b/SharedVersion.cs
index 594ca0219..687c9204d 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -3,5 +3,6 @@
#if (DEBUG)
[assembly: AssemblyVersion("3.0.*")]
#else
-[assembly: AssemblyVersion("3.0.5395.0")]
+[assembly: AssemblyVersion("3.0.*")]
+//[assembly: AssemblyVersion("3.0.5395.0")]
#endif