diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index f35ade4324..9b04ec0117 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -71,8 +71,7 @@ namespace MediaBrowser.Api
///
private void DeleteEncodedMediaCache()
{
- foreach (var file in Directory.EnumerateFiles(_appPaths.TranscodingTempPath)
- .Where(i => EntityResolutionHelper.VideoFileExtensions.Contains(Path.GetExtension(i)))
+ foreach (var file in Directory.EnumerateFiles(_appPaths.TranscodingTempPath, "*", SearchOption.AllDirectories)
.ToList())
{
File.Delete(file);
@@ -116,11 +115,10 @@ namespace MediaBrowser.Api
/// The path.
/// The type.
/// The process.
- /// if set to true [is video].
/// The start time ticks.
/// The source path.
/// The device id.
- public void OnTranscodeBeginning(string path, TranscodingJobType type, Process process, bool isVideo, long? startTimeTicks, string sourcePath, string deviceId)
+ public void OnTranscodeBeginning(string path, TranscodingJobType type, Process process, long? startTimeTicks, string sourcePath, string deviceId)
{
lock (_activeTranscodingJobs)
{
@@ -130,7 +128,6 @@ namespace MediaBrowser.Api
Path = path,
Process = process,
ActiveRequestCount = 1,
- IsVideo = isVideo,
StartTimeTicks = startTimeTicks,
SourcePath = sourcePath,
DeviceId = deviceId
@@ -261,7 +258,7 @@ namespace MediaBrowser.Api
{
// This is really only needed for HLS.
// Progressive streams can stop on their own reliably
- jobs.AddRange(_activeTranscodingJobs.Where(i => isVideo == i.IsVideo && string.Equals(deviceId, i.DeviceId, StringComparison.OrdinalIgnoreCase)));
+ jobs.AddRange(_activeTranscodingJobs.Where(i => string.Equals(deviceId, i.DeviceId, StringComparison.OrdinalIgnoreCase)));
}
foreach (var job in jobs)
@@ -325,37 +322,15 @@ namespace MediaBrowser.Api
}
}
- // Determine if it exited successfully
- var hasExitedSuccessfully = false;
-
- try
- {
- hasExitedSuccessfully = process.ExitCode == 0;
- }
- catch (InvalidOperationException)
- {
-
- }
- catch (NotSupportedException)
- {
-
- }
-
// Dispose the process
process.Dispose();
- // If it didn't complete successfully cleanup the partial files
- // Also don't cache output from resume points
- // Also don't cache video
- if (!hasExitedSuccessfully || job.StartTimeTicks.HasValue || job.IsVideo)
- {
- DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
- }
+ DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
}
private async void DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs)
{
- if (retryCount >= 5)
+ if (retryCount >= 10)
{
return;
}
@@ -455,7 +430,6 @@ namespace MediaBrowser.Api
/// The kill timer.
public Timer KillTimer { get; set; }
- public bool IsVideo { get; set; }
public long? StartTimeTicks { get; set; }
public string SourcePath { get; set; }
public string DeviceId { get; set; }
diff --git a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs b/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs
index cd04a82121..6acecd342d 100644
--- a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs
+++ b/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs
@@ -24,6 +24,8 @@ namespace MediaBrowser.Api.DefaultTheme
[ApiMember(Name = "RecentlyPlayedGamesLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int RecentlyPlayedGamesLimit { get; set; }
+
+ public string ParentId { get; set; }
}
[Route("/MBT/DefaultTheme/TV", "GET")]
@@ -49,6 +51,8 @@ namespace MediaBrowser.Api.DefaultTheme
[ApiMember(Name = "LatestEpisodeLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int LatestEpisodeLimit { get; set; }
+
+ public string ParentId { get; set; }
}
[Route("/MBT/DefaultTheme/Movies", "GET")]
@@ -71,6 +75,8 @@ namespace MediaBrowser.Api.DefaultTheme
[ApiMember(Name = "LatestTrailersLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int LatestTrailersLimit { get; set; }
+
+ public string ParentId { get; set; }
}
[Route("/MBT/DefaultTheme/Favorites", "GET")]
@@ -224,7 +230,7 @@ namespace MediaBrowser.Api.DefaultTheme
{
var user = _userManager.GetUserById(request.UserId);
- var items = user.RootFolder.GetRecursiveChildren(user, i => i is Game || i is GameSystem)
+ var items = GetAllLibraryItems(user.Id, _userManager, _libraryManager, request.ParentId).Where(i => i is Game || i is GameSystem)
.ToList();
var gamesWithImages = items.OfType().Where(i => !string.IsNullOrEmpty(i.PrimaryImagePath)).ToList();
@@ -280,7 +286,7 @@ namespace MediaBrowser.Api.DefaultTheme
var user = _userManager.GetUserById(request.UserId);
- var series = user.RootFolder.GetRecursiveChildren(user)
+ var series = GetAllLibraryItems(user.Id, _userManager, _libraryManager, request.ParentId)
.OfType()
.ToList();
@@ -403,7 +409,8 @@ namespace MediaBrowser.Api.DefaultTheme
{
var user = _userManager.GetUserById(request.UserId);
- var items = user.RootFolder.GetRecursiveChildren(user, i => i is Movie || i is Trailer || i is BoxSet)
+ var items = GetAllLibraryItems(user.Id, _userManager, _libraryManager, request.ParentId)
+ .Where(i => i is Movie || i is Trailer || i is BoxSet)
.ToList();
var view = new MoviesView();
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 7e352e4de1..23209b59ce 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -903,7 +903,7 @@ namespace MediaBrowser.Api.Playback
EnableRaisingEvents = true
};
- ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, TranscodingJobType, process, state.IsInputVideo, state.Request.StartTimeTicks, state.MediaPath, state.Request.DeviceId);
+ ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, TranscodingJobType, process, state.Request.StartTimeTicks, state.MediaPath, state.Request.DeviceId);
var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments;
Logger.Info(commandLineLogMessage);
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index c865504045..fd93ef6852 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -273,9 +273,7 @@ namespace MediaBrowser.Api.Playback.Hls
const string keyFrameArg = " -force_key_frames expr:if(isnan(prev_forced_t),gte(t,.1),gte(t,prev_forced_t+5))";
- var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsExternal &&
- (state.SubtitleStream.Codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 ||
- state.SubtitleStream.Codec.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1);
+ var hasGraphicalSubs = state.SubtitleStream != null && state.SubtitleStream.IsGraphicalSubtitleStream;
var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index efd98616f9..77ac95815d 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -168,9 +168,7 @@ namespace MediaBrowser.Api.Playback.Hls
" -force_key_frames expr:if(isnan(prev_forced_t),gte(t,.1),gte(t,prev_forced_t+1))" :
" -force_key_frames expr:if(isnan(prev_forced_t),gte(t,.1),gte(t,prev_forced_t+5))";
- var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsExternal &&
- (state.SubtitleStream.Codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 ||
- state.SubtitleStream.Codec.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1);
+ var hasGraphicalSubs = state.SubtitleStream != null && state.SubtitleStream.IsGraphicalSubtitleStream;
var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index f21e69290e..d7061ae754 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -146,9 +146,7 @@ namespace MediaBrowser.Api.Playback.Progressive
args += keyFrameArg;
- var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsExternal &&
- (state.SubtitleStream.Codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 ||
- state.SubtitleStream.Codec.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1);
+ var hasGraphicalSubs = state.SubtitleStream != null && state.SubtitleStream.IsGraphicalSubtitleStream;
var request = state.VideoRequest;
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index 503d1513c1..be761ef662 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -305,13 +305,7 @@ namespace MediaBrowser.Controller.Entities.TV
if (!ParentIndexNumber.HasValue && !string.IsNullOrEmpty(Path))
{
- ParentIndexNumber = TVUtils.GetSeasonNumberFromPath(Path);
-
- // If a change was made record it
- if (ParentIndexNumber.HasValue)
- {
- hasChanges = true;
- }
+ ParentIndexNumber = TVUtils.GetSeasonNumberFromEpisodeFile(Path);
}
// If a change was made record it
diff --git a/MediaBrowser.Model/Configuration/MetadataOptions.cs b/MediaBrowser.Model/Configuration/MetadataOptions.cs
index 88fa486f97..fdfbbf4f42 100644
--- a/MediaBrowser.Model/Configuration/MetadataOptions.cs
+++ b/MediaBrowser.Model/Configuration/MetadataOptions.cs
@@ -52,14 +52,30 @@ namespace MediaBrowser.Model.Configuration
public int GetLimit(ImageType type)
{
- ImageOption option = ImageOptions.FirstOrDefault(i => i.Type == type);
+ ImageOption option = null;
+ foreach (ImageOption i in ImageOptions)
+ {
+ if (i.Type == type)
+ {
+ option = i;
+ break;
+ }
+ }
return option == null ? 1 : option.Limit;
}
public int GetMinWidth(ImageType type)
{
- ImageOption option = ImageOptions.FirstOrDefault(i => i.Type == type);
+ ImageOption option = null;
+ foreach (ImageOption i in ImageOptions)
+ {
+ if (i.Type == type)
+ {
+ option = i;
+ break;
+ }
+ }
return option == null ? 0 : option.MinWidth;
}
diff --git a/MediaBrowser.Model/Configuration/NotificationOptions.cs b/MediaBrowser.Model/Configuration/NotificationOptions.cs
index 0ed43ae1eb..d6517e895d 100644
--- a/MediaBrowser.Model/Configuration/NotificationOptions.cs
+++ b/MediaBrowser.Model/Configuration/NotificationOptions.cs
@@ -70,7 +70,11 @@ namespace MediaBrowser.Model.Configuration
public NotificationOption GetOptions(string type)
{
- return Options.FirstOrDefault(i => string.Equals(type, i.Type, StringComparison.OrdinalIgnoreCase));
+ foreach (NotificationOption i in Options)
+ {
+ if (string.Equals(type, i.Type, StringComparison.OrdinalIgnoreCase)) return i;
+ }
+ return null;
}
public bool IsEnabled(string type)
diff --git a/MediaBrowser.Model/Configuration/NotificationType.cs b/MediaBrowser.Model/Configuration/NotificationType.cs
index eaafb651ce..0ddcf42517 100644
--- a/MediaBrowser.Model/Configuration/NotificationType.cs
+++ b/MediaBrowser.Model/Configuration/NotificationType.cs
@@ -12,6 +12,7 @@ namespace MediaBrowser.Model.Configuration
PluginUpdateInstalled,
PluginUninstalled,
NewLibraryContent,
+ NewLibraryContentMultiple,
ServerRestartRequired,
TaskFailed,
VideoPlayback
diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
index 5309df1310..a7ad49cba2 100644
--- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
+++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
@@ -1,6 +1,5 @@
using MediaBrowser.Model.MediaInfo;
using System.Collections.Generic;
-using System.Linq;
namespace MediaBrowser.Model.Dlna
{
@@ -158,11 +157,21 @@ namespace MediaBrowser.Model.Dlna
if (string.IsNullOrEmpty(orgPn))
{
- orgPn = GetVideoOrgPnValue(container, videoCodec, audioCodec, width, height, timestamp)
- .FirstOrDefault();
+ foreach (string s in GetVideoOrgPnValue(container, videoCodec, audioCodec, width, height, timestamp))
+ {
+ orgPn = s;
+ break;
+ }
+ }
+ if (string.IsNullOrEmpty(orgPn))
+ {
// TODO: Support multiple values and return multiple headers?
- orgPn = (orgPn ?? string.Empty).Split(',').FirstOrDefault();
+ foreach (string s in (orgPn ?? string.Empty).Split(','))
+ {
+ orgPn = s;
+ break;
+ }
}
string contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn;
@@ -191,16 +200,12 @@ namespace MediaBrowser.Model.Dlna
return format.HasValue ? format.Value.ToString() : null;
}
- private IEnumerable GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestamp)
+ private List GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestamp)
{
- return new MediaFormatProfileResolver()
- .ResolveVideoFormat(container,
- videoCodec,
- audioCodec,
- width,
- height,
- timestamp)
- .Select(i => i.ToString());
+ List list = new List();
+ foreach (MediaFormatProfile i in new MediaFormatProfileResolver().ResolveVideoFormat(container, videoCodec, audioCodec, width, height, timestamp))
+ list.Add(i.ToString());
+ return list;
}
}
}
diff --git a/MediaBrowser.Model/Dlna/Filter.cs b/MediaBrowser.Model/Dlna/Filter.cs
index c8940734b2..760adb5859 100644
--- a/MediaBrowser.Model/Dlna/Filter.cs
+++ b/MediaBrowser.Model/Dlna/Filter.cs
@@ -19,9 +19,10 @@ namespace MediaBrowser.Model.Dlna
{
_all = string.Equals(filter, "*", StringComparison.OrdinalIgnoreCase);
- _fields = (filter ?? string.Empty)
- .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
- .ToList();
+ List list = new List();
+ foreach (string s in (filter ?? string.Empty).Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries))
+ list.Add(s);
+ _fields = list;
}
public bool Contains(string field)
diff --git a/MediaBrowser.Model/Dlna/TranscodingProfile.cs b/MediaBrowser.Model/Dlna/TranscodingProfile.cs
index bee5f2a691..51f4bfe619 100644
--- a/MediaBrowser.Model/Dlna/TranscodingProfile.cs
+++ b/MediaBrowser.Model/Dlna/TranscodingProfile.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using System.Linq;
using System.Xml.Serialization;
namespace MediaBrowser.Model.Dlna
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index 66163c1ef7..9f64b36e43 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -1,4 +1,6 @@
-using System.Diagnostics;
+using System;
+using System.Diagnostics;
+using System.Runtime.Serialization;
namespace MediaBrowser.Model.Entities
{
@@ -128,6 +130,20 @@ namespace MediaBrowser.Model.Entities
/// true if this instance is external; otherwise, false.
public bool IsExternal { get; set; }
+ [IgnoreDataMember]
+ public bool IsGraphicalSubtitleStream
+ {
+ get
+ {
+ if (IsExternal) return false;
+
+ var codec = Codec ?? string.Empty;
+
+ return codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 ||
+ codec.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1;
+ }
+ }
+
///
/// Gets or sets the filename.
///
diff --git a/MediaBrowser.Model/Web/QueryStringDictionary.cs b/MediaBrowser.Model/Web/QueryStringDictionary.cs
index b532358ff1..b011d4d9cb 100644
--- a/MediaBrowser.Model/Web/QueryStringDictionary.cs
+++ b/MediaBrowser.Model/Web/QueryStringDictionary.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
namespace MediaBrowser.Model.Web
@@ -24,7 +25,7 @@ namespace MediaBrowser.Model.Web
/// The value.
public void Add(string name, int value)
{
- Add(name, value.ToString());
+ Add(name, value.ToString(CultureInfo.InvariantCulture));
}
///
@@ -34,7 +35,7 @@ namespace MediaBrowser.Model.Web
/// The value.
public void Add(string name, long value)
{
- Add(name, value.ToString());
+ Add(name, value.ToString(CultureInfo.InvariantCulture));
}
///
@@ -44,7 +45,7 @@ namespace MediaBrowser.Model.Web
/// The value.
public void Add(string name, double value)
{
- Add(name, value.ToString());
+ Add(name, value.ToString(CultureInfo.InvariantCulture));
}
///
@@ -135,7 +136,7 @@ namespace MediaBrowser.Model.Web
throw new ArgumentNullException("value");
}
- Add(name, string.Join(",", value.Select(v => v.ToString()).ToArray()));
+ Add(name, string.Join(",", value.Select(v => v.ToString(CultureInfo.InvariantCulture)).ToArray()));
}
///
@@ -188,7 +189,7 @@ namespace MediaBrowser.Model.Web
/// The name.
/// The value.
/// The delimiter.
- /// value
+ /// value
public void Add(string name, IEnumerable value, string delimiter)
{
if (value == null)
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs
index 7607ec98a3..fdc81db373 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Events;
+using System.Globalization;
+using MediaBrowser.Common.Events;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Common.Updates;
@@ -247,10 +248,10 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
DisposeLibraryUpdateTimer();
}
- var item = items.FirstOrDefault();
-
- if (item != null)
+ if (items.Count == 1)
{
+ var item = items.First();
+
var notification = new NotificationRequest
{
NotificationType = NotificationType.NewLibraryContent.ToString()
@@ -258,10 +259,16 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
notification.Variables["Name"] = item.Name;
- if (items.Count > 1)
+ await SendNotification(notification).ConfigureAwait(false);
+ }
+ else
+ {
+ var notification = new NotificationRequest
{
- notification.Name = items.Count + " new library items.";
- }
+ NotificationType = NotificationType.NewLibraryContentMultiple.ToString()
+ };
+
+ notification.Variables["ItemCount"] = items.Count.ToString(CultureInfo.InvariantCulture);
await SendNotification(notification).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json
index 781a4c5b70..bcd04f4ae3 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/server.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json
@@ -568,6 +568,7 @@
"NotificationOptionTaskFailed": "Scheduled task failure",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
+ "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
"SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
"NotificationOptionServerRestartRequired": "Server restart required",
"LabelNotificationEnabled": "Enable this notification",
@@ -716,5 +717,9 @@
"LabelDownloadLanguages": "Download languages:",
"ButtonRegister": "Register",
"LabelSkipIfAudioTrackPresent": "Skip if the default audio track matches the download language",
- "LabelSkipIfAudioTrackPresentHelp": "Uncheck this to ensure all videos have subtitles, regardless of audio language."
+ "LabelSkipIfAudioTrackPresentHelp": "Uncheck this to ensure all videos have subtitles, regardless of audio language.",
+ "HeaderSendMessage": "Send Message",
+ "ButtonSend": "Send",
+ "LabelMessageText": "Message text:",
+ "LabelMessageTitle": "Message title:"
}
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Notifications/CoreNotificationTypes.cs b/MediaBrowser.Server.Implementations/Notifications/CoreNotificationTypes.cs
index f712949d91..012b5ae927 100644
--- a/MediaBrowser.Server.Implementations/Notifications/CoreNotificationTypes.cs
+++ b/MediaBrowser.Server.Implementations/Notifications/CoreNotificationTypes.cs
@@ -90,6 +90,13 @@ namespace MediaBrowser.Server.Implementations.Notifications
Variables = new List{"Name"}
},
+ new NotificationTypeInfo
+ {
+ Type = NotificationType.NewLibraryContentMultiple.ToString(),
+ DefaultTitle = "{ItemCount} new items have been added to your media library.",
+ Variables = new List{"ItemCount"}
+ },
+
new NotificationTypeInfo
{
Type = NotificationType.AudioPlayback.ToString(),
diff --git a/OpenSubtitlesHandler/OpenSubtitles.cs b/OpenSubtitlesHandler/OpenSubtitles.cs
index e810dad69c..9452c25ece 100644
--- a/OpenSubtitlesHandler/OpenSubtitles.cs
+++ b/OpenSubtitlesHandler/OpenSubtitles.cs
@@ -440,6 +440,187 @@ namespace OpenSubtitlesHandler
}
return new MethodResponseError("Fail", "Search Subtitles call failed !");
}
+
+ public static async Task SearchSubtitlesAsync(SubtitleSearchParameters[] parameters, CancellationToken cancellationToken)
+ {
+ if (TOKEN == "")
+ {
+ OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error);
+ return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first.");
+ }
+ if (parameters == null)
+ {
+ OSHConsole.UpdateLine("No subtitle search parameter passed !!", DebugCode.Error);
+ return new MethodResponseError("Fail", "No subtitle search parameter passed"); ;
+ }
+ if (parameters.Length == 0)
+ {
+ OSHConsole.UpdateLine("No subtitle search parameter passed !!", DebugCode.Error);
+ return new MethodResponseError("Fail", "No subtitle search parameter passed"); ;
+ }
+ // Method call ..
+ List parms = new List();
+ // Add token param
+ parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String));
+ // Add subtitle search parameters. Each one will be like 'array' of structs.
+ XmlRpcValueArray array = new XmlRpcValueArray();
+ foreach (SubtitleSearchParameters param in parameters)
+ {
+ XmlRpcValueStruct strct = new XmlRpcValueStruct(new List());
+ // sublanguageid member
+ XmlRpcStructMember member = new XmlRpcStructMember("sublanguageid",
+ new XmlRpcValueBasic(param.SubLangaugeID, XmlRpcBasicValueType.String));
+ strct.Members.Add(member);
+ // moviehash member
+ if (param.MovieHash.Length > 0 && param.MovieByteSize > 0)
+ {
+ member = new XmlRpcStructMember("moviehash",
+ new XmlRpcValueBasic(param.MovieHash, XmlRpcBasicValueType.String));
+ strct.Members.Add(member);
+ // moviehash member
+ member = new XmlRpcStructMember("moviebytesize",
+ new XmlRpcValueBasic(param.MovieByteSize, XmlRpcBasicValueType.Int));
+ strct.Members.Add(member);
+ }
+ if (param.Query.Length > 0)
+ {
+ member = new XmlRpcStructMember("query",
+ new XmlRpcValueBasic(param.Query, XmlRpcBasicValueType.String));
+ strct.Members.Add(member);
+ }
+
+ if (param.Episode.Length > 0 && param.Season.Length > 0)
+ {
+ member = new XmlRpcStructMember("season",
+ new XmlRpcValueBasic(param.Season, XmlRpcBasicValueType.String));
+ strct.Members.Add(member);
+ member = new XmlRpcStructMember("episode",
+ new XmlRpcValueBasic(param.Episode, XmlRpcBasicValueType.String));
+ strct.Members.Add(member);
+ }
+
+ // imdbid member
+ if (param.IMDbID.Length > 0)
+ {
+ member = new XmlRpcStructMember("imdbid",
+ new XmlRpcValueBasic(param.IMDbID, XmlRpcBasicValueType.String));
+ strct.Members.Add(member);
+ }
+ // Add the struct to the array
+ array.Values.Add(strct);
+ }
+ // Add the array to the parameters
+ parms.Add(array);
+ // Call !
+ XmlRpcMethodCall call = new XmlRpcMethodCall("SearchSubtitles", parms);
+ OSHConsole.WriteLine("Sending SearchSubtitles request to the server ...", DebugCode.Good);
+ // Send the request to the server
+ string response = Utilities.GetStreamString(await Utilities.SendRequestAsync(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT, cancellationToken).ConfigureAwait(false));
+
+ if (!response.Contains("ERROR:"))
+ {
+ // No error occur, get and decode the response.
+ XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response);
+ if (calls.Length > 0)
+ {
+ if (calls[0].Parameters.Count > 0)
+ {
+ // We expect Struct of 3 members:
+ //* the first is status
+ //* the second is [array of structs, each one includes subtitle file].
+ //* the third is [double basic value] represent seconds token by server.
+ XmlRpcValueStruct mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0];
+ // Create the response, we'll need it later
+ MethodResponseSubtitleSearch R = new MethodResponseSubtitleSearch();
+ // To make sure response is not currepted by server, do it in loop
+ foreach (XmlRpcStructMember MEMBER in mainStruct.Members)
+ {
+ if (MEMBER.Name == "status")
+ {
+ R.Status = (string)MEMBER.Data.Data;
+ OSHConsole.WriteLine("Status= " + R.Status);
+ }
+ else if (MEMBER.Name == "seconds")
+ {
+ R.Seconds = (double)MEMBER.Data.Data;
+ OSHConsole.WriteLine("Seconds= " + R.Seconds);
+ }
+ else if (MEMBER.Name == "data")
+ {
+ if (MEMBER.Data is XmlRpcValueArray)
+ {
+ OSHConsole.WriteLine("Search results: ");
+
+ XmlRpcValueArray rarray = (XmlRpcValueArray)MEMBER.Data;
+ foreach (IXmlRpcValue subStruct in rarray.Values)
+ {
+ if (subStruct == null) continue;
+ if (!(subStruct is XmlRpcValueStruct)) continue;
+
+ SubtitleSearchResult result = new SubtitleSearchResult();
+ foreach (XmlRpcStructMember submember in ((XmlRpcValueStruct)subStruct).Members)
+ {
+ // To avoid errors of arranged info or missing ones, let's do it with switch..
+ switch (submember.Name)
+ {
+ case "IDMovie": result.IDMovie = submember.Data.Data.ToString(); break;
+ case "IDMovieImdb": result.IDMovieImdb = submember.Data.Data.ToString(); break;
+ case "IDSubMovieFile": result.IDSubMovieFile = submember.Data.Data.ToString(); break;
+ case "IDSubtitle": result.IDSubtitle = submember.Data.Data.ToString(); break;
+ case "IDSubtitleFile": result.IDSubtitleFile = submember.Data.Data.ToString(); break;
+ case "ISO639": result.ISO639 = submember.Data.Data.ToString(); break;
+ case "LanguageName": result.LanguageName = submember.Data.Data.ToString(); break;
+ case "MovieByteSize": result.MovieByteSize = submember.Data.Data.ToString(); break;
+ case "MovieHash": result.MovieHash = submember.Data.Data.ToString(); break;
+ case "MovieImdbRating": result.MovieImdbRating = submember.Data.Data.ToString(); break;
+ case "MovieName": result.MovieName = submember.Data.Data.ToString(); break;
+ case "MovieNameEng": result.MovieNameEng = submember.Data.Data.ToString(); break;
+ case "MovieReleaseName": result.MovieReleaseName = submember.Data.Data.ToString(); break;
+ case "MovieTimeMS": result.MovieTimeMS = submember.Data.Data.ToString(); break;
+ case "MovieYear": result.MovieYear = submember.Data.Data.ToString(); break;
+ case "SubActualCD": result.SubActualCD = submember.Data.Data.ToString(); break;
+ case "SubAddDate": result.SubAddDate = submember.Data.Data.ToString(); break;
+ case "SubAuthorComment": result.SubAuthorComment = submember.Data.Data.ToString(); break;
+ case "SubBad": result.SubBad = submember.Data.Data.ToString(); break;
+ case "SubDownloadLink": result.SubDownloadLink = submember.Data.Data.ToString(); break;
+ case "SubDownloadsCnt": result.SubDownloadsCnt = submember.Data.Data.ToString(); break;
+ case "SeriesEpisode": result.SeriesEpisode = submember.Data.Data.ToString(); break;
+ case "SeriesSeason": result.SeriesSeason = submember.Data.Data.ToString(); break;
+ case "SubFileName": result.SubFileName = submember.Data.Data.ToString(); break;
+ case "SubFormat": result.SubFormat = submember.Data.Data.ToString(); break;
+ case "SubHash": result.SubHash = submember.Data.Data.ToString(); break;
+ case "SubLanguageID": result.SubLanguageID = submember.Data.Data.ToString(); break;
+ case "SubRating": result.SubRating = submember.Data.Data.ToString(); break;
+ case "SubSize": result.SubSize = submember.Data.Data.ToString(); break;
+ case "SubSumCD": result.SubSumCD = submember.Data.Data.ToString(); break;
+ case "UserID": result.UserID = submember.Data.Data.ToString(); break;
+ case "UserNickName": result.UserNickName = submember.Data.Data.ToString(); break;
+ case "ZipDownloadLink": result.ZipDownloadLink = submember.Data.Data.ToString(); break;
+ }
+ }
+ R.Results.Add(result);
+ OSHConsole.WriteLine(">" + result.ToString());
+ }
+ }
+ else// Unknown data ?
+ {
+ OSHConsole.WriteLine("Data= " + MEMBER.Data.Data.ToString(), DebugCode.Warning);
+ }
+ }
+ }
+ // Return the response to user !!
+ return R;
+ }
+ }
+ }
+ else
+ {
+ OSHConsole.WriteLine(response, DebugCode.Error);
+ return new MethodResponseError("Fail", response);
+ }
+ return new MethodResponseError("Fail", "Search Subtitles call failed !");
+ }
+
///
/// Download subtitle file(s)
///