mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
Do better to make sure hls files are cleaned up
This commit is contained in:
parent
06a11c27d9
commit
1a323767be
@ -71,8 +71,7 @@ namespace MediaBrowser.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void DeleteEncodedMediaCache()
|
private void DeleteEncodedMediaCache()
|
||||||
{
|
{
|
||||||
foreach (var file in Directory.EnumerateFiles(_appPaths.TranscodingTempPath)
|
foreach (var file in Directory.EnumerateFiles(_appPaths.TranscodingTempPath, "*", SearchOption.AllDirectories)
|
||||||
.Where(i => EntityResolutionHelper.VideoFileExtensions.Contains(Path.GetExtension(i)))
|
|
||||||
.ToList())
|
.ToList())
|
||||||
{
|
{
|
||||||
File.Delete(file);
|
File.Delete(file);
|
||||||
@ -116,11 +115,10 @@ namespace MediaBrowser.Api
|
|||||||
/// <param name="path">The path.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <param name="type">The type.</param>
|
/// <param name="type">The type.</param>
|
||||||
/// <param name="process">The process.</param>
|
/// <param name="process">The process.</param>
|
||||||
/// <param name="isVideo">if set to <c>true</c> [is video].</param>
|
|
||||||
/// <param name="startTimeTicks">The start time ticks.</param>
|
/// <param name="startTimeTicks">The start time ticks.</param>
|
||||||
/// <param name="sourcePath">The source path.</param>
|
/// <param name="sourcePath">The source path.</param>
|
||||||
/// <param name="deviceId">The device id.</param>
|
/// <param name="deviceId">The device id.</param>
|
||||||
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)
|
lock (_activeTranscodingJobs)
|
||||||
{
|
{
|
||||||
@ -130,7 +128,6 @@ namespace MediaBrowser.Api
|
|||||||
Path = path,
|
Path = path,
|
||||||
Process = process,
|
Process = process,
|
||||||
ActiveRequestCount = 1,
|
ActiveRequestCount = 1,
|
||||||
IsVideo = isVideo,
|
|
||||||
StartTimeTicks = startTimeTicks,
|
StartTimeTicks = startTimeTicks,
|
||||||
SourcePath = sourcePath,
|
SourcePath = sourcePath,
|
||||||
DeviceId = deviceId
|
DeviceId = deviceId
|
||||||
@ -261,7 +258,7 @@ namespace MediaBrowser.Api
|
|||||||
{
|
{
|
||||||
// This is really only needed for HLS.
|
// This is really only needed for HLS.
|
||||||
// Progressive streams can stop on their own reliably
|
// 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)
|
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
|
// Dispose the process
|
||||||
process.Dispose();
|
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)
|
private async void DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs)
|
||||||
{
|
{
|
||||||
if (retryCount >= 5)
|
if (retryCount >= 10)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -455,7 +430,6 @@ namespace MediaBrowser.Api
|
|||||||
/// <value>The kill timer.</value>
|
/// <value>The kill timer.</value>
|
||||||
public Timer KillTimer { get; set; }
|
public Timer KillTimer { get; set; }
|
||||||
|
|
||||||
public bool IsVideo { get; set; }
|
|
||||||
public long? StartTimeTicks { get; set; }
|
public long? StartTimeTicks { get; set; }
|
||||||
public string SourcePath { get; set; }
|
public string SourcePath { get; set; }
|
||||||
public string DeviceId { get; set; }
|
public string DeviceId { get; set; }
|
||||||
|
@ -24,6 +24,8 @@ namespace MediaBrowser.Api.DefaultTheme
|
|||||||
|
|
||||||
[ApiMember(Name = "RecentlyPlayedGamesLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "RecentlyPlayedGamesLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
public int RecentlyPlayedGamesLimit { get; set; }
|
public int RecentlyPlayedGamesLimit { get; set; }
|
||||||
|
|
||||||
|
public string ParentId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/MBT/DefaultTheme/TV", "GET")]
|
[Route("/MBT/DefaultTheme/TV", "GET")]
|
||||||
@ -49,6 +51,8 @@ namespace MediaBrowser.Api.DefaultTheme
|
|||||||
|
|
||||||
[ApiMember(Name = "LatestEpisodeLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "LatestEpisodeLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
public int LatestEpisodeLimit { get; set; }
|
public int LatestEpisodeLimit { get; set; }
|
||||||
|
|
||||||
|
public string ParentId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/MBT/DefaultTheme/Movies", "GET")]
|
[Route("/MBT/DefaultTheme/Movies", "GET")]
|
||||||
@ -71,6 +75,8 @@ namespace MediaBrowser.Api.DefaultTheme
|
|||||||
|
|
||||||
[ApiMember(Name = "LatestTrailersLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "LatestTrailersLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
public int LatestTrailersLimit { get; set; }
|
public int LatestTrailersLimit { get; set; }
|
||||||
|
|
||||||
|
public string ParentId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/MBT/DefaultTheme/Favorites", "GET")]
|
[Route("/MBT/DefaultTheme/Favorites", "GET")]
|
||||||
@ -224,7 +230,7 @@ namespace MediaBrowser.Api.DefaultTheme
|
|||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(request.UserId);
|
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();
|
.ToList();
|
||||||
|
|
||||||
var gamesWithImages = items.OfType<Game>().Where(i => !string.IsNullOrEmpty(i.PrimaryImagePath)).ToList();
|
var gamesWithImages = items.OfType<Game>().Where(i => !string.IsNullOrEmpty(i.PrimaryImagePath)).ToList();
|
||||||
@ -280,7 +286,7 @@ namespace MediaBrowser.Api.DefaultTheme
|
|||||||
|
|
||||||
var user = _userManager.GetUserById(request.UserId);
|
var user = _userManager.GetUserById(request.UserId);
|
||||||
|
|
||||||
var series = user.RootFolder.GetRecursiveChildren(user)
|
var series = GetAllLibraryItems(user.Id, _userManager, _libraryManager, request.ParentId)
|
||||||
.OfType<Series>()
|
.OfType<Series>()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
@ -403,7 +409,8 @@ namespace MediaBrowser.Api.DefaultTheme
|
|||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(request.UserId);
|
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();
|
.ToList();
|
||||||
|
|
||||||
var view = new MoviesView();
|
var view = new MoviesView();
|
||||||
|
@ -903,7 +903,7 @@ namespace MediaBrowser.Api.Playback
|
|||||||
EnableRaisingEvents = true
|
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;
|
var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments;
|
||||||
Logger.Info(commandLineLogMessage);
|
Logger.Info(commandLineLogMessage);
|
||||||
|
@ -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))";
|
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 &&
|
var hasGraphicalSubs = state.SubtitleStream != null && state.SubtitleStream.IsGraphicalSubtitleStream;
|
||||||
(state.SubtitleStream.Codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 ||
|
|
||||||
state.SubtitleStream.Codec.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1);
|
|
||||||
|
|
||||||
var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
|
var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
|
||||||
|
|
||||||
|
@ -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+1))" :
|
||||||
" -force_key_frames expr:if(isnan(prev_forced_t),gte(t,.1),gte(t,prev_forced_t+5))";
|
" -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 &&
|
var hasGraphicalSubs = state.SubtitleStream != null && state.SubtitleStream.IsGraphicalSubtitleStream;
|
||||||
(state.SubtitleStream.Codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 ||
|
|
||||||
state.SubtitleStream.Codec.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1);
|
|
||||||
|
|
||||||
var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
|
var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
|
||||||
|
|
||||||
|
@ -146,9 +146,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||||||
|
|
||||||
args += keyFrameArg;
|
args += keyFrameArg;
|
||||||
|
|
||||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsExternal &&
|
var hasGraphicalSubs = state.SubtitleStream != null && state.SubtitleStream.IsGraphicalSubtitleStream;
|
||||||
(state.SubtitleStream.Codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 ||
|
|
||||||
state.SubtitleStream.Codec.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1);
|
|
||||||
|
|
||||||
var request = state.VideoRequest;
|
var request = state.VideoRequest;
|
||||||
|
|
||||||
|
@ -305,13 +305,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||||||
|
|
||||||
if (!ParentIndexNumber.HasValue && !string.IsNullOrEmpty(Path))
|
if (!ParentIndexNumber.HasValue && !string.IsNullOrEmpty(Path))
|
||||||
{
|
{
|
||||||
ParentIndexNumber = TVUtils.GetSeasonNumberFromPath(Path);
|
ParentIndexNumber = TVUtils.GetSeasonNumberFromEpisodeFile(Path);
|
||||||
|
|
||||||
// If a change was made record it
|
|
||||||
if (ParentIndexNumber.HasValue)
|
|
||||||
{
|
|
||||||
hasChanges = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a change was made record it
|
// If a change was made record it
|
||||||
|
@ -52,14 +52,30 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
|
|
||||||
public int GetLimit(ImageType type)
|
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;
|
return option == null ? 1 : option.Limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetMinWidth(ImageType type)
|
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;
|
return option == null ? 0 : option.MinWidth;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,11 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
|
|
||||||
public NotificationOption GetOptions(string type)
|
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)
|
public bool IsEnabled(string type)
|
||||||
|
@ -12,6 +12,7 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
PluginUpdateInstalled,
|
PluginUpdateInstalled,
|
||||||
PluginUninstalled,
|
PluginUninstalled,
|
||||||
NewLibraryContent,
|
NewLibraryContent,
|
||||||
|
NewLibraryContentMultiple,
|
||||||
ServerRestartRequired,
|
ServerRestartRequired,
|
||||||
TaskFailed,
|
TaskFailed,
|
||||||
VideoPlayback
|
VideoPlayback
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
@ -158,11 +157,21 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
|
|
||||||
if (string.IsNullOrEmpty(orgPn))
|
if (string.IsNullOrEmpty(orgPn))
|
||||||
{
|
{
|
||||||
orgPn = GetVideoOrgPnValue(container, videoCodec, audioCodec, width, height, timestamp)
|
foreach (string s in GetVideoOrgPnValue(container, videoCodec, audioCodec, width, height, timestamp))
|
||||||
.FirstOrDefault();
|
{
|
||||||
|
orgPn = s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(orgPn))
|
||||||
|
{
|
||||||
// TODO: Support multiple values and return multiple headers?
|
// 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;
|
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;
|
return format.HasValue ? format.Value.ToString() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<string> GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestamp)
|
private List<string> GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestamp)
|
||||||
{
|
{
|
||||||
return new MediaFormatProfileResolver()
|
List<string> list = new List<string>();
|
||||||
.ResolveVideoFormat(container,
|
foreach (MediaFormatProfile i in new MediaFormatProfileResolver().ResolveVideoFormat(container, videoCodec, audioCodec, width, height, timestamp))
|
||||||
videoCodec,
|
list.Add(i.ToString());
|
||||||
audioCodec,
|
return list;
|
||||||
width,
|
|
||||||
height,
|
|
||||||
timestamp)
|
|
||||||
.Select(i => i.ToString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,10 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
{
|
{
|
||||||
_all = string.Equals(filter, "*", StringComparison.OrdinalIgnoreCase);
|
_all = string.Equals(filter, "*", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
_fields = (filter ?? string.Empty)
|
List<string> list = new List<string>();
|
||||||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
foreach (string s in (filter ?? string.Empty).Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries))
|
||||||
.ToList();
|
list.Add(s);
|
||||||
|
_fields = list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Contains(string field)
|
public bool Contains(string field)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using System.Diagnostics;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Entities
|
namespace MediaBrowser.Model.Entities
|
||||||
{
|
{
|
||||||
@ -128,6 +130,20 @@ namespace MediaBrowser.Model.Entities
|
|||||||
/// <value><c>true</c> if this instance is external; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if this instance is external; otherwise, <c>false</c>.</value>
|
||||||
public bool IsExternal { get; set; }
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the filename.
|
/// Gets or sets the filename.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Web
|
namespace MediaBrowser.Model.Web
|
||||||
@ -24,7 +25,7 @@ namespace MediaBrowser.Model.Web
|
|||||||
/// <param name="value">The value.</param>
|
/// <param name="value">The value.</param>
|
||||||
public void Add(string name, int value)
|
public void Add(string name, int value)
|
||||||
{
|
{
|
||||||
Add(name, value.ToString());
|
Add(name, value.ToString(CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -34,7 +35,7 @@ namespace MediaBrowser.Model.Web
|
|||||||
/// <param name="value">The value.</param>
|
/// <param name="value">The value.</param>
|
||||||
public void Add(string name, long value)
|
public void Add(string name, long value)
|
||||||
{
|
{
|
||||||
Add(name, value.ToString());
|
Add(name, value.ToString(CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -44,7 +45,7 @@ namespace MediaBrowser.Model.Web
|
|||||||
/// <param name="value">The value.</param>
|
/// <param name="value">The value.</param>
|
||||||
public void Add(string name, double value)
|
public void Add(string name, double value)
|
||||||
{
|
{
|
||||||
Add(name, value.ToString());
|
Add(name, value.ToString(CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -135,7 +136,7 @@ namespace MediaBrowser.Model.Web
|
|||||||
throw new ArgumentNullException("value");
|
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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -188,7 +189,7 @@ namespace MediaBrowser.Model.Web
|
|||||||
/// <param name="name">The name.</param>
|
/// <param name="name">The name.</param>
|
||||||
/// <param name="value">The value.</param>
|
/// <param name="value">The value.</param>
|
||||||
/// <param name="delimiter">The delimiter.</param>
|
/// <param name="delimiter">The delimiter.</param>
|
||||||
/// <exception cref="System.ArgumentNullException">value</exception>
|
/// <exception cref="ArgumentNullException">value</exception>
|
||||||
public void Add(string name, IEnumerable<string> value, string delimiter)
|
public void Add(string name, IEnumerable<string> value, string delimiter)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MediaBrowser.Common.Events;
|
using System.Globalization;
|
||||||
|
using MediaBrowser.Common.Events;
|
||||||
using MediaBrowser.Common.Plugins;
|
using MediaBrowser.Common.Plugins;
|
||||||
using MediaBrowser.Common.ScheduledTasks;
|
using MediaBrowser.Common.ScheduledTasks;
|
||||||
using MediaBrowser.Common.Updates;
|
using MediaBrowser.Common.Updates;
|
||||||
@ -247,10 +248,10 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
|
|||||||
DisposeLibraryUpdateTimer();
|
DisposeLibraryUpdateTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
var item = items.FirstOrDefault();
|
if (items.Count == 1)
|
||||||
|
|
||||||
if (item != null)
|
|
||||||
{
|
{
|
||||||
|
var item = items.First();
|
||||||
|
|
||||||
var notification = new NotificationRequest
|
var notification = new NotificationRequest
|
||||||
{
|
{
|
||||||
NotificationType = NotificationType.NewLibraryContent.ToString()
|
NotificationType = NotificationType.NewLibraryContent.ToString()
|
||||||
@ -258,10 +259,16 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
|
|||||||
|
|
||||||
notification.Variables["Name"] = item.Name;
|
notification.Variables["Name"] = item.Name;
|
||||||
|
|
||||||
if (items.Count > 1)
|
await SendNotification(notification).ConfigureAwait(false);
|
||||||
{
|
|
||||||
notification.Name = items.Count + " new library items.";
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var notification = new NotificationRequest
|
||||||
|
{
|
||||||
|
NotificationType = NotificationType.NewLibraryContentMultiple.ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
notification.Variables["ItemCount"] = items.Count.ToString(CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
await SendNotification(notification).ConfigureAwait(false);
|
await SendNotification(notification).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -568,6 +568,7 @@
|
|||||||
"NotificationOptionTaskFailed": "Scheduled task failure",
|
"NotificationOptionTaskFailed": "Scheduled task failure",
|
||||||
"NotificationOptionInstallationFailed": "Installation failure",
|
"NotificationOptionInstallationFailed": "Installation failure",
|
||||||
"NotificationOptionNewLibraryContent": "New content added",
|
"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.",
|
"SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
|
||||||
"NotificationOptionServerRestartRequired": "Server restart required",
|
"NotificationOptionServerRestartRequired": "Server restart required",
|
||||||
"LabelNotificationEnabled": "Enable this notification",
|
"LabelNotificationEnabled": "Enable this notification",
|
||||||
@ -716,5 +717,9 @@
|
|||||||
"LabelDownloadLanguages": "Download languages:",
|
"LabelDownloadLanguages": "Download languages:",
|
||||||
"ButtonRegister": "Register",
|
"ButtonRegister": "Register",
|
||||||
"LabelSkipIfAudioTrackPresent": "Skip if the default audio track matches the download language",
|
"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:"
|
||||||
}
|
}
|
@ -90,6 +90,13 @@ namespace MediaBrowser.Server.Implementations.Notifications
|
|||||||
Variables = new List<string>{"Name"}
|
Variables = new List<string>{"Name"}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
new NotificationTypeInfo
|
||||||
|
{
|
||||||
|
Type = NotificationType.NewLibraryContentMultiple.ToString(),
|
||||||
|
DefaultTitle = "{ItemCount} new items have been added to your media library.",
|
||||||
|
Variables = new List<string>{"ItemCount"}
|
||||||
|
},
|
||||||
|
|
||||||
new NotificationTypeInfo
|
new NotificationTypeInfo
|
||||||
{
|
{
|
||||||
Type = NotificationType.AudioPlayback.ToString(),
|
Type = NotificationType.AudioPlayback.ToString(),
|
||||||
|
@ -440,6 +440,187 @@ namespace OpenSubtitlesHandler
|
|||||||
}
|
}
|
||||||
return new MethodResponseError("Fail", "Search Subtitles call failed !");
|
return new MethodResponseError("Fail", "Search Subtitles call failed !");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<IMethodResponse> 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<IXmlRpcValue> parms = new List<IXmlRpcValue>();
|
||||||
|
// 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<XmlRpcStructMember>());
|
||||||
|
// 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 !");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Download subtitle file(s)
|
/// Download subtitle file(s)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user