From 314a51dff3f070be75bcaf00be244977fdd3ceb5 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 11 Oct 2014 21:46:02 -0400 Subject: [PATCH] add more device options --- MediaBrowser.Api/Devices/DeviceService.cs | 5 ++- .../Playback/BaseStreamingService.cs | 2 +- .../BaseProgressiveStreamingService.cs | 32 ++++++++++++++----- .../Playback/StaticRemoteStreamWriter.cs | 4 +-- .../HttpClientManager/HttpClientManager.cs | 8 ++--- MediaBrowser.Common/Net/HttpRequestOptions.cs | 1 + MediaBrowser.Common/Net/HttpResponseInfo.cs | 23 +++++++++++-- .../Devices/IDeviceManager.cs | 3 +- .../Entities/ICollectionFolder.cs | 5 ++- MediaBrowser.Controller/Entities/UserView.cs | 29 +---------------- MediaBrowser.Model/Devices/DeviceInfo.cs | 5 +++ MediaBrowser.Model/Devices/DevicesOptions.cs | 1 + MediaBrowser.Model/Dlna/DeviceProfile.cs | 3 ++ MediaBrowser.Model/Dlna/StreamBuilder.cs | 31 +++++++++++++++--- MediaBrowser.Model/Dlna/StreamInfo.cs | 9 ++++-- .../Channels/ChannelDownloadScheduledTask.cs | 7 ---- .../Devices/DeviceManager.cs | 14 ++++++-- .../Library/LibraryManager.cs | 2 +- .../Library/Resolvers/PhotoResolver.cs | 15 +++++++-- .../Localization/Server/server.json | 8 +++-- .../Session/SessionManager.cs | 2 +- .../Api/DashboardService.cs | 1 + .../MediaBrowser.WebDashboard.csproj | 6 ++++ Nuget/MediaBrowser.Common.Internal.nuspec | 4 +-- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Model.Signed.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +-- OpenSubtitlesHandler/OpenSubtitles.cs | 16 ++++++++-- 28 files changed, 162 insertions(+), 82 deletions(-) diff --git a/MediaBrowser.Api/Devices/DeviceService.cs b/MediaBrowser.Api/Devices/DeviceService.cs index 55980bc001..87419e4405 100644 --- a/MediaBrowser.Api/Devices/DeviceService.cs +++ b/MediaBrowser.Api/Devices/DeviceService.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.Api.Devices [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")] + [ApiMember(Name = "DeviceId", 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")] @@ -87,8 +87,7 @@ namespace MediaBrowser.Api.Devices public void Post(PostCameraUpload request) { - var deviceId = request.DeviceId; - + var deviceId = Request.QueryString["DeviceId"]; var album = Request.QueryString["Album"]; var fullPath = Request.QueryString["FullPath"]; var name = Request.QueryString["Name"]; diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index f40c2fbf7f..8b53954884 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -986,7 +986,7 @@ namespace MediaBrowser.Api.Playback StartStreamingLog(transcodingJob, state, process.StandardError.BaseStream, state.LogFileStream); // Wait for the file to exist before proceeeding - while (!File.Exists(outputPath)) + while (!File.Exists(outputPath) && !transcodingJob.HasExited) { await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false); } diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 94cf984d2a..6bec387d42 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -308,6 +308,8 @@ namespace MediaBrowser.Api.Playback.Progressive string useragent = null; state.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent); + var trySupportSeek = false; + var options = new HttpRequestOptions { Url = state.MediaPath, @@ -316,25 +318,39 @@ namespace MediaBrowser.Api.Playback.Progressive CancellationToken = cancellationTokenSource.Token }; - if (!string.IsNullOrWhiteSpace(Request.QueryString["Range"])) + if (trySupportSeek) { - options.RequestHeaders["Range"] = Request.QueryString["Range"]; + if (!string.IsNullOrWhiteSpace(Request.QueryString["Range"])) + { + options.RequestHeaders["Range"] = Request.QueryString["Range"]; + } } - var response = await HttpClient.GetResponse(options).ConfigureAwait(false); - foreach (var name in new[] { "Content-Length", "Content-Range", "Accept-Ranges" }) + if (trySupportSeek) { - var val = response.Headers[name]; - if (!string.IsNullOrWhiteSpace(val)) + foreach (var name in new[] {"Content-Range", "Accept-Ranges"}) { - responseHeaders[name] = val; + var val = response.Headers[name]; + if (!string.IsNullOrWhiteSpace(val)) + { + responseHeaders[name] = val; + } } } + else + { + responseHeaders["Accept-Ranges"] = "none"; + } + + if (response.ContentLength.HasValue) + { + responseHeaders["Content-Length"] = response.ContentLength.Value.ToString(UsCulture); + } if (isHeadRequest) { - using (response.Content) + using (response) { return ResultFactory.GetResult(new byte[] { }, response.ContentType, responseHeaders); } diff --git a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs index 24dce64dfe..8f9fa11db1 100644 --- a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs +++ b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs @@ -53,9 +53,9 @@ namespace MediaBrowser.Api.Playback /// Task. public async Task WriteToAsync(Stream responseStream) { - using (var remoteStream = _response.Content) + using (_response) { - await remoteStream.CopyToAsync(responseStream, 819200).ConfigureAwait(false); + await _response.Content.CopyToAsync(responseStream, 819200).ConfigureAwait(false); } } } diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 81fcd6228c..4a8597b7fc 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -398,7 +398,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager options.CancellationToken.ThrowIfCancellationRequested(); - return GetResponseInfo(httpResponse, httpResponse.GetResponseStream(), GetContentLength(httpResponse)); + return GetResponseInfo(httpResponse, httpResponse.GetResponseStream(), GetContentLength(httpResponse), httpResponse); } using (var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false)) @@ -417,7 +417,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager memoryStream.Position = 0; - return GetResponseInfo(httpResponse, memoryStream, memoryStream.Length); + return GetResponseInfo(httpResponse, memoryStream, memoryStream.Length, null); } } } @@ -480,9 +480,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager return exception; } - private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, Stream content, long? contentLength) + private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, Stream content, long? contentLength, IDisposable disposable) { - return new HttpResponseInfo + return new HttpResponseInfo(disposable) { Content = content, diff --git a/MediaBrowser.Common/Net/HttpRequestOptions.cs b/MediaBrowser.Common/Net/HttpRequestOptions.cs index ba972b6224..ad7aad1d33 100644 --- a/MediaBrowser.Common/Net/HttpRequestOptions.cs +++ b/MediaBrowser.Common/Net/HttpRequestOptions.cs @@ -114,6 +114,7 @@ namespace MediaBrowser.Common.Net RequestHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); LogRequest = true; + CacheMode = CacheMode.None; } public void SetPostData(IDictionary values) diff --git a/MediaBrowser.Common/Net/HttpResponseInfo.cs b/MediaBrowser.Common/Net/HttpResponseInfo.cs index 10b5e1983c..890c893e61 100644 --- a/MediaBrowser.Common/Net/HttpResponseInfo.cs +++ b/MediaBrowser.Common/Net/HttpResponseInfo.cs @@ -1,4 +1,5 @@ -using System.Collections.Specialized; +using System; +using System.Collections.Specialized; using System.IO; using System.Net; @@ -7,7 +8,7 @@ namespace MediaBrowser.Common.Net /// /// Class HttpResponseInfo /// - public class HttpResponseInfo + public class HttpResponseInfo : IDisposable { /// /// Gets or sets the type of the content. @@ -50,5 +51,23 @@ namespace MediaBrowser.Common.Net /// /// The headers. public NameValueCollection Headers { get; set; } + + private readonly IDisposable _disposable; + + public HttpResponseInfo(IDisposable disposable) + { + _disposable = disposable; + } + public HttpResponseInfo() + { + } + + public void Dispose() + { + if (_disposable != null) + { + _disposable.Dispose(); + } + } } } diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs index b82c39effc..e66de42bb1 100644 --- a/MediaBrowser.Controller/Devices/IDeviceManager.cs +++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs @@ -13,9 +13,10 @@ namespace MediaBrowser.Controller.Devices /// /// The reported identifier. /// The name. + /// Name of the application. /// The used by user identifier. /// Task. - Task RegisterDevice(string reportedId, string name, string usedByUserId); + Task RegisterDevice(string reportedId, string name, string appName, string usedByUserId); /// /// Saves the capabilities. diff --git a/MediaBrowser.Controller/Entities/ICollectionFolder.cs b/MediaBrowser.Controller/Entities/ICollectionFolder.cs index 4c6346f7ee..656aa37ce6 100644 --- a/MediaBrowser.Controller/Entities/ICollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/ICollectionFolder.cs @@ -1,4 +1,5 @@ - +using System.Collections.Generic; + namespace MediaBrowser.Controller.Entities { /// @@ -7,5 +8,7 @@ namespace MediaBrowser.Controller.Entities public interface ICollectionFolder { string CollectionType { get; } + string Path { get; } + IEnumerable PhysicalLocations { get; } } } diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index bcbaa967a1..eb08a6f2fe 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -3,7 +3,6 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace MediaBrowser.Controller.Entities @@ -60,7 +59,7 @@ namespace MediaBrowser.Controller.Entities CollectionType.Trailers }; - var collectionFolder = folder as CollectionFolder; + var collectionFolder = folder as ICollectionFolder; if (collectionFolder == null) { @@ -70,30 +69,4 @@ namespace MediaBrowser.Controller.Entities return standaloneTypes.Contains(collectionFolder.CollectionType ?? string.Empty); } } - - public class SpecialFolder : Folder - { - public SpecialFolderType SpecialFolderType { get; set; } - public string ItemTypeName { get; set; } - public string ParentId { get; set; } - - public override IEnumerable GetChildren(User user, bool includeLinkedChildren) - { - var parent = (Folder)LibraryManager.GetItemById(new Guid(ParentId)); - - if (SpecialFolderType == SpecialFolderType.ItemsByType) - { - var items = parent.GetRecursiveChildren(user, includeLinkedChildren); - - return items.Where(i => string.Equals(i.GetType().Name, ItemTypeName, StringComparison.OrdinalIgnoreCase)); - } - - return new List(); - } - } - - public enum SpecialFolderType - { - ItemsByType = 1 - } } diff --git a/MediaBrowser.Model/Devices/DeviceInfo.cs b/MediaBrowser.Model/Devices/DeviceInfo.cs index cc622af27f..fce3b02f60 100644 --- a/MediaBrowser.Model/Devices/DeviceInfo.cs +++ b/MediaBrowser.Model/Devices/DeviceInfo.cs @@ -21,6 +21,11 @@ namespace MediaBrowser.Model.Devices /// The last name of the user. public string LastUserName { get; set; } /// + /// Gets or sets the name of the application. + /// + /// The name of the application. + public string AppName { get; set; } + /// /// Gets or sets the last user identifier. /// /// The last user identifier. diff --git a/MediaBrowser.Model/Devices/DevicesOptions.cs b/MediaBrowser.Model/Devices/DevicesOptions.cs index 6c2082e8df..ba2baddbe1 100644 --- a/MediaBrowser.Model/Devices/DevicesOptions.cs +++ b/MediaBrowser.Model/Devices/DevicesOptions.cs @@ -5,6 +5,7 @@ namespace MediaBrowser.Model.Devices { public string[] EnabledCameraUploadDevices { get; set; } public string CameraUploadPath { get; set; } + public bool EnableCameraUploadSubfolders { get; set; } public DevicesOptions() { diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index 244b52b703..7ed7792136 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -74,6 +74,9 @@ namespace MediaBrowser.Model.Dlna public bool RequiresPlainVideoItems { get; set; } public bool RequiresPlainFolders { get; set; } + public bool SupportsDirectRemoteContent { get; set; } + public bool SupportsCustomHttpHeaders { get; set; } + public XmlAttribute[] XmlRootAttributes { get; set; } /// diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 815e8e20bf..776d9927ae 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -82,7 +82,14 @@ namespace MediaBrowser.Model.Dlna // If that doesn't produce anything, just take the first foreach (StreamInfo i in streams) { - if (i.IsDirectStream) + if (i.PlayMethod == PlayMethod.DirectPlay) + { + return i; + } + } + foreach (StreamInfo i in streams) + { + if (i.PlayMethod == PlayMethod.DirectStream) { return i; } @@ -249,11 +256,11 @@ namespace MediaBrowser.Model.Dlna if (IsEligibleForDirectPlay(item, maxBitrateSetting, subtitleStream, options)) { // See if it can be direct played - DirectPlayProfile directPlay = GetVideoDirectPlayProfile(options.Profile, item, videoStream, audioStream); + var directPlay = GetVideoDirectPlayProfile(options.Profile, item, videoStream, audioStream); if (directPlay != null) { - playlistItem.PlayMethod = PlayMethod.DirectStream; + playlistItem.PlayMethod = directPlay.Value; playlistItem.Container = item.Container; if (subtitleStream != null) @@ -366,7 +373,7 @@ namespace MediaBrowser.Model.Dlna return 128000; } - private DirectPlayProfile GetVideoDirectPlayProfile(DeviceProfile profile, + private PlayMethod? GetVideoDirectPlayProfile(DeviceProfile profile, MediaSourceInfo mediaSource, MediaStream videoStream, MediaStream audioStream) @@ -487,7 +494,21 @@ namespace MediaBrowser.Model.Dlna } } - return directPlay; + if (mediaSource.Protocol == MediaProtocol.Http) + { + if (!profile.SupportsDirectRemoteContent) + { + return null; + } + + if (mediaSource.RequiredHttpHeaders.Count > 0 && !profile.SupportsCustomHttpHeaders) + { + return null; + } + return PlayMethod.DirectPlay; + } + + return PlayMethod.DirectStream; } private bool IsEligibleForDirectPlay(MediaSourceInfo item, diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 36dc611f26..58848ff50e 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -1,5 +1,4 @@ -using System.Globalization; -using MediaBrowser.Model.Drawing; +using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; @@ -7,6 +6,7 @@ using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Session; using System; using System.Collections.Generic; +using System.Globalization; namespace MediaBrowser.Model.Dlna { @@ -89,6 +89,11 @@ namespace MediaBrowser.Model.Dlna public string ToDlnaUrl(string baseUrl) { + if (PlayMethod == PlayMethod.DirectPlay) + { + return MediaSource.Path; + } + if (string.IsNullOrEmpty(baseUrl)) { throw new ArgumentNullException(baseUrl); diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs index af52486089..e38aef8105 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs @@ -186,13 +186,6 @@ namespace MediaBrowser.Server.Implementations.Channels private double? GetDownloadLimit(ChannelOptions channelOptions) { - if (!_security.IsMBSupporter) - { - const double limit = .5; - - return Math.Min(channelOptions.DownloadSizeLimit ?? limit, limit); - } - return channelOptions.DownloadSizeLimit; } diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs index 55425ad7e7..6d4238bdf5 100644 --- a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs +++ b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs @@ -29,7 +29,7 @@ namespace MediaBrowser.Server.Implementations.Devices _config = config; } - public Task RegisterDevice(string reportedId, string name, string usedByUserId) + public Task RegisterDevice(string reportedId, string name, string appName, string usedByUserId) { var device = GetDevice(reportedId) ?? new DeviceInfo { @@ -37,6 +37,7 @@ namespace MediaBrowser.Server.Implementations.Devices }; device.Name = name; + device.AppName = appName; if (!string.IsNullOrWhiteSpace(usedByUserId)) { @@ -115,12 +116,21 @@ namespace MediaBrowser.Server.Implementations.Devices { var config = _config.GetUploadOptions(); + var device = GetDevice(deviceId); + if (!string.IsNullOrWhiteSpace(config.CameraUploadPath)) { return config.CameraUploadPath; } - return Path.Combine(_config.CommonApplicationPaths.DataPath, "camerauploads"); + var path = Path.Combine(_config.CommonApplicationPaths.DataPath, "camerauploads"); + + if (config.EnableCameraUploadSubfolders) + { + path = Path.Combine(path, _fileSystem.GetValidFilename(device.Name)); + } + + return path; } } diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 839fb3d575..71e1b1087e 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1501,7 +1501,7 @@ namespace MediaBrowser.Server.Implementations.Library .Select(i => i.RootFolder) .Distinct() .SelectMany(i => i.Children) - .OfType() + .OfType() .Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path)) .Select(i => i.CollectionType) .Where(i => !string.IsNullOrEmpty(i)) diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs index 60e7edfdd4..e3fe37be87 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs @@ -29,11 +29,22 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers } protected static string[] ImageExtensions = { ".tiff", ".jpeg", ".jpg", ".png", ".aiff" }; + + private static readonly string[] IgnoreFiles = + { + "folder", + "thumb", + "landscape", + "fanart", + "backdrop", + "poster" + }; + internal static bool IsImageFile(string path) { - var filename = Path.GetFileName(path); + var filename = Path.GetFileNameWithoutExtension(path) ?? string.Empty; - return !string.Equals(filename, "folder.jpg", StringComparison.OrdinalIgnoreCase) + return !IgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase) && ImageExtensions.Contains(Path.GetExtension(path) ?? string.Empty, StringComparer.OrdinalIgnoreCase); } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index fe1f84ef37..efe50f45af 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1047,7 +1047,7 @@ "AppDeviceValues": "App: {0}, Device: {1}", "ProviderValue": "Provider: {0}", "LabelChannelDownloadSizeLimit": "Download size limit (GB):", - "LabelChannelDownloadSizeLimitHelp": "Limit the size of the channel download folder. Downloading beyond 500MB requires an active supporter membership.", + "LabelChannelDownloadSizeLimitHelpText": "Limit the size of the channel download folder.", "HeaderRecentActivity": "Recent Activity", "HeaderPeople": "People", "HeaderDownloadPeopleMetadataFor": "Download biography and images for:", @@ -1222,6 +1222,8 @@ "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." + "LabelCameraUploadPath": "Camera upload path:", + "LabelCameraUploadPathHelp": "Select a custom upload path, if desired. If unspecified a default folder will be used.", + "LabelCreateCameraUploadSubfolder": "Create a sub-folder for each device", + "LabelCreateCameraUploadSubfolderHelp": "Specific folders can be assigned to devices by clicking on the device on the Devices page." } diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 10c89c6138..8d640bf1e4 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -422,7 +422,7 @@ namespace MediaBrowser.Server.Implementations.Session if (!string.IsNullOrEmpty(deviceId)) { var userIdString = userId.HasValue ? userId.Value.ToString("N") : null; - await _deviceManager.RegisterDevice(deviceId, deviceName, userIdString).ConfigureAwait(false); + await _deviceManager.RegisterDevice(deviceId, deviceName, clientType, userIdString).ConfigureAwait(false); } } diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 9c31e29408..dc547d6083 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -564,6 +564,7 @@ namespace MediaBrowser.WebDashboard.Api "dashboardgeneral.js", "dashboardpage.js", "dashboardsync.js", + "device.js", "devices.js", "devicesupload.js", "directorybrowser.js", diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 65fc46978e..7a8d432009 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -367,6 +367,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -697,6 +700,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 41f99f47da..6f9d320df9 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.476 + 3.0.477 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 962eae0c87..a2fa43075c 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.476 + 3.0.477 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec index 992d2f2d02..cd18acd572 100644 --- a/Nuget/MediaBrowser.Model.Signed.nuspec +++ b/Nuget/MediaBrowser.Model.Signed.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Model.Signed - 3.0.476 + 3.0.477 MediaBrowser.Model - Signed Edition Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 7c65bf3e70..988533e649 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.476 + 3.0.477 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - + diff --git a/OpenSubtitlesHandler/OpenSubtitles.cs b/OpenSubtitlesHandler/OpenSubtitles.cs index 9452c25ece..2dc71560bc 100644 --- a/OpenSubtitlesHandler/OpenSubtitles.cs +++ b/OpenSubtitlesHandler/OpenSubtitles.cs @@ -17,6 +17,7 @@ along with this program. If not, see . */ using System; +using System.Globalization; using System.Text; using System.Collections.Generic; using System.IO; @@ -131,9 +132,18 @@ namespace OpenSubtitlesHandler { switch (MEMBER.Name) { - case "token": re.Token = TOKEN = MEMBER.Data.Data.ToString(); OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": re.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "status": re.Status = MEMBER.Data.Data.ToString(); OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; + case "token": + re.Token = TOKEN = MEMBER.Data.Data.ToString(); + OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); + break; + case "seconds": + re.Seconds = double.Parse(MEMBER.Data.Data.ToString(), CultureInfo.InvariantCulture); + OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); + break; + case "status": + re.Status = MEMBER.Data.Data.ToString(); + OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); + break; } } return re;