Merge branch 'beta'
This commit is contained in:
commit
2d49ec4a53
|
@ -10,6 +10,7 @@ namespace MediaBrowser.Api
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Branding/Css", "GET", Summary = "Gets custom css")]
|
[Route("/Branding/Css", "GET", Summary = "Gets custom css")]
|
||||||
|
[Route("/Branding/Css.css", "GET", Summary = "Gets custom css")]
|
||||||
public class GetBrandingCss
|
public class GetBrandingCss
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,6 +247,12 @@ namespace MediaBrowser.Api
|
||||||
hasBudget.Revenue = request.Revenue;
|
hasBudget.Revenue = request.Revenue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hasOriginalTitle = item as IHasOriginalTitle;
|
||||||
|
if (hasOriginalTitle != null)
|
||||||
|
{
|
||||||
|
hasOriginalTitle.OriginalTitle = hasOriginalTitle.OriginalTitle;
|
||||||
|
}
|
||||||
|
|
||||||
var hasCriticRating = item as IHasCriticRating;
|
var hasCriticRating = item as IHasCriticRating;
|
||||||
if (hasCriticRating != null)
|
if (hasCriticRating != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -289,7 +289,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
|
||||||
return "h264_qsv";
|
return "h264_qsv";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -821,9 +821,14 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected string GetVideoDecoder(StreamState state)
|
protected string GetVideoDecoder(StreamState state)
|
||||||
{
|
{
|
||||||
if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
|
||||||
|
{
|
||||||
|
if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
switch (state.MediaSource.VideoStream.Codec.ToLower())
|
switch (state.MediaSource.VideoStream.Codec.ToLower())
|
||||||
{
|
{
|
||||||
|
@ -831,7 +836,8 @@ namespace MediaBrowser.Api.Playback
|
||||||
case "h264":
|
case "h264":
|
||||||
if (MediaEncoder.SupportsDecoder("h264_qsv"))
|
if (MediaEncoder.SupportsDecoder("h264_qsv"))
|
||||||
{
|
{
|
||||||
return "-c:v h264_qsv ";
|
// Seeing stalls and failures with decoding. Not worth it compared to encoding.
|
||||||
|
//return "-c:v h264_qsv ";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "mpeg2video":
|
case "mpeg2video":
|
||||||
|
@ -1033,7 +1039,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
process.BeginOutputReadLine();
|
process.BeginOutputReadLine();
|
||||||
|
|
||||||
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
|
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
|
||||||
StartStreamingLog(transcodingJob, state, process.StandardError.BaseStream, state.LogFileStream);
|
Task.Run(() => StartStreamingLog(transcodingJob, state, process.StandardError.BaseStream, state.LogFileStream));
|
||||||
|
|
||||||
// Wait for the file to exist before proceeeding
|
// Wait for the file to exist before proceeeding
|
||||||
while (!FileSystem.FileExists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)
|
while (!FileSystem.FileExists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)
|
||||||
|
@ -1076,7 +1082,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void StartStreamingLog(TranscodingJob transcodingJob, StreamState state, Stream source, Stream target)
|
private async Task StartStreamingLog(TranscodingJob transcodingJob, StreamState state, Stream source, Stream target)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -1804,6 +1810,15 @@ namespace MediaBrowser.Api.Playback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.Equals("h264", videoStream.Codec, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (videoStream.IsAVC.HasValue && !videoStream.IsAVC.Value)
|
||||||
|
{
|
||||||
|
Logger.Debug("Cannot stream copy video. Stream is marked as not AVC");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Source and target codecs must match
|
// Source and target codecs must match
|
||||||
if (!string.Equals(request.VideoCodec, videoStream.Codec, StringComparison.OrdinalIgnoreCase))
|
if (!string.Equals(request.VideoCodec, videoStream.Codec, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
@ -2222,9 +2237,10 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
if (state.VideoRequest != null)
|
if (state.VideoRequest != null)
|
||||||
{
|
{
|
||||||
|
// Important: If this is ever re-enabled, make sure not to use it with wtv because it breaks seeking
|
||||||
if (string.Equals(state.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase) && state.VideoRequest.CopyTimestamps)
|
if (string.Equals(state.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase) && state.VideoRequest.CopyTimestamps)
|
||||||
{
|
{
|
||||||
inputModifier += " -noaccurate_seek";
|
//inputModifier += " -noaccurate_seek";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -289,17 +289,5 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
return isLiveStream;
|
return isLiveStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool CanStreamCopyAudio(StreamState state, List<string> supportedAudioCodecs)
|
|
||||||
{
|
|
||||||
var isLiveStream = IsLiveStream(state);
|
|
||||||
|
|
||||||
if (!isLiveStream)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.CanStreamCopyAudio(state, supportedAudioCodecs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -500,18 +500,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
|
return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsLiveStream(StreamState state)
|
|
||||||
{
|
|
||||||
var isLiveStream = (state.RunTimeTicks ?? 0) == 0;
|
|
||||||
|
|
||||||
if (state.VideoRequest.ForceLiveStream)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isLiveStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetMasterPlaylistFileText(StreamState state, int totalBitrate)
|
private string GetMasterPlaylistFileText(StreamState state, int totalBitrate)
|
||||||
{
|
{
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
|
@ -830,11 +818,10 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
{
|
{
|
||||||
if (state.VideoStream != null && IsH264(state.VideoStream) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
if (state.VideoStream != null && IsH264(state.VideoStream) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
Logger.Debug("Enabling h264_mp4toannexb due to nal_length_size of {0}", state.VideoStream.NalLengthSize);
|
|
||||||
args += " -bsf:v h264_mp4toannexb";
|
args += " -bsf:v h264_mp4toannexb";
|
||||||
}
|
}
|
||||||
|
|
||||||
args += " -flags -global_header -sc_threshold 0";
|
args += " -flags -global_header";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -859,7 +846,12 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
args += GetGraphicalSubtitleParam(state, codec);
|
args += GetGraphicalSubtitleParam(state, codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
args += " -flags -global_header -sc_threshold 0";
|
args += " -flags -global_header";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EnableCopyTs(state) && args.IndexOf("-copyts", StringComparison.OrdinalIgnoreCase) == -1)
|
||||||
|
{
|
||||||
|
args += " -copyts";
|
||||||
}
|
}
|
||||||
|
|
||||||
return args;
|
return args;
|
||||||
|
@ -867,7 +859,8 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
private bool EnableCopyTs(StreamState state)
|
private bool EnableCopyTs(StreamState state)
|
||||||
{
|
{
|
||||||
return state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode;
|
//return state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
|
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
|
||||||
|
@ -889,24 +882,28 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
var mapArgs = state.IsOutputVideo ? GetMapArgs(state) : string.Empty;
|
var mapArgs = state.IsOutputVideo ? GetMapArgs(state) : string.Empty;
|
||||||
|
|
||||||
//var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state);
|
var enableGenericSegmenter = false;
|
||||||
|
|
||||||
//return string.Format("{0} {11} {1}{10} -map_metadata -1 -threads {2} {3} {4} {5} -f segment -segment_time {6} -segment_format mpegts -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
|
if (enableGenericSegmenter)
|
||||||
// inputModifier,
|
{
|
||||||
// GetInputArgument(state),
|
var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state);
|
||||||
// threads,
|
|
||||||
// mapArgs,
|
|
||||||
// GetVideoArguments(state),
|
|
||||||
// GetAudioArguments(state),
|
|
||||||
// state.SegmentLength.ToString(UsCulture),
|
|
||||||
// startNumberParam,
|
|
||||||
// outputPath,
|
|
||||||
// outputTsArg,
|
|
||||||
// slowSeekParam,
|
|
||||||
// toTimeParam
|
|
||||||
// ).Trim();
|
|
||||||
|
|
||||||
return string.Format("{0}{11} {1} -map_metadata -1 -threads {2} {3} {4}{5} {6} -hls_time {7} -start_number {8} -hls_list_size {9} -y \"{10}\"",
|
return string.Format("{0} {10} {1} -map_metadata -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} -segment_format mpegts -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
|
||||||
|
inputModifier,
|
||||||
|
GetInputArgument(state),
|
||||||
|
threads,
|
||||||
|
mapArgs,
|
||||||
|
GetVideoArguments(state),
|
||||||
|
GetAudioArguments(state),
|
||||||
|
state.SegmentLength.ToString(UsCulture),
|
||||||
|
startNumberParam,
|
||||||
|
outputPath,
|
||||||
|
outputTsArg,
|
||||||
|
toTimeParam
|
||||||
|
).Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format("{0}{11} {1} -map_metadata -1 -threads {2} {3} {4}{5} {6} -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -hls_time {7} -start_number {8} -hls_list_size {9} -y \"{10}\"",
|
||||||
inputModifier,
|
inputModifier,
|
||||||
GetInputArgument(state),
|
GetInputArgument(state),
|
||||||
threads,
|
threads,
|
||||||
|
@ -946,10 +943,10 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
{
|
{
|
||||||
var isLiveStream = IsLiveStream(state);
|
var isLiveStream = IsLiveStream(state);
|
||||||
|
|
||||||
if (!isLiveStream)
|
//if (!isLiveStream && Request.QueryString["AllowCustomSegmenting"] != "true")
|
||||||
{
|
//{
|
||||||
return false;
|
// return false;
|
||||||
}
|
//}
|
||||||
|
|
||||||
return base.CanStreamCopyVideo(state);
|
return base.CanStreamCopyVideo(state);
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
// if h264_mp4toannexb is ever added, do not use it for live tv
|
// if h264_mp4toannexb is ever added, do not use it for live tv
|
||||||
if (state.VideoStream != null && IsH264(state.VideoStream) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
if (state.VideoStream != null && IsH264(state.VideoStream) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
Logger.Debug("Enabling h264_mp4toannexb due to nal_length_size of {0}", state.VideoStream.NalLengthSize);
|
|
||||||
args += " -bsf:v h264_mp4toannexb";
|
args += " -bsf:v h264_mp4toannexb";
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
|
|
|
@ -15,6 +15,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Playback
|
namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
|
@ -66,14 +67,16 @@ namespace MediaBrowser.Api.Playback
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
private readonly INetworkManager _networkManager;
|
private readonly INetworkManager _networkManager;
|
||||||
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
|
|
||||||
public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager, IServerConfigurationManager config, INetworkManager networkManager)
|
public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager, IServerConfigurationManager config, INetworkManager networkManager, IMediaEncoder mediaEncoder)
|
||||||
{
|
{
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_deviceManager = deviceManager;
|
_deviceManager = deviceManager;
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_config = config;
|
_config = config;
|
||||||
_networkManager = networkManager;
|
_networkManager = networkManager;
|
||||||
|
_mediaEncoder = mediaEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetBitrateTestBytes request)
|
public object Get(GetBitrateTestBytes request)
|
||||||
|
@ -241,7 +244,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
int? subtitleStreamIndex,
|
int? subtitleStreamIndex,
|
||||||
string playSessionId)
|
string playSessionId)
|
||||||
{
|
{
|
||||||
var streamBuilder = new StreamBuilder(Logger);
|
var streamBuilder = new StreamBuilder(_mediaEncoder, Logger);
|
||||||
|
|
||||||
var options = new VideoOptions
|
var options = new VideoOptions
|
||||||
{
|
{
|
||||||
|
|
|
@ -141,7 +141,6 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
{
|
{
|
||||||
if (state.VideoStream != null && IsH264(state.VideoStream) && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
if (state.VideoStream != null && IsH264(state.VideoStream) && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
Logger.Debug("Enabling h264_mp4toannexb due to nal_length_size of {0}", state.VideoStream.NalLengthSize);
|
|
||||||
args += " -bsf:v h264_mp4toannexb";
|
args += " -bsf:v h264_mp4toannexb";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,19 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
public List<string> PlayableStreamFileNames { get; set; }
|
public List<string> PlayableStreamFileNames { get; set; }
|
||||||
|
|
||||||
public int SegmentLength = 3;
|
public int SegmentLength
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int HlsListSize
|
public int HlsListSize
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
@ -54,8 +54,9 @@
|
||||||
<Reference Include="MoreLinq">
|
<Reference Include="MoreLinq">
|
||||||
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
|
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="NLog">
|
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NLog.4.2.3\lib\net45\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.4.3.1\lib\net45\NLog.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Patterns.Logging">
|
<Reference Include="Patterns.Logging">
|
||||||
<HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
|
<HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
|
||||||
|
@ -64,8 +65,9 @@
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>
|
<HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="SimpleInjector">
|
<Reference Include="SimpleInjector, Version=3.1.3.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\SimpleInjector.3.1.2\lib\net45\SimpleInjector.dll</HintPath>
|
<HintPath>..\packages\SimpleInjector.3.1.3\lib\net45\SimpleInjector.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Configuration" />
|
<Reference Include="System.Configuration" />
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<packages>
|
<packages>
|
||||||
<package id="CommonIO" version="1.0.0.9" targetFramework="net45" />
|
<package id="CommonIO" version="1.0.0.9" targetFramework="net45" />
|
||||||
<package id="morelinq" version="1.4.0" targetFramework="net45" />
|
<package id="morelinq" version="1.4.0" targetFramework="net45" />
|
||||||
<package id="NLog" version="4.2.3" targetFramework="net45" />
|
<package id="NLog" version="4.3.1" targetFramework="net45" />
|
||||||
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
|
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
|
||||||
<package id="SimpleInjector" version="3.1.2" targetFramework="net45" />
|
<package id="SimpleInjector" version="3.1.3" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
|
@ -125,6 +125,8 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string OriginalTitle { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id.
|
/// Gets or sets the id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1540,11 +1542,11 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(info.Path))
|
if (!string.IsNullOrEmpty(info.Path))
|
||||||
{
|
{
|
||||||
var itemByPath = LibraryManager.FindByPath(info.Path);
|
var itemByPath = LibraryManager.FindByPath(info.Path, null);
|
||||||
|
|
||||||
if (itemByPath == null)
|
if (itemByPath == null)
|
||||||
{
|
{
|
||||||
Logger.Warn("Unable to find linked item at path {0}", info.Path);
|
//Logger.Warn("Unable to find linked item at path {0}", info.Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return itemByPath;
|
return itemByPath;
|
||||||
|
@ -1553,6 +1555,15 @@ namespace MediaBrowser.Controller.Entities
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public virtual bool EnableRememberingTrackSelections
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a studio to the item
|
/// Adds a studio to the item
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -8,6 +8,7 @@ using System.Runtime.Serialization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CommonIO;
|
using CommonIO;
|
||||||
|
using MoreLinq;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities
|
namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
|
@ -97,7 +98,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return base.IsValidFromResolver(newItem);
|
return base.IsValidFromResolver(newItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,9 +200,30 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
public IEnumerable<Folder> GetPhysicalParents()
|
public IEnumerable<Folder> GetPhysicalParents()
|
||||||
{
|
{
|
||||||
return LibraryManager.RootFolder.Children
|
var rootChildren = LibraryManager.RootFolder.Children
|
||||||
.OfType<Folder>()
|
.OfType<Folder>()
|
||||||
.Where(i => i.Path != null && PhysicalLocations.Contains(i.Path, StringComparer.OrdinalIgnoreCase));
|
.ToList();
|
||||||
|
|
||||||
|
return PhysicalLocations.Where(i => !string.Equals(i, Path, StringComparison.OrdinalIgnoreCase)).SelectMany(i => GetPhysicalParents(i, rootChildren)).DistinctBy(i => i.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<Folder> GetPhysicalParents(string path, List<Folder> rootChildren)
|
||||||
|
{
|
||||||
|
var result = rootChildren
|
||||||
|
.Where(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (result.Count == 0)
|
||||||
|
{
|
||||||
|
var folder = LibraryManager.FindByPath(path, true) as Folder;
|
||||||
|
|
||||||
|
if (folder != null)
|
||||||
|
{
|
||||||
|
result.Add(folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
|
|
|
@ -20,5 +20,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// <param name="userData">The user data.</param>
|
/// <param name="userData">The user data.</param>
|
||||||
/// <param name="user">The user.</param>
|
/// <param name="user">The user.</param>
|
||||||
void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user);
|
void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user);
|
||||||
|
|
||||||
|
bool EnableRememberingTrackSelections { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,6 @@ namespace MediaBrowser.Controller.Entities.Movies
|
||||||
{
|
{
|
||||||
public List<Guid> SpecialFeatureIds { get; set; }
|
public List<Guid> SpecialFeatureIds { get; set; }
|
||||||
|
|
||||||
public string OriginalTitle { get; set; }
|
|
||||||
|
|
||||||
public List<Guid> ThemeSongIds { get; set; }
|
public List<Guid> ThemeSongIds { get; set; }
|
||||||
public List<Guid> ThemeVideoIds { get; set; }
|
public List<Guid> ThemeVideoIds { get; set; }
|
||||||
public List<string> ProductionLocations { get; set; }
|
public List<string> ProductionLocations { get; set; }
|
||||||
|
|
|
@ -19,8 +19,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||||
{
|
{
|
||||||
public List<Guid> SpecialFeatureIds { get; set; }
|
public List<Guid> SpecialFeatureIds { get; set; }
|
||||||
|
|
||||||
public string OriginalTitle { get; set; }
|
|
||||||
|
|
||||||
public int? AnimeSeriesIndex { get; set; }
|
public int? AnimeSeriesIndex { get; set; }
|
||||||
|
|
||||||
public Series()
|
public Series()
|
||||||
|
@ -257,7 +255,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||||
// Refresh current item
|
// Refresh current item
|
||||||
await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
// Refresh TV
|
// Refresh seasons
|
||||||
foreach (var item in seasons)
|
foreach (var item in seasons)
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
@ -270,12 +268,30 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||||
progress.Report(percent * 100);
|
progress.Report(percent * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh all non-songs
|
// Refresh episodes and other children
|
||||||
foreach (var item in otherItems)
|
foreach (var item in otherItems)
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
var skipItem = false;
|
||||||
|
|
||||||
|
var episode = item as Episode;
|
||||||
|
|
||||||
|
if (episode != null
|
||||||
|
&& refreshOptions.MetadataRefreshMode != MetadataRefreshMode.FullRefresh
|
||||||
|
&& !refreshOptions.ReplaceAllMetadata
|
||||||
|
&& episode.IsMissingEpisode
|
||||||
|
&& episode.LocationType == Model.Entities.LocationType.Virtual
|
||||||
|
&& episode.PremiereDate.HasValue
|
||||||
|
&& (DateTime.UtcNow - episode.PremiereDate.Value).TotalDays > 30)
|
||||||
|
{
|
||||||
|
skipItem = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skipItem)
|
||||||
|
{
|
||||||
|
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
numComplete++;
|
numComplete++;
|
||||||
double percent = numComplete;
|
double percent = numComplete;
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class Trailer
|
/// Class Trailer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Trailer : Video, IHasCriticRating, IHasProductionLocations, IHasBudget, IHasKeywords, IHasTaglines, IHasMetascore, IHasLookupInfo<TrailerInfo>
|
public class Trailer : Video, IHasCriticRating, IHasProductionLocations, IHasBudget, IHasKeywords, IHasTaglines, IHasMetascore, IHasOriginalTitle, IHasLookupInfo<TrailerInfo>
|
||||||
{
|
{
|
||||||
public List<string> ProductionLocations { get; set; }
|
public List<string> ProductionLocations { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -317,6 +317,11 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newAsVideo.VideoType != VideoType)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.IsValidFromResolver(newItem);
|
return base.IsValidFromResolver(newItem);
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <returns>BaseItem.</returns>
|
/// <returns>BaseItem.</returns>
|
||||||
BaseItem FindByPath(string path);
|
BaseItem FindByPath(string path, bool? isFolder);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the artist.
|
/// Gets the artist.
|
||||||
|
@ -243,6 +243,8 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// <returns>BaseItem.</returns>
|
/// <returns>BaseItem.</returns>
|
||||||
BaseItem RetrieveItem(Guid id);
|
BaseItem RetrieveItem(Guid id);
|
||||||
|
|
||||||
|
bool IsScanRunning { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when [item added].
|
/// Occurs when [item added].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The banner URL
|
/// The banner URL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly string BannerUrl = "http://www.thetvdb.com/banners/";
|
public static readonly string BannerUrl = "https://www.thetvdb.com/banners/";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the air days.
|
/// Gets the air days.
|
||||||
|
|
|
@ -46,6 +46,8 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task<List<MediaSourceInfo>>.</returns>
|
/// <returns>Task<List<MediaSourceInfo>>.</returns>
|
||||||
Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
|
Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
string ApplyDuration(string streamPath, TimeSpan duration);
|
||||||
}
|
}
|
||||||
public interface IConfigurableTunerHost
|
public interface IConfigurableTunerHost
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,6 +45,15 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
set { }
|
set { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool EnableRememberingTrackSelections
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the number.
|
/// Gets or sets the number.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -4,13 +4,14 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.MediaEncoding
|
namespace MediaBrowser.Controller.MediaEncoding
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface IMediaEncoder
|
/// Interface IMediaEncoder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IMediaEncoder
|
public interface IMediaEncoder : ITranscoderSupport
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the encoder path.
|
/// Gets the encoder path.
|
||||||
|
|
|
@ -12,6 +12,7 @@ using MediaBrowser.Model.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.ContentDirectory
|
namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
{
|
{
|
||||||
|
@ -27,6 +28,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
private readonly IChannelManager _channelManager;
|
private readonly IChannelManager _channelManager;
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
private readonly IUserViewManager _userViewManager;
|
private readonly IUserViewManager _userViewManager;
|
||||||
|
private readonly Func<IMediaEncoder> _mediaEncoder;
|
||||||
|
|
||||||
public ContentDirectory(IDlnaManager dlna,
|
public ContentDirectory(IDlnaManager dlna,
|
||||||
IUserDataManager userDataManager,
|
IUserDataManager userDataManager,
|
||||||
|
@ -35,7 +37,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
IServerConfigurationManager config,
|
IServerConfigurationManager config,
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager)
|
IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, Func<IMediaEncoder> mediaEncoder)
|
||||||
: base(logger, httpClient)
|
: base(logger, httpClient)
|
||||||
{
|
{
|
||||||
_dlna = dlna;
|
_dlna = dlna;
|
||||||
|
@ -48,6 +50,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
_channelManager = channelManager;
|
_channelManager = channelManager;
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_userViewManager = userViewManager;
|
_userViewManager = userViewManager;
|
||||||
|
_mediaEncoder = mediaEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int SystemUpdateId
|
private int SystemUpdateId
|
||||||
|
@ -89,7 +92,8 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
_localization,
|
_localization,
|
||||||
_channelManager,
|
_channelManager,
|
||||||
_mediaSourceManager,
|
_mediaSourceManager,
|
||||||
_userViewManager)
|
_userViewManager,
|
||||||
|
_mediaEncoder())
|
||||||
.ProcessControlRequest(request);
|
.ProcessControlRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.ContentDirectory
|
namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
{
|
{
|
||||||
|
@ -34,6 +35,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
private readonly User _user;
|
private readonly User _user;
|
||||||
private readonly IUserViewManager _userViewManager;
|
private readonly IUserViewManager _userViewManager;
|
||||||
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
|
|
||||||
private const string NS_DC = "http://purl.org/dc/elements/1.1/";
|
private const string NS_DC = "http://purl.org/dc/elements/1.1/";
|
||||||
private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
|
private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
|
||||||
|
@ -47,7 +49,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
|
|
||||||
private readonly DeviceProfile _profile;
|
private readonly DeviceProfile _profile;
|
||||||
|
|
||||||
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager)
|
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder)
|
||||||
: base(config, logger)
|
: base(config, logger)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
|
@ -56,10 +58,11 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
_systemUpdateId = systemUpdateId;
|
_systemUpdateId = systemUpdateId;
|
||||||
_channelManager = channelManager;
|
_channelManager = channelManager;
|
||||||
_userViewManager = userViewManager;
|
_userViewManager = userViewManager;
|
||||||
|
_mediaEncoder = mediaEncoder;
|
||||||
_profile = profile;
|
_profile = profile;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, libraryManager);
|
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, libraryManager, _mediaEncoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
|
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
|
||||||
|
|
|
@ -19,6 +19,7 @@ using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.Didl
|
namespace MediaBrowser.Dlna.Didl
|
||||||
|
@ -42,8 +43,9 @@ namespace MediaBrowser.Dlna.Didl
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
|
|
||||||
public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, ILogger logger, ILibraryManager libraryManager)
|
public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, ILogger logger, ILibraryManager libraryManager, IMediaEncoder mediaEncoder)
|
||||||
{
|
{
|
||||||
_profile = profile;
|
_profile = profile;
|
||||||
_imageProcessor = imageProcessor;
|
_imageProcessor = imageProcessor;
|
||||||
|
@ -53,6 +55,7 @@ namespace MediaBrowser.Dlna.Didl
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
|
_mediaEncoder = mediaEncoder;
|
||||||
_accessToken = accessToken;
|
_accessToken = accessToken;
|
||||||
_user = user;
|
_user = user;
|
||||||
}
|
}
|
||||||
|
@ -142,7 +145,7 @@ namespace MediaBrowser.Dlna.Didl
|
||||||
{
|
{
|
||||||
var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList();
|
var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList();
|
||||||
|
|
||||||
streamInfo = new StreamBuilder(GetStreamBuilderLogger(options)).BuildVideoItem(new VideoOptions
|
streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildVideoItem(new VideoOptions
|
||||||
{
|
{
|
||||||
ItemId = GetClientId(video),
|
ItemId = GetClientId(video),
|
||||||
MediaSources = sources,
|
MediaSources = sources,
|
||||||
|
@ -385,7 +388,7 @@ namespace MediaBrowser.Dlna.Didl
|
||||||
{
|
{
|
||||||
var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user).ToList();
|
var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user).ToList();
|
||||||
|
|
||||||
streamInfo = new StreamBuilder(GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions
|
streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions
|
||||||
{
|
{
|
||||||
ItemId = GetClientId(audio),
|
ItemId = GetClientId(audio),
|
||||||
MediaSources = sources,
|
MediaSources = sources,
|
||||||
|
|
|
@ -14,6 +14,7 @@ using MediaBrowser.Dlna.Ssdp;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.Main
|
namespace MediaBrowser.Dlna.Main
|
||||||
{
|
{
|
||||||
|
@ -34,6 +35,7 @@ namespace MediaBrowser.Dlna.Main
|
||||||
private readonly IUserDataManager _userDataManager;
|
private readonly IUserDataManager _userDataManager;
|
||||||
private readonly ILocalizationManager _localization;
|
private readonly ILocalizationManager _localization;
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
|
|
||||||
private readonly SsdpHandler _ssdpHandler;
|
private readonly SsdpHandler _ssdpHandler;
|
||||||
private readonly IDeviceDiscovery _deviceDiscovery;
|
private readonly IDeviceDiscovery _deviceDiscovery;
|
||||||
|
@ -54,7 +56,7 @@ namespace MediaBrowser.Dlna.Main
|
||||||
IUserDataManager userDataManager,
|
IUserDataManager userDataManager,
|
||||||
ILocalizationManager localization,
|
ILocalizationManager localization,
|
||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
ISsdpHandler ssdpHandler, IDeviceDiscovery deviceDiscovery)
|
ISsdpHandler ssdpHandler, IDeviceDiscovery deviceDiscovery, IMediaEncoder mediaEncoder)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_appHost = appHost;
|
_appHost = appHost;
|
||||||
|
@ -69,6 +71,7 @@ namespace MediaBrowser.Dlna.Main
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_deviceDiscovery = deviceDiscovery;
|
_deviceDiscovery = deviceDiscovery;
|
||||||
|
_mediaEncoder = mediaEncoder;
|
||||||
_ssdpHandler = (SsdpHandler)ssdpHandler;
|
_ssdpHandler = (SsdpHandler)ssdpHandler;
|
||||||
_logger = logManager.GetLogger("Dlna");
|
_logger = logManager.GetLogger("Dlna");
|
||||||
}
|
}
|
||||||
|
@ -196,7 +199,8 @@ namespace MediaBrowser.Dlna.Main
|
||||||
_config,
|
_config,
|
||||||
_userDataManager,
|
_userDataManager,
|
||||||
_localization,
|
_localization,
|
||||||
_mediaSourceManager);
|
_mediaSourceManager,
|
||||||
|
_mediaEncoder);
|
||||||
|
|
||||||
_manager.Start();
|
_manager.Start();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.PlayTo
|
namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
|
@ -35,6 +36,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
private readonly ILocalizationManager _localization;
|
private readonly ILocalizationManager _localization;
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
private readonly IConfigurationManager _config;
|
private readonly IConfigurationManager _config;
|
||||||
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
|
|
||||||
private readonly IDeviceDiscovery _deviceDiscovery;
|
private readonly IDeviceDiscovery _deviceDiscovery;
|
||||||
private readonly string _serverAddress;
|
private readonly string _serverAddress;
|
||||||
|
@ -74,7 +76,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
get { return IsSessionActive; }
|
get { return IsSessionActive; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayToController(SessionInfo session, ISessionManager sessionManager, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, string accessToken, IDeviceDiscovery deviceDiscovery, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IConfigurationManager config)
|
public PlayToController(SessionInfo session, ISessionManager sessionManager, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, string accessToken, IDeviceDiscovery deviceDiscovery, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IConfigurationManager config, IMediaEncoder mediaEncoder)
|
||||||
{
|
{
|
||||||
_session = session;
|
_session = session;
|
||||||
_sessionManager = sessionManager;
|
_sessionManager = sessionManager;
|
||||||
|
@ -88,6 +90,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
_mediaEncoder = mediaEncoder;
|
||||||
_accessToken = accessToken;
|
_accessToken = accessToken;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_creationTime = DateTime.UtcNow;
|
_creationTime = DateTime.UtcNow;
|
||||||
|
@ -478,7 +481,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
playlistItem.StreamUrl = playlistItem.StreamInfo.ToDlnaUrl(_serverAddress, _accessToken);
|
playlistItem.StreamUrl = playlistItem.StreamInfo.ToDlnaUrl(_serverAddress, _accessToken);
|
||||||
|
|
||||||
var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _libraryManager)
|
var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _libraryManager, _mediaEncoder)
|
||||||
.GetItemDidl(_config.GetDlnaConfiguration(), item, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
|
.GetItemDidl(_config.GetDlnaConfiguration(), item, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
|
||||||
|
|
||||||
playlistItem.Didl = itemXml;
|
playlistItem.Didl = itemXml;
|
||||||
|
@ -550,7 +553,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
return new PlaylistItem
|
return new PlaylistItem
|
||||||
{
|
{
|
||||||
StreamInfo = new StreamBuilder(GetStreamBuilderLogger()).BuildVideoItem(new VideoOptions
|
StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildVideoItem(new VideoOptions
|
||||||
{
|
{
|
||||||
ItemId = item.Id.ToString("N"),
|
ItemId = item.Id.ToString("N"),
|
||||||
MediaSources = mediaSources,
|
MediaSources = mediaSources,
|
||||||
|
@ -570,7 +573,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
return new PlaylistItem
|
return new PlaylistItem
|
||||||
{
|
{
|
||||||
StreamInfo = new StreamBuilder(GetStreamBuilderLogger()).BuildAudioItem(new AudioOptions
|
StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildAudioItem(new AudioOptions
|
||||||
{
|
{
|
||||||
ItemId = item.Id.ToString("N"),
|
ItemId = item.Id.ToString("N"),
|
||||||
MediaSources = mediaSources,
|
MediaSources = mediaSources,
|
||||||
|
|
|
@ -12,6 +12,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.PlayTo
|
namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
|
@ -32,11 +33,12 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
private readonly IDeviceDiscovery _deviceDiscovery;
|
private readonly IDeviceDiscovery _deviceDiscovery;
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
|
|
||||||
private readonly List<string> _nonRendererUrls = new List<string>();
|
private readonly List<string> _nonRendererUrls = new List<string>();
|
||||||
private DateTime _lastRendererClear;
|
private DateTime _lastRendererClear;
|
||||||
|
|
||||||
public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
|
public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_sessionManager = sessionManager;
|
_sessionManager = sessionManager;
|
||||||
|
@ -51,6 +53,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
_userDataManager = userDataManager;
|
_userDataManager = userDataManager;
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
|
_mediaEncoder = mediaEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
|
@ -132,7 +135,8 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
_userDataManager,
|
_userDataManager,
|
||||||
_localization,
|
_localization,
|
||||||
_mediaSourceManager,
|
_mediaSourceManager,
|
||||||
_config);
|
_config,
|
||||||
|
_mediaEncoder);
|
||||||
|
|
||||||
controller.Init(device);
|
controller.Init(device);
|
||||||
|
|
||||||
|
|
|
@ -109,30 +109,31 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
|
|
||||||
var endPoint = new IPEndPoint(localIp, 1900);
|
var endPoint = new IPEndPoint(localIp, 1900);
|
||||||
|
|
||||||
var socket = GetMulticastSocket(localIp, endPoint);
|
using (var socket = GetMulticastSocket(localIp, endPoint))
|
||||||
|
|
||||||
var receiveBuffer = new byte[64000];
|
|
||||||
|
|
||||||
CreateNotifier(localIp);
|
|
||||||
|
|
||||||
while (!_tokenSource.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
var receivedBytes = await socket.ReceiveAsync(receiveBuffer, 0, 64000);
|
var receiveBuffer = new byte[64000];
|
||||||
|
|
||||||
if (receivedBytes > 0)
|
CreateNotifier(localIp);
|
||||||
|
|
||||||
|
while (!_tokenSource.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
var args = SsdpHelper.ParseSsdpResponse(receiveBuffer);
|
var receivedBytes = await socket.ReceiveAsync(receiveBuffer, 0, 64000);
|
||||||
args.EndPoint = endPoint;
|
|
||||||
args.LocalEndPoint = new IPEndPoint(localIp, 0);
|
|
||||||
|
|
||||||
if (_ssdpHandler.IgnoreMessage(args, true))
|
if (receivedBytes > 0)
|
||||||
{
|
{
|
||||||
return;
|
var args = SsdpHelper.ParseSsdpResponse(receiveBuffer);
|
||||||
|
args.EndPoint = endPoint;
|
||||||
|
args.LocalEndPoint = new IPEndPoint(localIp, 0);
|
||||||
|
|
||||||
|
if (_ssdpHandler.IgnoreMessage(args, true))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ssdpHandler.LogMessageReceived(args, true);
|
||||||
|
|
||||||
|
TryCreateDevice(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ssdpHandler.LogMessageReceived(args, true);
|
|
||||||
|
|
||||||
TryCreateDevice(args);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ using CommonIO;
|
||||||
|
|
||||||
namespace MediaBrowser.LocalMetadata
|
namespace MediaBrowser.LocalMetadata
|
||||||
{
|
{
|
||||||
public abstract class BaseXmlProvider<T> : ILocalMetadataProvider<T>, IHasChangeMonitor, IHasOrder
|
public abstract class BaseXmlProvider<T> : ILocalMetadataProvider<T>, IHasItemChangeMonitor, IHasOrder
|
||||||
where T : IHasMetadata, new()
|
where T : IHasMetadata, new()
|
||||||
{
|
{
|
||||||
protected IFileSystem FileSystem;
|
protected IFileSystem FileSystem;
|
||||||
|
@ -56,7 +56,7 @@ namespace MediaBrowser.LocalMetadata
|
||||||
|
|
||||||
protected abstract FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService);
|
protected abstract FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService);
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
var file = GetXmlFile(new ItemInfo(item), directoryService);
|
var file = GetXmlFile(new ItemInfo(item), directoryService);
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ namespace MediaBrowser.LocalMetadata
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return file.Exists && FileSystem.GetLastWriteTimeUtc(file) > date;
|
return file.Exists && FileSystem.GetLastWriteTimeUtc(file) > item.DateLastSaved;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
|
|
|
@ -41,19 +41,36 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const string vn = " -vn";
|
|
||||||
|
|
||||||
var threads = GetNumberOfThreads(state, false);
|
var threads = GetNumberOfThreads(state, false);
|
||||||
|
|
||||||
var inputModifier = GetInputModifier(state);
|
var inputModifier = GetInputModifier(state);
|
||||||
|
|
||||||
return string.Format("{0} {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"",
|
var albumCoverInput = string.Empty;
|
||||||
|
var mapArgs = string.Empty;
|
||||||
|
var metadata = string.Empty;
|
||||||
|
var vn = string.Empty;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(state.AlbumCoverPath))
|
||||||
|
{
|
||||||
|
albumCoverInput = " -i \"" + state.AlbumCoverPath + "\"";
|
||||||
|
mapArgs = " -map 0:a -map 1:v -c:v copy";
|
||||||
|
metadata = " -metadata:s:v title=\"Album cover\" -metadata:s:v comment=\"Cover(Front)\"";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vn = " -vn";
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format("{0} {1}{6}{7} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1{8} -y \"{5}\"",
|
||||||
inputModifier,
|
inputModifier,
|
||||||
GetInputArgument(state),
|
GetInputArgument(state),
|
||||||
threads,
|
threads,
|
||||||
vn,
|
vn,
|
||||||
string.Join(" ", audioTranscodeParams.ToArray()),
|
string.Join(" ", audioTranscodeParams.ToArray()),
|
||||||
state.OutputFilePath).Trim();
|
state.OutputFilePath,
|
||||||
|
albumCoverInput,
|
||||||
|
mapArgs,
|
||||||
|
metadata).Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string GetOutputFileExtension(EncodingJob state)
|
protected override string GetOutputFileExtension(EncodingJob state)
|
||||||
|
|
|
@ -366,9 +366,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected string GetVideoDecoder(EncodingJob state)
|
protected string GetVideoDecoder(EncodingJob state)
|
||||||
{
|
{
|
||||||
if (string.Equals(GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
|
||||||
|
{
|
||||||
|
if (string.Equals(GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
switch (state.MediaSource.VideoStream.Codec.ToLower())
|
switch (state.MediaSource.VideoStream.Codec.ToLower())
|
||||||
{
|
{
|
||||||
|
@ -376,7 +381,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
case "h264":
|
case "h264":
|
||||||
if (MediaEncoder.SupportsDecoder("h264_qsv"))
|
if (MediaEncoder.SupportsDecoder("h264_qsv"))
|
||||||
{
|
{
|
||||||
return "-c:v h264_qsv ";
|
// Seeing stalls and failures with decoding. Not worth it compared to encoding.
|
||||||
|
//return "-c:v h264_qsv ";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "mpeg2video":
|
case "mpeg2video":
|
||||||
|
|
|
@ -64,6 +64,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
public long? InputFileSize { get; set; }
|
public long? InputFileSize { get; set; }
|
||||||
public string OutputAudioSync = "1";
|
public string OutputAudioSync = "1";
|
||||||
public string OutputVideoSync = "vfr";
|
public string OutputVideoSync = "vfr";
|
||||||
|
public string AlbumCoverPath { get; set; }
|
||||||
|
|
||||||
public string GetMimeType(string outputPath)
|
public string GetMimeType(string outputPath)
|
||||||
{
|
{
|
||||||
|
|
|
@ -60,6 +60,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
var primaryImage = item.GetImageInfo(ImageType.Primary, 0) ??
|
||||||
|
item.Parents.Select(i => i.GetImageInfo(ImageType.Primary, 0)).FirstOrDefault(i => i != null);
|
||||||
|
|
||||||
|
if (primaryImage != null)
|
||||||
|
{
|
||||||
|
state.AlbumCoverPath = primaryImage.Path;
|
||||||
|
}
|
||||||
|
|
||||||
var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(request.ItemId, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false);
|
var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(request.ItemId, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
|
var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
|
||||||
|
@ -575,6 +583,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.Equals("h264", videoStream.Codec, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (videoStream.IsAVC.HasValue && !videoStream.IsAVC.Value)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If client is requesting a specific video profile, it must match the source
|
// If client is requesting a specific video profile, it must match the source
|
||||||
if (!string.IsNullOrEmpty(request.Profile))
|
if (!string.IsNullOrEmpty(request.Profile))
|
||||||
{
|
{
|
||||||
|
|
|
@ -96,15 +96,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
FFMpegPath = ffMpegPath;
|
FFMpegPath = ffMpegPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<string> _encoders = new List<string>();
|
||||||
public void SetAvailableEncoders(List<string> list)
|
public void SetAvailableEncoders(List<string> list)
|
||||||
{
|
{
|
||||||
|
_encoders = list.ToList();
|
||||||
|
//_logger.Info("Supported encoders: {0}", string.Join(",", list.ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<string> _decoders = new List<string>();
|
private List<string> _decoders = new List<string>();
|
||||||
public void SetAvailableDecoders(List<string> list)
|
public void SetAvailableDecoders(List<string> list)
|
||||||
{
|
{
|
||||||
_decoders = list.ToList();
|
_decoders = list.ToList();
|
||||||
|
//_logger.Info("Supported decoders: {0}", string.Join(",", list.ToArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SupportsEncoder(string decoder)
|
||||||
|
{
|
||||||
|
return _encoders.Contains(decoder, StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SupportsDecoder(string decoder)
|
public bool SupportsDecoder(string decoder)
|
||||||
|
@ -112,6 +120,20 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
return _decoders.Contains(decoder, StringComparer.OrdinalIgnoreCase);
|
return _decoders.Contains(decoder, StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool CanEncodeToAudioCodec(string codec)
|
||||||
|
{
|
||||||
|
if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
codec = "libopus";
|
||||||
|
}
|
||||||
|
else if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
codec = "libmp3lame";
|
||||||
|
}
|
||||||
|
|
||||||
|
return SupportsEncoder(codec);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the encoder path.
|
/// Gets the encoder path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -75,7 +75,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
{
|
{
|
||||||
if (state.VideoStream != null && IsH264(state.VideoStream) && string.Equals(state.Options.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
if (state.VideoStream != null && IsH264(state.VideoStream) && string.Equals(state.Options.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
Logger.Debug("Enabling h264_mp4toannexb due to nal_length_size of {0}", state.VideoStream.NalLengthSize);
|
|
||||||
args += " -bsf:v h264_mp4toannexb";
|
args += " -bsf:v h264_mp4toannexb";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -411,6 +411,17 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
NalLengthSize = streamInfo.nal_length_size
|
NalLengthSize = streamInfo.nal_length_size
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (string.Equals(streamInfo.is_avc, "true", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(streamInfo.is_avc, "1", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
stream.IsAVC = true;
|
||||||
|
}
|
||||||
|
else if (string.Equals(streamInfo.is_avc, "false", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(streamInfo.is_avc, "0", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
stream.IsAVC = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Filter out junk
|
// Filter out junk
|
||||||
if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string) && streamInfo.codec_tag_string.IndexOf("[0]", StringComparison.OrdinalIgnoreCase) == -1)
|
if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string) && streamInfo.codec_tag_string.IndexOf("[0]", StringComparison.OrdinalIgnoreCase) == -1)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,4 +23,17 @@ namespace MediaBrowser.Model.Dlna
|
||||||
/// <returns><c>true</c> if this instance [can access URL] the specified URL; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if this instance [can access URL] the specified URL; otherwise, <c>false</c>.</returns>
|
||||||
bool CanAccessUrl(string url, bool requiresCustomRequestHeaders);
|
bool CanAccessUrl(string url, bool requiresCustomRequestHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface ITranscoderSupport
|
||||||
|
{
|
||||||
|
bool CanEncodeToAudioCodec(string codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FullTranscoderSupport : ITranscoderSupport
|
||||||
|
{
|
||||||
|
public bool CanEncodeToAudioCodec(string codec)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,15 +13,27 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
private readonly ILocalPlayer _localPlayer;
|
private readonly ILocalPlayer _localPlayer;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
private readonly ITranscoderSupport _transcoderSupport;
|
||||||
|
|
||||||
public StreamBuilder(ILocalPlayer localPlayer, ILogger logger)
|
public StreamBuilder(ILocalPlayer localPlayer, ITranscoderSupport transcoderSupport, ILogger logger)
|
||||||
{
|
{
|
||||||
|
_transcoderSupport = transcoderSupport;
|
||||||
_localPlayer = localPlayer;
|
_localPlayer = localPlayer;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StreamBuilder(ITranscoderSupport transcoderSupport, ILogger logger)
|
||||||
|
: this(new NullLocalPlayer(), transcoderSupport, logger)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamBuilder(ILocalPlayer localPlayer, ILogger logger)
|
||||||
|
: this(localPlayer, new FullTranscoderSupport(), logger)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public StreamBuilder(ILogger logger)
|
public StreamBuilder(ILogger logger)
|
||||||
: this(new NullLocalPlayer(), logger)
|
: this(new NullLocalPlayer(), new FullTranscoderSupport(), logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,8 +197,11 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
if (i.Type == playlistItem.MediaType && i.Context == options.Context)
|
if (i.Type == playlistItem.MediaType && i.Context == options.Context)
|
||||||
{
|
{
|
||||||
transcodingProfile = i;
|
if (_transcoderSupport.CanEncodeToAudioCodec(i.AudioCodec ?? i.Container))
|
||||||
break;
|
{
|
||||||
|
transcodingProfile = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1038,6 +1053,18 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check audio codec
|
||||||
|
List<string> audioCodecs = profile.GetAudioCodecs();
|
||||||
|
if (audioCodecs.Count > 0)
|
||||||
|
{
|
||||||
|
// Check audio codecs
|
||||||
|
string audioCodec = audioStream == null ? null : audioStream.Codec;
|
||||||
|
if (string.IsNullOrEmpty(audioCodec) || !ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1073,6 +1100,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check audio codec
|
||||||
List<string> audioCodecs = profile.GetAudioCodecs();
|
List<string> audioCodecs = profile.GetAudioCodecs();
|
||||||
if (audioCodecs.Count > 0)
|
if (audioCodecs.Count > 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,8 @@ namespace MediaBrowser.Model.Dto
|
||||||
/// <value>The name.</value>
|
/// <value>The name.</value>
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string OriginalTitle { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the server identifier.
|
/// Gets or sets the server identifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -42,6 +42,8 @@ namespace MediaBrowser.Model.Entities
|
||||||
/// <value><c>true</c> if this instance is interlaced; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if this instance is interlaced; otherwise, <c>false</c>.</value>
|
||||||
public bool IsInterlaced { get; set; }
|
public bool IsInterlaced { get; set; }
|
||||||
|
|
||||||
|
public bool? IsAVC { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the channel layout.
|
/// Gets or sets the channel layout.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace MediaBrowser.Model.LiveTv
|
||||||
public string RecordingPath { get; set; }
|
public string RecordingPath { get; set; }
|
||||||
public bool EnableAutoOrganize { get; set; }
|
public bool EnableAutoOrganize { get; set; }
|
||||||
public bool EnableRecordingEncoding { get; set; }
|
public bool EnableRecordingEncoding { get; set; }
|
||||||
|
public bool EnableOriginalAudioWithEncodedRecordings { get; set; }
|
||||||
|
|
||||||
public List<TunerHostInfo> TunerHosts { get; set; }
|
public List<TunerHostInfo> TunerHosts { get; set; }
|
||||||
public List<ListingsProviderInfo> ListingProviders { get; set; }
|
public List<ListingsProviderInfo> ListingProviders { get; set; }
|
||||||
|
|
|
@ -130,6 +130,8 @@
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Metascore,
|
Metascore,
|
||||||
|
|
||||||
|
OriginalTitle,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The item overview
|
/// The item overview
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -102,6 +102,8 @@ namespace MediaBrowser.Model.Sync
|
||||||
/// <value>The index of the job item.</value>
|
/// <value>The index of the job item.</value>
|
||||||
public int JobItemIndex { get; set; }
|
public int JobItemIndex { get; set; }
|
||||||
|
|
||||||
|
public long ItemDateModifiedTicks { get; set; }
|
||||||
|
|
||||||
public SyncJobItem()
|
public SyncJobItem()
|
||||||
{
|
{
|
||||||
AdditionalFiles = new List<ItemFileInfo>();
|
AdditionalFiles = new List<ItemFileInfo>();
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace MediaBrowser.Providers.BoxSets
|
||||||
{
|
{
|
||||||
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
|
||||||
|
|
||||||
return GetImages(mainResult, language, tmdbImageUrl);
|
return GetImages(mainResult, language, tmdbImageUrl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace MediaBrowser.Providers.BoxSets
|
||||||
{
|
{
|
||||||
public class MovieDbBoxSetProvider : IRemoteMetadataProvider<BoxSet, BoxSetInfo>
|
public class MovieDbBoxSetProvider : IRemoteMetadataProvider<BoxSet, BoxSetInfo>
|
||||||
{
|
{
|
||||||
private const string GetCollectionInfo3 = @"http://api.themoviedb.org/3/collection/{0}?api_key={1}&append_to_response=images";
|
private const string GetCollectionInfo3 = @"https://api.themoviedb.org/3/collection/{0}?api_key={1}&append_to_response=images";
|
||||||
|
|
||||||
internal static MovieDbBoxSetProvider Current;
|
internal static MovieDbBoxSetProvider Current;
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ namespace MediaBrowser.Providers.BoxSets
|
||||||
|
|
||||||
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
|
||||||
|
|
||||||
var result = new RemoteSearchResult
|
var result = new RemoteSearchResult
|
||||||
{
|
{
|
||||||
|
|
|
@ -295,7 +295,12 @@ namespace MediaBrowser.Providers.Manager
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item is BoxSet || item is IItemByName || item is Playlist)
|
if (!(item is Audio) && !(item is Video))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item is IItemByName)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -305,16 +310,6 @@ namespace MediaBrowser.Providers.Manager
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item is ICollectionFolder)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(item is Audio) && !(item is Video))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,18 +430,18 @@ namespace MediaBrowser.Providers.Manager
|
||||||
var providersWithChanges = providers
|
var providersWithChanges = providers
|
||||||
.Where(i =>
|
.Where(i =>
|
||||||
{
|
{
|
||||||
var hasChangeMonitor = i as IHasChangeMonitor;
|
|
||||||
if (hasChangeMonitor != null)
|
|
||||||
{
|
|
||||||
return HasChanged(item, hasChangeMonitor, currentItem.DateLastSaved, options.DirectoryService);
|
|
||||||
}
|
|
||||||
|
|
||||||
var hasFileChangeMonitor = i as IHasItemChangeMonitor;
|
var hasFileChangeMonitor = i as IHasItemChangeMonitor;
|
||||||
if (hasFileChangeMonitor != null)
|
if (hasFileChangeMonitor != null)
|
||||||
{
|
{
|
||||||
return HasChanged(item, hasFileChangeMonitor, options.DirectoryService);
|
return HasChanged(item, hasFileChangeMonitor, options.DirectoryService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hasChangeMonitor = i as IHasChangeMonitor;
|
||||||
|
if (hasChangeMonitor != null)
|
||||||
|
{
|
||||||
|
return HasChanged(item, hasChangeMonitor, currentItem.DateLastSaved, options.DirectoryService);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
|
@ -40,6 +40,15 @@ namespace MediaBrowser.Providers.Manager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (replaceData || string.IsNullOrEmpty(target.OriginalTitle))
|
||||||
|
{
|
||||||
|
// Safeguard against incoming data having an emtpy name
|
||||||
|
if (!string.IsNullOrWhiteSpace(source.OriginalTitle))
|
||||||
|
{
|
||||||
|
target.OriginalTitle = source.OriginalTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (replaceData || !target.CommunityRating.HasValue)
|
if (replaceData || !target.CommunityRating.HasValue)
|
||||||
{
|
{
|
||||||
target.CommunityRating = source.CommunityRating;
|
target.CommunityRating = source.CommunityRating;
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
{
|
{
|
||||||
class FanartMovieUpdatesPostScanTask : ILibraryPostScanTask
|
class FanartMovieUpdatesPostScanTask : ILibraryPostScanTask
|
||||||
{
|
{
|
||||||
private const string UpdatesUrl = "http://webservice.fanart.tv/v3/movies/latest?api_key={0}&date={1}";
|
private const string UpdatesUrl = "https://webservice.fanart.tv/v3/movies/latest?api_key={0}&date={1}";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _HTTP client
|
/// The _HTTP client
|
||||||
|
|
|
@ -16,6 +16,7 @@ using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CommonIO;
|
using CommonIO;
|
||||||
|
@ -23,7 +24,7 @@ using MediaBrowser.Providers.TV;
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.Movies
|
namespace MediaBrowser.Providers.Movies
|
||||||
{
|
{
|
||||||
public class FanartMovieImageProvider : IRemoteImageProvider, IHasChangeMonitor, IHasOrder
|
public class FanartMovieImageProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder
|
||||||
{
|
{
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
|
@ -31,7 +32,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IJsonSerializer _json;
|
private readonly IJsonSerializer _json;
|
||||||
|
|
||||||
private const string FanArtBaseUrl = "http://webservice.fanart.tv/v3/movies/{1}?api_key={0}";
|
private const string FanArtBaseUrl = "https://webservice.fanart.tv/v3/movies/{1}?api_key={0}";
|
||||||
// &client_key=52c813aa7b8c8b3bb87f4797532a2f8c
|
// &client_key=52c813aa7b8c8b3bb87f4797532a2f8c
|
||||||
|
|
||||||
internal static FanartMovieImageProvider Current;
|
internal static FanartMovieImageProvider Current;
|
||||||
|
@ -185,6 +186,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
PopulateImages(list, obj.moviebackground, ImageType.Backdrop, 1920, 1080);
|
PopulateImages(list, obj.moviebackground, ImageType.Backdrop, 1920, 1080);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Regex _regex_http = new Regex("^http://");
|
||||||
private void PopulateImages(List<RemoteImageInfo> list, List<Image> images, ImageType type, int width, int height)
|
private void PopulateImages(List<RemoteImageInfo> list, List<Image> images, ImageType type, int width, int height)
|
||||||
{
|
{
|
||||||
if (images == null)
|
if (images == null)
|
||||||
|
@ -208,7 +210,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
Width = width,
|
Width = width,
|
||||||
Height = height,
|
Height = height,
|
||||||
ProviderName = Name,
|
ProviderName = Name,
|
||||||
Url = url,
|
Url = _regex_http.Replace(url, "https://", 1),
|
||||||
Language = i.lang
|
Language = i.lang
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -239,7 +241,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
var options = FanartSeriesProvider.Current.GetFanartOptions();
|
var options = FanartSeriesProvider.Current.GetFanartOptions();
|
||||||
if (!options.EnableAutomaticUpdates)
|
if (!options.EnableAutomaticUpdates)
|
||||||
|
@ -260,7 +262,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
|
|
||||||
var fileInfo = _fileSystem.GetFileInfo(path);
|
var fileInfo = _fileSystem.GetFileInfo(path);
|
||||||
|
|
||||||
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
|
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -249,7 +249,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
}
|
}
|
||||||
|
|
||||||
resultItem.ResetPeople();
|
resultItem.ResetPeople();
|
||||||
var tmdbImageUrl = settings.images.base_url + "original";
|
var tmdbImageUrl = settings.images.secure_base_url + "original";
|
||||||
|
|
||||||
//Actors, Directors, Writers - all in People
|
//Actors, Directors, Writers - all in People
|
||||||
//actors come from cast
|
//actors come from cast
|
||||||
|
@ -329,7 +329,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
{
|
{
|
||||||
hasTrailers.RemoteTrailers = movieData.trailers.youtube.Select(i => new MediaUrl
|
hasTrailers.RemoteTrailers = movieData.trailers.youtube.Select(i => new MediaUrl
|
||||||
{
|
{
|
||||||
Url = string.Format("http://www.youtube.com/watch?v={0}", i.source),
|
Url = string.Format("https://www.youtube.com/watch?v={0}", i.source),
|
||||||
Name = i.name,
|
Name = i.name,
|
||||||
VideoSize = string.Equals("hd", i.size, StringComparison.OrdinalIgnoreCase) ? VideoSize.HighDefinition : VideoSize.StandardDefinition
|
VideoSize = string.Equals("hd", i.size, StringComparison.OrdinalIgnoreCase) ? VideoSize.HighDefinition : VideoSize.StandardDefinition
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.Movies
|
namespace MediaBrowser.Providers.Movies
|
||||||
{
|
{
|
||||||
class MovieDbImageProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor
|
class MovieDbImageProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
|
||||||
{
|
{
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
|
@ -72,7 +72,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
|
|
||||||
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
|
||||||
|
|
||||||
var supportedImages = GetSupportedImages(item).ToList();
|
var supportedImages = GetSupportedImages(item).ToList();
|
||||||
|
|
||||||
|
@ -222,9 +222,9 @@ namespace MediaBrowser.Providers.Movies
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
return MovieDbProvider.Current.HasChanged(item, date);
|
return MovieDbProvider.Current.HasChanged(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
|
|
||||||
var tmdbSettings = await GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
var tmdbSettings = await GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
|
||||||
|
|
||||||
var remoteResult = new RemoteSearchResult
|
var remoteResult = new RemoteSearchResult
|
||||||
{
|
{
|
||||||
|
@ -172,8 +172,8 @@ namespace MediaBrowser.Providers.Movies
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private const string TmdbConfigUrl = "http://api.themoviedb.org/3/configuration?api_key={0}";
|
private const string TmdbConfigUrl = "https://api.themoviedb.org/3/configuration?api_key={0}";
|
||||||
private const string GetMovieInfo3 = @"http://api.themoviedb.org/3/movie/{0}?api_key={1}&append_to_response=casts,releases,images,keywords,trailers";
|
private const string GetMovieInfo3 = @"https://api.themoviedb.org/3/movie/{0}?api_key={1}&append_to_response=casts,releases,images,keywords,trailers";
|
||||||
|
|
||||||
internal static string ApiKey = "f6bd687ffa63cd282b6ff2c6877f2669";
|
internal static string ApiKey = "f6bd687ffa63cd282b6ff2c6877f2669";
|
||||||
internal static string AcceptHeader = "application/json,image/*";
|
internal static string AcceptHeader = "application/json,image/*";
|
||||||
|
@ -281,7 +281,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
public static string NormalizeLanguage(string language)
|
public static string NormalizeLanguage(string language)
|
||||||
{
|
{
|
||||||
// They require this to be uppercase
|
// They require this to be uppercase
|
||||||
// http://emby.media/community/index.php?/topic/32454-fr-follow-tmdbs-new-language-api-update/?p=311148
|
// https://emby.media/community/index.php?/topic/32454-fr-follow-tmdbs-new-language-api-update/?p=311148
|
||||||
var parts = language.Split('-');
|
var parts = language.Split('-');
|
||||||
|
|
||||||
if (parts.Length == 2)
|
if (parts.Length == 2)
|
||||||
|
@ -414,7 +414,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
return _configurationManager.GetConfiguration<TheMovieDbOptions>("themoviedb");
|
return _configurationManager.GetConfiguration<TheMovieDbOptions>("themoviedb");
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, DateTime date)
|
public bool HasChanged(IHasMetadata item)
|
||||||
{
|
{
|
||||||
if (!GetTheMovieDbOptions().EnableAutomaticUpdates)
|
if (!GetTheMovieDbOptions().EnableAutomaticUpdates)
|
||||||
{
|
{
|
||||||
|
@ -430,7 +430,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
|
|
||||||
var fileInfo = _fileSystem.GetFileInfo(dataFilePath);
|
var fileInfo = _fileSystem.GetFileInfo(dataFilePath);
|
||||||
|
|
||||||
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
|
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
public class MovieDbSearch
|
public class MovieDbSearch
|
||||||
{
|
{
|
||||||
private static readonly CultureInfo EnUs = new CultureInfo("en-US");
|
private static readonly CultureInfo EnUs = new CultureInfo("en-US");
|
||||||
private const string Search3 = @"http://api.themoviedb.org/3/search/{3}?api_key={1}&query={0}&language={2}";
|
private const string Search3 = @"https://api.themoviedb.org/3/search/{3}?api_key={1}&query={0}&language={2}";
|
||||||
|
|
||||||
internal static string ApiKey = "f6bd687ffa63cd282b6ff2c6877f2669";
|
internal static string ApiKey = "f6bd687ffa63cd282b6ff2c6877f2669";
|
||||||
internal static string AcceptHeader = "application/json,image/*";
|
internal static string AcceptHeader = "application/json,image/*";
|
||||||
|
@ -56,7 +56,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
|
|
||||||
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(name))
|
if (!string.IsNullOrWhiteSpace(name))
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,9 +33,9 @@ namespace MediaBrowser.Providers.Movies
|
||||||
get { return MovieDbProvider.Current.Name; }
|
get { return MovieDbProvider.Current.Name; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
return MovieDbProvider.Current.HasChanged(item, date);
|
return MovieDbProvider.Current.HasChanged(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Order
|
public int Order
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
|
|
||||||
public string UrlFormatString
|
public string UrlFormatString
|
||||||
{
|
{
|
||||||
get { return "http://www.themoviedb.org/movie/{0}"; }
|
get { return "https://www.themoviedb.org/movie/{0}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
|
@ -51,7 +51,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
|
|
||||||
public string UrlFormatString
|
public string UrlFormatString
|
||||||
{
|
{
|
||||||
get { return "http://www.themoviedb.org/tv/{0}"; }
|
get { return "https://www.themoviedb.org/tv/{0}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
|
@ -74,7 +74,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
|
|
||||||
public string UrlFormatString
|
public string UrlFormatString
|
||||||
{
|
{
|
||||||
get { return "http://www.themoviedb.org/collection/{0}"; }
|
get { return "https://www.themoviedb.org/collection/{0}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
|
@ -97,7 +97,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
|
|
||||||
public string UrlFormatString
|
public string UrlFormatString
|
||||||
{
|
{
|
||||||
get { return "http://www.themoviedb.org/person/{0}"; }
|
get { return "https://www.themoviedb.org/person/{0}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
|
@ -120,7 +120,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
|
|
||||||
public string UrlFormatString
|
public string UrlFormatString
|
||||||
{
|
{
|
||||||
get { return "http://www.themoviedb.org/collection/{0}"; }
|
get { return "https://www.themoviedb.org/collection/{0}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The updates URL
|
/// The updates URL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const string UpdatesUrl = "http://api.themoviedb.org/3/movie/changes?start_date={0}&api_key={1}&page={2}";
|
private const string UpdatesUrl = "https://api.themoviedb.org/3/movie/changes?start_date={0}&api_key={1}&page={2}";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _HTTP client
|
/// The _HTTP client
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
internal class TmdbImageSettings
|
internal class TmdbImageSettings
|
||||||
{
|
{
|
||||||
public List<string> backdrop_sizes { get; set; }
|
public List<string> backdrop_sizes { get; set; }
|
||||||
public string base_url { get; set; }
|
public string secure_base_url { get; set; }
|
||||||
public List<string> poster_sizes { get; set; }
|
public List<string> poster_sizes { get; set; }
|
||||||
public List<string> profile_sizes { get; set; }
|
public List<string> profile_sizes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ using MediaBrowser.Model.Serialization;
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.Music
|
namespace MediaBrowser.Providers.Music
|
||||||
{
|
{
|
||||||
public class FanartAlbumProvider : IRemoteImageProvider, IHasChangeMonitor, IHasOrder
|
public class FanartAlbumProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder
|
||||||
{
|
{
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
|
@ -213,7 +213,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
var options = FanartSeriesProvider.Current.GetFanartOptions();
|
var options = FanartSeriesProvider.Current.GetFanartOptions();
|
||||||
if (!options.EnableAutomaticUpdates)
|
if (!options.EnableAutomaticUpdates)
|
||||||
|
@ -235,7 +235,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
|
|
||||||
var fileInfo = _fileSystem.GetFileInfo(artistJsonPath);
|
var fileInfo = _fileSystem.GetFileInfo(artistJsonPath);
|
||||||
|
|
||||||
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
|
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,11 @@ using MediaBrowser.Model.Serialization;
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.Music
|
namespace MediaBrowser.Providers.Music
|
||||||
{
|
{
|
||||||
public class FanartArtistProvider : IRemoteImageProvider, IHasChangeMonitor, IHasOrder
|
public class FanartArtistProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder
|
||||||
{
|
{
|
||||||
internal readonly SemaphoreSlim FanArtResourcePool = new SemaphoreSlim(3, 3);
|
internal readonly SemaphoreSlim FanArtResourcePool = new SemaphoreSlim(3, 3);
|
||||||
internal const string ApiKey = "5c6b04c68e904cfed1e6cbc9a9e683d4";
|
internal const string ApiKey = "5c6b04c68e904cfed1e6cbc9a9e683d4";
|
||||||
private const string FanArtBaseUrl = "http://webservice.fanart.tv/v3.1/music/{1}?api_key={0}";
|
private const string FanArtBaseUrl = "https://webservice.fanart.tv/v3.1/music/{1}?api_key={0}";
|
||||||
|
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
|
@ -207,7 +207,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
var options = FanartSeriesProvider.Current.GetFanartOptions();
|
var options = FanartSeriesProvider.Current.GetFanartOptions();
|
||||||
if (!options.EnableAutomaticUpdates)
|
if (!options.EnableAutomaticUpdates)
|
||||||
|
@ -224,7 +224,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
|
|
||||||
var fileInfo = _fileSystem.GetFileInfo(artistJsonPath);
|
var fileInfo = _fileSystem.GetFileInfo(artistJsonPath);
|
||||||
|
|
||||||
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
|
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
{
|
{
|
||||||
class FanartUpdatesPostScanTask : ILibraryPostScanTask
|
class FanartUpdatesPostScanTask : ILibraryPostScanTask
|
||||||
{
|
{
|
||||||
private const string UpdatesUrl = "http://api.fanart.tv/webservice/newmusic/{0}/{1}/";
|
private const string UpdatesUrl = "https://api.fanart.tv/webservice/newmusic/{0}/{1}/";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _HTTP client
|
/// The _HTTP client
|
||||||
|
|
|
@ -27,9 +27,9 @@ namespace MediaBrowser.Providers.Music
|
||||||
get { return MovieDbProvider.Current.Name; }
|
get { return MovieDbProvider.Current.Name; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
return MovieDbProvider.Current.HasChanged(item, date);
|
return MovieDbProvider.Current.HasChanged(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(releaseId))
|
if (!string.IsNullOrEmpty(releaseId))
|
||||||
{
|
{
|
||||||
url = string.Format("http://www.musicbrainz.org/ws/2/release/?query=reid:{0}", releaseId);
|
url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=reid:{0}", releaseId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -50,7 +50,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(artistMusicBrainzId))
|
if (!string.IsNullOrWhiteSpace(artistMusicBrainzId))
|
||||||
{
|
{
|
||||||
url = string.Format("http://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND arid:{1}",
|
url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND arid:{1}",
|
||||||
WebUtility.UrlEncode(searchInfo.Name),
|
WebUtility.UrlEncode(searchInfo.Name),
|
||||||
artistMusicBrainzId);
|
artistMusicBrainzId);
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
{
|
{
|
||||||
isNameSearch = true;
|
isNameSearch = true;
|
||||||
|
|
||||||
url = string.Format("http://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
|
url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
|
||||||
WebUtility.UrlEncode(searchInfo.Name),
|
WebUtility.UrlEncode(searchInfo.Name),
|
||||||
WebUtility.UrlEncode(searchInfo.GetAlbumArtist()));
|
WebUtility.UrlEncode(searchInfo.GetAlbumArtist()));
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
private IEnumerable<RemoteSearchResult> GetResultsFromResponse(XmlDocument doc)
|
private IEnumerable<RemoteSearchResult> GetResultsFromResponse(XmlDocument doc)
|
||||||
{
|
{
|
||||||
var ns = new XmlNamespaceManager(doc.NameTable);
|
var ns = new XmlNamespaceManager(doc.NameTable);
|
||||||
ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
|
ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#");
|
||||||
|
|
||||||
var list = new List<RemoteSearchResult>();
|
var list = new List<RemoteSearchResult>();
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
|
|
||||||
private async Task<ReleaseResult> GetReleaseResult(string albumName, string artistId, CancellationToken cancellationToken)
|
private async Task<ReleaseResult> GetReleaseResult(string albumName, string artistId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var url = string.Format("http://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND arid:{1}",
|
var url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND arid:{1}",
|
||||||
WebUtility.UrlEncode(albumName),
|
WebUtility.UrlEncode(albumName),
|
||||||
artistId);
|
artistId);
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
|
|
||||||
private async Task<ReleaseResult> GetReleaseResultByArtistName(string albumName, string artistName, CancellationToken cancellationToken)
|
private async Task<ReleaseResult> GetReleaseResultByArtistName(string albumName, string artistName, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var url = string.Format("http://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
|
var url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
|
||||||
WebUtility.UrlEncode(albumName),
|
WebUtility.UrlEncode(albumName),
|
||||||
WebUtility.UrlEncode(artistName));
|
WebUtility.UrlEncode(artistName));
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
private ReleaseResult GetReleaseResult(XmlDocument doc)
|
private ReleaseResult GetReleaseResult(XmlDocument doc)
|
||||||
{
|
{
|
||||||
var ns = new XmlNamespaceManager(doc.NameTable);
|
var ns = new XmlNamespaceManager(doc.NameTable);
|
||||||
ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
|
ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#");
|
||||||
|
|
||||||
var result = new ReleaseResult
|
var result = new ReleaseResult
|
||||||
{
|
{
|
||||||
|
@ -258,12 +258,12 @@ namespace MediaBrowser.Providers.Music
|
||||||
/// <returns>Task{System.String}.</returns>
|
/// <returns>Task{System.String}.</returns>
|
||||||
private async Task<string> GetReleaseGroupId(string releaseEntryId, CancellationToken cancellationToken)
|
private async Task<string> GetReleaseGroupId(string releaseEntryId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var url = string.Format("http://www.musicbrainz.org/ws/2/release-group/?query=reid:{0}", releaseEntryId);
|
var url = string.Format("https://www.musicbrainz.org/ws/2/release-group/?query=reid:{0}", releaseEntryId);
|
||||||
|
|
||||||
var doc = await GetMusicBrainzResponse(url, false, cancellationToken).ConfigureAwait(false);
|
var doc = await GetMusicBrainzResponse(url, false, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var ns = new XmlNamespaceManager(doc.NameTable);
|
var ns = new XmlNamespaceManager(doc.NameTable);
|
||||||
ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
|
ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#");
|
||||||
var node = doc.SelectSingleNode("//mb:release-group-list/mb:release-group/@id", ns);
|
var node = doc.SelectSingleNode("//mb:release-group-list/mb:release-group/@id", ns);
|
||||||
|
|
||||||
return node != null ? node.Value : null;
|
return node != null ? node.Value : null;
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(musicBrainzId))
|
if (!string.IsNullOrWhiteSpace(musicBrainzId))
|
||||||
{
|
{
|
||||||
var url = string.Format("http://www.musicbrainz.org/ws/2/artist/?query=arid:{0}", musicBrainzId);
|
var url = string.Format("https://www.musicbrainz.org/ws/2/artist/?query=arid:{0}", musicBrainzId);
|
||||||
|
|
||||||
var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, false, cancellationToken)
|
var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, false, cancellationToken)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
@ -35,7 +35,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
// They seem to throw bad request failures on any term with a slash
|
// They seem to throw bad request failures on any term with a slash
|
||||||
var nameToSearch = searchInfo.Name.Replace('/', ' ');
|
var nameToSearch = searchInfo.Name.Replace('/', ' ');
|
||||||
|
|
||||||
var url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch));
|
var url = String.Format("https://www.musicbrainz.org/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch));
|
||||||
|
|
||||||
var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false);
|
var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
if (HasDiacritics(searchInfo.Name))
|
if (HasDiacritics(searchInfo.Name))
|
||||||
{
|
{
|
||||||
// Try again using the search with accent characters url
|
// Try again using the search with accent characters url
|
||||||
url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));
|
url = String.Format("https://www.musicbrainz.org/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));
|
||||||
|
|
||||||
doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false);
|
doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
private IEnumerable<RemoteSearchResult> GetResultsFromResponse(XmlDocument doc)
|
private IEnumerable<RemoteSearchResult> GetResultsFromResponse(XmlDocument doc)
|
||||||
{
|
{
|
||||||
var ns = new XmlNamespaceManager(doc.NameTable);
|
var ns = new XmlNamespaceManager(doc.NameTable);
|
||||||
ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
|
ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#");
|
||||||
|
|
||||||
var list = new List<RemoteSearchResult>();
|
var list = new List<RemoteSearchResult>();
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
|
|
||||||
public string UrlFormatString
|
public string UrlFormatString
|
||||||
{
|
{
|
||||||
get { return "http://musicbrainz.org/release-group/{0}"; }
|
get { return "https://musicbrainz.org/release-group/{0}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
|
@ -41,7 +41,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
|
|
||||||
public string UrlFormatString
|
public string UrlFormatString
|
||||||
{
|
{
|
||||||
get { return "http://musicbrainz.org/artist/{0}"; }
|
get { return "https://musicbrainz.org/artist/{0}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
|
@ -64,7 +64,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
|
|
||||||
public string UrlFormatString
|
public string UrlFormatString
|
||||||
{
|
{
|
||||||
get { return "http://musicbrainz.org/release/{0}"; }
|
get { return "https://musicbrainz.org/release/{0}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
|
@ -87,7 +87,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
|
|
||||||
public string UrlFormatString
|
public string UrlFormatString
|
||||||
{
|
{
|
||||||
get { return "http://musicbrainz.org/artist/{0}"; }
|
get { return "https://musicbrainz.org/artist/{0}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
|
@ -110,7 +110,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
|
|
||||||
public string UrlFormatString
|
public string UrlFormatString
|
||||||
{
|
{
|
||||||
get { return "http://musicbrainz.org/artist/{0}"; }
|
get { return "https://musicbrainz.org/artist/{0}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
|
@ -133,7 +133,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
|
|
||||||
public string UrlFormatString
|
public string UrlFormatString
|
||||||
{
|
{
|
||||||
get { return "http://musicbrainz.org/track/{0}"; }
|
get { return "https://musicbrainz.org/track/{0}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace MediaBrowser.Providers.Omdb
|
||||||
list.Add(new RemoteImageInfo
|
list.Add(new RemoteImageInfo
|
||||||
{
|
{
|
||||||
ProviderName = Name,
|
ProviderName = Name,
|
||||||
Url = string.Format("http://img.omdbapi.com/?i={0}&apikey=82e83907", imdbId)
|
Url = string.Format("https://img.omdbapi.com/?i={0}&apikey=82e83907", imdbId)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace MediaBrowser.Providers.Omdb
|
||||||
|
|
||||||
var imdbId = searchInfo.GetProviderId(MetadataProviders.Imdb);
|
var imdbId = searchInfo.GetProviderId(MetadataProviders.Imdb);
|
||||||
|
|
||||||
var url = "http://www.omdbapi.com/?plot=full&r=json";
|
var url = "https://www.omdbapi.com/?plot=full&r=json";
|
||||||
if (type == "episode" && episodeSearchInfo != null)
|
if (type == "episode" && episodeSearchInfo != null)
|
||||||
{
|
{
|
||||||
episodeSearchInfo.SeriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out imdbId);
|
episodeSearchInfo.SeriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out imdbId);
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.Omdb
|
||||||
|
|
||||||
var imdbParam = imdbId.StartsWith("tt", StringComparison.OrdinalIgnoreCase) ? imdbId : "tt" + imdbId;
|
var imdbParam = imdbId.StartsWith("tt", StringComparison.OrdinalIgnoreCase) ? imdbId : "tt" + imdbId;
|
||||||
|
|
||||||
var url = string.Format("http://www.omdbapi.com/?i={0}&tomatoes=true", imdbParam);
|
var url = string.Format("https://www.omdbapi.com/?i={0}&tomatoes=true", imdbParam);
|
||||||
|
|
||||||
using (var stream = await _httpClient.Get(new HttpRequestOptions
|
using (var stream = await _httpClient.Get(new HttpRequestOptions
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace MediaBrowser.Providers.People
|
||||||
|
|
||||||
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
|
||||||
|
|
||||||
return GetImages(images, item.GetPreferredMetadataLanguage(), tmdbImageUrl);
|
return GetImages(images, item.GetPreferredMetadataLanguage(), tmdbImageUrl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace MediaBrowser.Providers.People
|
||||||
|
|
||||||
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(tmdbId))
|
if (!string.IsNullOrEmpty(tmdbId))
|
||||||
{
|
{
|
||||||
|
@ -97,7 +97,7 @@ namespace MediaBrowser.Providers.People
|
||||||
|
|
||||||
var requestCount = _requestCount;
|
var requestCount = _requestCount;
|
||||||
|
|
||||||
if (requestCount >= 30)
|
if (requestCount >= 40)
|
||||||
{
|
{
|
||||||
//_logger.Debug("Throttling Tmdb people");
|
//_logger.Debug("Throttling Tmdb people");
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ namespace MediaBrowser.Providers.People
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var url = string.Format(@"http://api.themoviedb.org/3/search/person?api_key={1}&query={0}", WebUtility.UrlEncode(searchInfo.Name), MovieDbProvider.ApiKey);
|
var url = string.Format(@"https://api.themoviedb.org/3/search/person?api_key={1}&query={0}", WebUtility.UrlEncode(searchInfo.Name), MovieDbProvider.ApiKey);
|
||||||
|
|
||||||
using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
|
using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
|
||||||
{
|
{
|
||||||
|
@ -234,7 +234,7 @@ namespace MediaBrowser.Providers.People
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var url = string.Format(@"http://api.themoviedb.org/3/person/{1}?api_key={0}&append_to_response=credits,images,external_ids", MovieDbProvider.ApiKey, id);
|
var url = string.Format(@"https://api.themoviedb.org/3/person/{1}?api_key={0}&append_to_response=credits,images,external_ids", MovieDbProvider.ApiKey, id);
|
||||||
|
|
||||||
using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
|
using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,7 +21,7 @@ using CommonIO;
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.TV
|
namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
public class FanArtSeasonProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor
|
public class FanArtSeasonProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
|
||||||
{
|
{
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
|
@ -225,7 +225,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
var options = FanartSeriesProvider.Current.GetFanartOptions();
|
var options = FanartSeriesProvider.Current.GetFanartOptions();
|
||||||
if (!options.EnableAutomaticUpdates)
|
if (!options.EnableAutomaticUpdates)
|
||||||
|
@ -250,7 +250,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
var fileInfo = _fileSystem.GetFileInfo(imagesFilePath);
|
var fileInfo = _fileSystem.GetFileInfo(imagesFilePath);
|
||||||
|
|
||||||
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
|
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
class FanArtTvUpdatesPostScanTask : ILibraryPostScanTask
|
class FanArtTvUpdatesPostScanTask : ILibraryPostScanTask
|
||||||
{
|
{
|
||||||
private const string UpdatesUrl = "http://webservice.fanart.tv/v3/tv/latest?api_key={0}&date={1}";
|
private const string UpdatesUrl = "https://webservice.fanart.tv/v3/tv/latest?api_key={0}&date={1}";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _HTTP client
|
/// The _HTTP client
|
||||||
|
|
|
@ -23,7 +23,7 @@ using CommonIO;
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.TV
|
namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
public class FanartSeriesProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor
|
public class FanartSeriesProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
|
||||||
{
|
{
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
|
@ -31,7 +31,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IJsonSerializer _json;
|
private readonly IJsonSerializer _json;
|
||||||
|
|
||||||
private const string FanArtBaseUrl = "http://webservice.fanart.tv/v3/tv/{1}?api_key={0}";
|
private const string FanArtBaseUrl = "https://webservice.fanart.tv/v3/tv/{1}?api_key={0}";
|
||||||
// &client_key=52c813aa7b8c8b3bb87f4797532a2f8c
|
// &client_key=52c813aa7b8c8b3bb87f4797532a2f8c
|
||||||
|
|
||||||
internal static FanartSeriesProvider Current { get; private set; }
|
internal static FanartSeriesProvider Current { get; private set; }
|
||||||
|
@ -341,7 +341,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
var options = GetFanartOptions();
|
var options = GetFanartOptions();
|
||||||
if (!options.EnableAutomaticUpdates)
|
if (!options.EnableAutomaticUpdates)
|
||||||
|
@ -358,7 +358,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
var fileInfo = _fileSystem.GetFileInfo(imagesFilePath);
|
var fileInfo = _fileSystem.GetFileInfo(imagesFilePath);
|
||||||
|
|
||||||
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
|
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -27,6 +27,8 @@ namespace MediaBrowser.Providers.TV
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
|
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
|
private static readonly SemaphoreSlim _resourceLock = new SemaphoreSlim(1, 1);
|
||||||
|
public static bool IsRunning = false;
|
||||||
|
|
||||||
public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization, IFileSystem fileSystem)
|
public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization, IFileSystem fileSystem)
|
||||||
{
|
{
|
||||||
|
@ -37,13 +39,16 @@ namespace MediaBrowser.Providers.TV
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Run(IEnumerable<IGrouping<string, Series>> series, CancellationToken cancellationToken)
|
public async Task Run(List<IGrouping<string, Series>> series, bool addNewItems, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
await _resourceLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
IsRunning = true;
|
||||||
|
|
||||||
foreach (var seriesGroup in series)
|
foreach (var seriesGroup in series)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Run(seriesGroup, cancellationToken).ConfigureAwait(false);
|
await Run(seriesGroup, addNewItems, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
|
@ -58,9 +63,12 @@ namespace MediaBrowser.Providers.TV
|
||||||
_logger.ErrorException("Error in missing episode provider for series id {0}", ex, seriesGroup.Key);
|
_logger.ErrorException("Error in missing episode provider for series id {0}", ex, seriesGroup.Key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IsRunning = false;
|
||||||
|
_resourceLock.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Run(IGrouping<string, Series> group, CancellationToken cancellationToken)
|
private async Task Run(IGrouping<string, Series> group, bool addNewItems, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var tvdbId = group.Key;
|
var tvdbId = group.Key;
|
||||||
|
|
||||||
|
@ -110,7 +118,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
var hasNewEpisodes = false;
|
var hasNewEpisodes = false;
|
||||||
|
|
||||||
if (_config.Configuration.EnableInternetProviders)
|
if (_config.Configuration.EnableInternetProviders && addNewItems)
|
||||||
{
|
{
|
||||||
var seriesConfig = _config.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, typeof(Series).Name, StringComparison.OrdinalIgnoreCase));
|
var seriesConfig = _config.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, typeof(Series).Name, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
@ -427,7 +435,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
await season.AddChild(episode, cancellationToken).ConfigureAwait(false);
|
await season.AddChild(episode, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
await episode.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
|
await episode.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
|
||||||
{
|
{
|
||||||
}, cancellationToken).ConfigureAwait(false);
|
}, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,10 @@ using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CommonIO;
|
using CommonIO;
|
||||||
|
using MediaBrowser.Common.ScheduledTasks;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Plugins;
|
||||||
|
using MediaBrowser.Model.Tasks;
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.TV
|
namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
|
@ -46,14 +50,17 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
private async Task RunInternal(IProgress<double> progress, CancellationToken cancellationToken)
|
private async Task RunInternal(IProgress<double> progress, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var seriesList = _libraryManager.RootFolder
|
var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
|
||||||
.GetRecursiveChildren(i => i is Series)
|
{
|
||||||
.Cast<Series>()
|
IncludeItemTypes = new[] { typeof(Series).Name },
|
||||||
.ToList();
|
Recursive = true
|
||||||
|
|
||||||
|
}).Cast<Series>().ToList();
|
||||||
|
|
||||||
var seriesGroups = FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList();
|
var seriesGroups = FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList();
|
||||||
|
|
||||||
await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem).Run(seriesGroups, cancellationToken).ConfigureAwait(false);
|
await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem)
|
||||||
|
.Run(seriesGroups, true, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var numComplete = 0;
|
var numComplete = 0;
|
||||||
|
|
||||||
|
@ -82,7 +89,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<IGrouping<string, Series>> FindSeriesGroups(List<Series> seriesList)
|
internal static IEnumerable<IGrouping<string, Series>> FindSeriesGroups(List<Series> seriesList)
|
||||||
{
|
{
|
||||||
var links = seriesList.ToDictionary(s => s, s => seriesList.Where(c => c != s && ShareProviderId(s, c)).ToList());
|
var links = seriesList.ToDictionary(s => s, s => seriesList.Where(c => c != s && ShareProviderId(s, c)).ToList());
|
||||||
|
|
||||||
|
@ -102,7 +109,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FindAllLinked(Series series, HashSet<Series> visited, IDictionary<Series, List<Series>> linksMap, List<Series> results)
|
private static void FindAllLinked(Series series, HashSet<Series> visited, IDictionary<Series, List<Series>> linksMap, List<Series> results)
|
||||||
{
|
{
|
||||||
results.Add(series);
|
results.Add(series);
|
||||||
visited.Add(series);
|
visited.Add(series);
|
||||||
|
@ -118,7 +125,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ShareProviderId(Series a, Series b)
|
private static bool ShareProviderId(Series a, Series b)
|
||||||
{
|
{
|
||||||
return a.ProviderIds.Any(id =>
|
return a.ProviderIds.Any(id =>
|
||||||
{
|
{
|
||||||
|
@ -137,4 +144,108 @@ namespace MediaBrowser.Providers.TV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class CleanMissingEpisodesEntryPoint : IServerEntryPoint
|
||||||
|
{
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
private readonly IServerConfigurationManager _config;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly ILocalizationManager _localization;
|
||||||
|
private readonly IFileSystem _fileSystem;
|
||||||
|
private readonly object _libraryChangedSyncLock = new object();
|
||||||
|
private const int LibraryUpdateDuration = 180000;
|
||||||
|
private readonly ITaskManager _taskManager;
|
||||||
|
|
||||||
|
public CleanMissingEpisodesEntryPoint(ILibraryManager libraryManager, IServerConfigurationManager config, ILogger logger, ILocalizationManager localization, IFileSystem fileSystem, ITaskManager taskManager)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
_config = config;
|
||||||
|
_logger = logger;
|
||||||
|
_localization = localization;
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
_taskManager = taskManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Timer LibraryUpdateTimer { get; set; }
|
||||||
|
|
||||||
|
public void Run()
|
||||||
|
{
|
||||||
|
_libraryManager.ItemAdded += _libraryManager_ItemAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _libraryManager_ItemAdded(object sender, ItemChangeEventArgs e)
|
||||||
|
{
|
||||||
|
if (!FilterItem(e.Item))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_libraryChangedSyncLock)
|
||||||
|
{
|
||||||
|
if (LibraryUpdateTimer == null)
|
||||||
|
{
|
||||||
|
LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration, Timeout.Infinite);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void LibraryUpdateTimerCallback(object state)
|
||||||
|
{
|
||||||
|
if (MissingEpisodeProvider.IsRunning)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_libraryManager.IsScanRunning)
|
||||||
|
{
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
|
||||||
|
{
|
||||||
|
IncludeItemTypes = new[] { typeof(Series).Name },
|
||||||
|
Recursive = true
|
||||||
|
|
||||||
|
}).Cast<Series>().ToList();
|
||||||
|
|
||||||
|
var seriesGroups = SeriesPostScanTask.FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList();
|
||||||
|
|
||||||
|
await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem)
|
||||||
|
.Run(seriesGroups, false, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool FilterItem(BaseItem item)
|
||||||
|
{
|
||||||
|
return item is Episode && item.LocationType != LocationType.Virtual;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases unmanaged and - optionally - managed resources.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
||||||
|
protected virtual void Dispose(bool dispose)
|
||||||
|
{
|
||||||
|
if (dispose)
|
||||||
|
{
|
||||||
|
if (LibraryUpdateTimer != null)
|
||||||
|
{
|
||||||
|
LibraryUpdateTimer.Dispose();
|
||||||
|
LibraryUpdateTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_libraryManager.ItemAdded -= _libraryManager_ItemAdded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
|
||||||
|
|
||||||
list.AddRange(GetPosters(response.images).Select(i => new RemoteImageInfo
|
list.AddRange(GetPosters(response.images).Select(i => new RemoteImageInfo
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
public abstract class MovieDbProviderBase
|
public abstract class MovieDbProviderBase
|
||||||
{
|
{
|
||||||
private const string EpisodeUrlPattern = @"http://api.themoviedb.org/3/tv/{0}/season/{1}/episode/{2}?api_key={3}&append_to_response=images,external_ids,credits,videos";
|
private const string EpisodeUrlPattern = @"https://api.themoviedb.org/3/tv/{0}/season/{1}/episode/{2}?api_key={3}&append_to_response=images,external_ids,credits,videos";
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
private readonly IServerConfigurationManager _configurationManager;
|
private readonly IServerConfigurationManager _configurationManager;
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
public class MovieDbSeasonProvider : IRemoteMetadataProvider<Season, SeasonInfo>
|
public class MovieDbSeasonProvider : IRemoteMetadataProvider<Season, SeasonInfo>
|
||||||
{
|
{
|
||||||
private const string GetTvInfo3 = @"http://api.themoviedb.org/3/tv/{0}/season/{1}?api_key={2}&append_to_response=images,keywords,external_ids,credits,videos";
|
private const string GetTvInfo3 = @"https://api.themoviedb.org/3/tv/{0}/season/{1}?api_key={2}&append_to_response=images,keywords,external_ids,credits,videos";
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
private readonly IServerConfigurationManager _configurationManager;
|
private readonly IServerConfigurationManager _configurationManager;
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
|
|
|
@ -16,7 +16,7 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.TV
|
namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
public class MovieDbSeriesImageProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor
|
public class MovieDbSeriesImageProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
|
||||||
{
|
{
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
|
@ -64,7 +64,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
|
||||||
|
|
||||||
list.AddRange(GetPosters(results).Select(i => new RemoteImageInfo
|
list.AddRange(GetPosters(results).Select(i => new RemoteImageInfo
|
||||||
{
|
{
|
||||||
|
@ -196,9 +196,9 @@ namespace MediaBrowser.Providers.TV
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
return MovieDbSeriesProvider.Current.HasChanged(item, date);
|
return MovieDbSeriesProvider.Current.HasChanged(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
public class MovieDbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
|
public class MovieDbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
|
||||||
{
|
{
|
||||||
private const string GetTvInfo3 = @"http://api.themoviedb.org/3/tv/{0}?api_key={1}&append_to_response=credits,images,keywords,external_ids,videos";
|
private const string GetTvInfo3 = @"https://api.themoviedb.org/3/tv/{0}?api_key={1}&append_to_response=credits,images,keywords,external_ids,videos,content_ratings";
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
|
|
||||||
internal static MovieDbSeriesProvider Current { get; private set; }
|
internal static MovieDbSeriesProvider Current { get; private set; }
|
||||||
|
@ -69,7 +69,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
var obj = _jsonSerializer.DeserializeFromFile<RootObject>(dataFilePath);
|
var obj = _jsonSerializer.DeserializeFromFile<RootObject>(dataFilePath);
|
||||||
|
|
||||||
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
|
||||||
|
|
||||||
var remoteResult = new RemoteSearchResult
|
var remoteResult = new RemoteSearchResult
|
||||||
{
|
{
|
||||||
|
@ -168,7 +168,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
result.Item = await FetchMovieData(tmdbId, info.MetadataLanguage, cancellationToken).ConfigureAwait(false);
|
result.Item = await FetchMovieData(tmdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
result.HasMetadata = result.Item != null;
|
result.HasMetadata = result.Item != null;
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Series> FetchMovieData(string tmdbId, string language, CancellationToken cancellationToken)
|
private async Task<Series> FetchMovieData(string tmdbId, string language, string preferredCountryCode, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
string dataFilePath = null;
|
string dataFilePath = null;
|
||||||
RootObject seriesInfo = null;
|
RootObject seriesInfo = null;
|
||||||
|
@ -201,12 +201,12 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
var item = new Series();
|
var item = new Series();
|
||||||
|
|
||||||
ProcessMainInfo(item, seriesInfo);
|
ProcessMainInfo(item, seriesInfo, preferredCountryCode);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessMainInfo(Series series, RootObject seriesInfo)
|
private void ProcessMainInfo(Series series, RootObject seriesInfo, string preferredCountryCode)
|
||||||
{
|
{
|
||||||
series.Name = seriesInfo.name;
|
series.Name = seriesInfo.name;
|
||||||
series.SetProviderId(MetadataProviders.Tmdb, seriesInfo.id.ToString(_usCulture));
|
series.SetProviderId(MetadataProviders.Tmdb, seriesInfo.id.ToString(_usCulture));
|
||||||
|
@ -265,6 +265,26 @@ namespace MediaBrowser.Providers.TV
|
||||||
series.SetProviderId(MetadataProviders.Tvdb, ids.tvdb_id.ToString(_usCulture));
|
series.SetProviderId(MetadataProviders.Tvdb, ids.tvdb_id.ToString(_usCulture));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var contentRatings = (seriesInfo.content_ratings ?? new ContentRatings()).results ?? new List<ContentRating>();
|
||||||
|
|
||||||
|
var ourRelease = contentRatings.FirstOrDefault(c => string.Equals(c.iso_3166_1, preferredCountryCode, StringComparison.OrdinalIgnoreCase));
|
||||||
|
var usRelease = contentRatings.FirstOrDefault(c => string.Equals(c.iso_3166_1, "US", StringComparison.OrdinalIgnoreCase));
|
||||||
|
var minimumRelease = contentRatings.FirstOrDefault();
|
||||||
|
|
||||||
|
if (ourRelease != null)
|
||||||
|
{
|
||||||
|
series.OfficialRating = ourRelease.rating;
|
||||||
|
}
|
||||||
|
else if (usRelease != null)
|
||||||
|
{
|
||||||
|
series.OfficialRating = usRelease.rating;
|
||||||
|
}
|
||||||
|
else if (minimumRelease != null)
|
||||||
|
{
|
||||||
|
series.OfficialRating = minimumRelease.rating;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GetSeriesDataPath(IApplicationPaths appPaths, string tmdbId)
|
internal static string GetSeriesDataPath(IApplicationPaths appPaths, string tmdbId)
|
||||||
|
@ -394,7 +414,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
return Path.Combine(path, filename);
|
return Path.Combine(path, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, DateTime date)
|
public bool HasChanged(IHasMetadata item)
|
||||||
{
|
{
|
||||||
if (!MovieDbProvider.Current.GetTheMovieDbOptions().EnableAutomaticUpdates)
|
if (!MovieDbProvider.Current.GetTheMovieDbOptions().EnableAutomaticUpdates)
|
||||||
{
|
{
|
||||||
|
@ -410,7 +430,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
var fileInfo = _fileSystem.GetFileInfo(dataFilePath);
|
var fileInfo = _fileSystem.GetFileInfo(dataFilePath);
|
||||||
|
|
||||||
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
|
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -418,7 +438,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
private async Task<RemoteSearchResult> FindByExternalId(string id, string externalSource, CancellationToken cancellationToken)
|
private async Task<RemoteSearchResult> FindByExternalId(string id, string externalSource, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var url = string.Format("http://api.themoviedb.org/3/tv/find/{0}?api_key={1}&external_source={2}",
|
var url = string.Format("https://api.themoviedb.org/3/tv/find/{0}?api_key={1}&external_source={2}",
|
||||||
id,
|
id,
|
||||||
MovieDbProvider.ApiKey,
|
MovieDbProvider.ApiKey,
|
||||||
externalSource);
|
externalSource);
|
||||||
|
@ -440,7 +460,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
if (tv != null)
|
if (tv != null)
|
||||||
{
|
{
|
||||||
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
|
||||||
|
|
||||||
var remoteResult = new RemoteSearchResult
|
var remoteResult = new RemoteSearchResult
|
||||||
{
|
{
|
||||||
|
@ -481,6 +501,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
public class Season
|
public class Season
|
||||||
{
|
{
|
||||||
public string air_date { get; set; }
|
public string air_date { get; set; }
|
||||||
|
public int episode_count { get; set; }
|
||||||
public int id { get; set; }
|
public int id { get; set; }
|
||||||
public string poster_path { get; set; }
|
public string poster_path { get; set; }
|
||||||
public int season_number { get; set; }
|
public int season_number { get; set; }
|
||||||
|
@ -528,7 +549,6 @@ namespace MediaBrowser.Providers.TV
|
||||||
public double aspect_ratio { get; set; }
|
public double aspect_ratio { get; set; }
|
||||||
public string file_path { get; set; }
|
public string file_path { get; set; }
|
||||||
public int height { get; set; }
|
public int height { get; set; }
|
||||||
public string id { get; set; }
|
|
||||||
public string iso_639_1 { get; set; }
|
public string iso_639_1 { get; set; }
|
||||||
public double vote_average { get; set; }
|
public double vote_average { get; set; }
|
||||||
public int vote_count { get; set; }
|
public int vote_count { get; set; }
|
||||||
|
@ -560,6 +580,17 @@ namespace MediaBrowser.Providers.TV
|
||||||
public List<object> results { get; set; }
|
public List<object> results { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ContentRating
|
||||||
|
{
|
||||||
|
public string iso_3166_1 { get; set; }
|
||||||
|
public string rating { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ContentRatings
|
||||||
|
{
|
||||||
|
public List<ContentRating> results { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class RootObject
|
public class RootObject
|
||||||
{
|
{
|
||||||
public string backdrop_path { get; set; }
|
public string backdrop_path { get; set; }
|
||||||
|
@ -590,6 +621,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
public Keywords keywords { get; set; }
|
public Keywords keywords { get; set; }
|
||||||
public ExternalIds external_ids { get; set; }
|
public ExternalIds external_ids { get; set; }
|
||||||
public Videos videos { get; set; }
|
public Videos videos { get; set; }
|
||||||
|
public ContentRatings content_ratings { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Order
|
public int Order
|
||||||
|
|
|
@ -17,7 +17,7 @@ using CommonIO;
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.TV
|
namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
public class TvdbEpisodeImageProvider : IRemoteImageProvider, IHasChangeMonitor
|
public class TvdbEpisodeImageProvider : IRemoteImageProvider, IHasItemChangeMonitor
|
||||||
{
|
{
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
|
@ -174,7 +174,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
var episode = (Episode)item;
|
var episode = (Episode)item;
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
// Process images
|
// Process images
|
||||||
var seriesXmlPath = TvdbSeriesProvider.Current.GetSeriesXmlPath(series.ProviderIds, series.GetPreferredMetadataLanguage());
|
var seriesXmlPath = TvdbSeriesProvider.Current.GetSeriesXmlPath(series.ProviderIds, series.GetPreferredMetadataLanguage());
|
||||||
|
|
||||||
return _fileSystem.GetLastWriteTimeUtc(seriesXmlPath) > date;
|
return _fileSystem.GetLastWriteTimeUtc(seriesXmlPath) > item.DateLastRefreshed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class RemoteEpisodeProvider
|
/// Class RemoteEpisodeProvider
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IItemIdentityProvider<EpisodeInfo>, IHasChangeMonitor
|
class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IItemIdentityProvider<EpisodeInfo>, IHasItemChangeMonitor
|
||||||
{
|
{
|
||||||
private static readonly string FullIdKey = MetadataProviders.Tvdb + "-Full";
|
private static readonly string FullIdKey = MetadataProviders.Tvdb + "-Full";
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
// Only enable for virtual items
|
// Only enable for virtual items
|
||||||
if (item.LocationType != LocationType.Virtual)
|
if (item.LocationType != LocationType.Virtual)
|
||||||
|
@ -160,7 +160,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
// Process images
|
// Process images
|
||||||
var seriesXmlPath = TvdbSeriesProvider.Current.GetSeriesXmlPath(series.ProviderIds, series.GetPreferredMetadataLanguage());
|
var seriesXmlPath = TvdbSeriesProvider.Current.GetSeriesXmlPath(series.ProviderIds, series.GetPreferredMetadataLanguage());
|
||||||
|
|
||||||
return _fileSystem.GetLastWriteTimeUtc(seriesXmlPath) > date;
|
return _fileSystem.GetLastWriteTimeUtc(seriesXmlPath) > item.DateLastRefreshed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -26,12 +26,12 @@ namespace MediaBrowser.Providers.TV
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The server time URL
|
/// The server time URL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const string ServerTimeUrl = "http://thetvdb.com/api/Updates.php?type=none";
|
private const string ServerTimeUrl = "https://thetvdb.com/api/Updates.php?type=none";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The updates URL
|
/// The updates URL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const string UpdatesUrl = "http://thetvdb.com/api/Updates.php?type=all&time={0}";
|
private const string UpdatesUrl = "https://thetvdb.com/api/Updates.php?type=all&time={0}";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _HTTP client
|
/// The _HTTP client
|
||||||
|
|
|
@ -20,7 +20,7 @@ using CommonIO;
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.TV
|
namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
public class TvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor
|
public class TvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
|
||||||
{
|
{
|
||||||
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||||
|
|
||||||
|
@ -363,7 +363,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
if (item.LocationType != LocationType.Virtual)
|
if (item.LocationType != LocationType.Virtual)
|
||||||
{
|
{
|
||||||
|
@ -384,7 +384,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
var fileInfo = _fileSystem.GetFileInfo(imagesXmlPath);
|
var fileInfo = _fileSystem.GetFileInfo(imagesXmlPath);
|
||||||
|
|
||||||
return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
|
return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -53,9 +53,9 @@ namespace MediaBrowser.Providers.TV
|
||||||
Current = this;
|
Current = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private const string SeriesSearchUrl = "http://www.thetvdb.com/api/GetSeries.php?seriesname={0}&language={1}";
|
private const string SeriesSearchUrl = "https://www.thetvdb.com/api/GetSeries.php?seriesname={0}&language={1}";
|
||||||
private const string SeriesGetZip = "http://www.thetvdb.com/api/{0}/series/{1}/all/{2}.zip";
|
private const string SeriesGetZip = "https://www.thetvdb.com/api/{0}/series/{1}/all/{2}.zip";
|
||||||
private const string GetSeriesByImdbId = "http://www.thetvdb.com/api/GetSeriesByRemoteID.php?imdbid={0}&language={1}";
|
private const string GetSeriesByImdbId = "https://www.thetvdb.com/api/GetSeriesByRemoteID.php?imdbid={0}&language={1}";
|
||||||
|
|
||||||
private string NormalizeLanguage(string language)
|
private string NormalizeLanguage(string language)
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
public string UrlFormatString
|
public string UrlFormatString
|
||||||
{
|
{
|
||||||
get { return "http://thetvdb.com/index.php?tab=series&id={0}"; }
|
get { return "https://thetvdb.com/index.php?tab=series&id={0}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Supports(IHasProviderIds item)
|
public bool Supports(IHasProviderIds item)
|
||||||
|
|
|
@ -282,7 +282,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
|
|
||||||
else if (dto.HasSyncJob.Value)
|
else if (dto.HasSyncJob.Value)
|
||||||
{
|
{
|
||||||
dto.SyncStatus = SyncJobItemStatus.Queued;
|
dto.SyncStatus = syncProgress.Where(i => string.Equals(i.ItemId, dto.Id, StringComparison.OrdinalIgnoreCase)).Select(i => i.Status).Max();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,7 +307,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
|
|
||||||
else if (dto.HasSyncJob.Value)
|
else if (dto.HasSyncJob.Value)
|
||||||
{
|
{
|
||||||
dto.SyncStatus = SyncJobItemStatus.Queued;
|
dto.SyncStatus = syncProgress.Where(i => string.Equals(i.ItemId, dto.Id, StringComparison.OrdinalIgnoreCase)).Select(i => i.Status).Max();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1126,6 +1126,11 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
dto.Overview = item.Overview;
|
dto.Overview = item.Overview;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fields.Contains(ItemFields.OriginalTitle))
|
||||||
|
{
|
||||||
|
dto.OriginalTitle = item.OriginalTitle;
|
||||||
|
}
|
||||||
|
|
||||||
if (fields.Contains(ItemFields.ShortOverview))
|
if (fields.Contains(ItemFields.ShortOverview))
|
||||||
{
|
{
|
||||||
var hasShortOverview = item as IHasShortOverview;
|
var hasShortOverview = item as IHasShortOverview;
|
||||||
|
|
|
@ -215,6 +215,12 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var video = e.Item as Video;
|
||||||
|
if (video != null && video.IsThemeMedia)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var type = GetPlaybackNotificationType(item.MediaType);
|
var type = GetPlaybackNotificationType(item.MediaType);
|
||||||
|
|
||||||
SendPlaybackNotification(type, e);
|
SendPlaybackNotification(type, e);
|
||||||
|
@ -230,6 +236,12 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var video = e.Item as Video;
|
||||||
|
if (video != null && video.IsThemeMedia)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var type = GetPlaybackStoppedNotificationType(item.MediaType);
|
var type = GetPlaybackStoppedNotificationType(item.MediaType);
|
||||||
|
|
||||||
SendPlaybackNotification(type, e);
|
SendPlaybackNotification(type, e);
|
||||||
|
|
|
@ -179,6 +179,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
|
|
||||||
private void OnWebSocketConnecting(WebSocketConnectingEventArgs args)
|
private void OnWebSocketConnecting(WebSocketConnectingEventArgs args)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (WebSocketConnecting != null)
|
if (WebSocketConnecting != null)
|
||||||
{
|
{
|
||||||
WebSocketConnecting(this, args);
|
WebSocketConnecting(this, args);
|
||||||
|
@ -187,6 +192,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
|
|
||||||
private void OnWebSocketConnected(WebSocketConnectEventArgs args)
|
private void OnWebSocketConnected(WebSocketConnectEventArgs args)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (WebSocketConnected != null)
|
if (WebSocketConnected != null)
|
||||||
{
|
{
|
||||||
WebSocketConnected(this, args);
|
WebSocketConnected(this, args);
|
||||||
|
@ -331,6 +341,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
|
|
||||||
var httpRes = httpReq.Response;
|
var httpRes = httpReq.Response;
|
||||||
|
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
httpRes.StatusCode = 503;
|
||||||
|
httpRes.Close();
|
||||||
|
return Task.FromResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
var operationName = httpReq.OperationName;
|
var operationName = httpReq.OperationName;
|
||||||
var localPath = url.LocalPath;
|
var localPath = url.LocalPath;
|
||||||
|
|
||||||
|
|
|
@ -663,7 +663,7 @@ namespace MediaBrowser.Server.Implementations.IO
|
||||||
|
|
||||||
while (item == null && !string.IsNullOrEmpty(path))
|
while (item == null && !string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
item = LibraryManager.FindByPath(path);
|
item = LibraryManager.FindByPath(path, null);
|
||||||
|
|
||||||
path = Path.GetDirectoryName(path);
|
path = Path.GetDirectoryName(path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,6 +143,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
|
private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
|
||||||
private readonly Func<IProviderManager> _providerManagerFactory;
|
private readonly Func<IProviderManager> _providerManagerFactory;
|
||||||
private readonly Func<IUserViewManager> _userviewManager;
|
private readonly Func<IUserViewManager> _userviewManager;
|
||||||
|
public bool IsScanRunning { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _library items cache
|
/// The _library items cache
|
||||||
|
@ -800,11 +801,12 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
return _userRootFolder;
|
return _userRootFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BaseItem FindByPath(string path)
|
public BaseItem FindByPath(string path, bool? isFolder)
|
||||||
{
|
{
|
||||||
var query = new InternalItemsQuery
|
var query = new InternalItemsQuery
|
||||||
{
|
{
|
||||||
Path = path
|
Path = path,
|
||||||
|
IsFolder = isFolder
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only use the database result if there's exactly one item, otherwise we run the risk of returning old data that hasn't been cleaned yet.
|
// Only use the database result if there's exactly one item, otherwise we run the risk of returning old data that hasn't been cleaned yet.
|
||||||
|
@ -1102,6 +1104,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public async Task ValidateMediaLibraryInternal(IProgress<double> progress, CancellationToken cancellationToken)
|
public async Task ValidateMediaLibraryInternal(IProgress<double> progress, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
IsScanRunning = true;
|
||||||
_libraryMonitorFactory().Stop();
|
_libraryMonitorFactory().Stop();
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -1111,6 +1114,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_libraryMonitorFactory().Start();
|
_libraryMonitorFactory().Start();
|
||||||
|
IsScanRunning = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -269,13 +269,15 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
{
|
{
|
||||||
var userData = item == null ? new UserItemData() : _userDataManager.GetUserData(user.Id, item.GetUserDataKey());
|
var userData = item == null ? new UserItemData() : _userDataManager.GetUserData(user.Id, item.GetUserDataKey());
|
||||||
|
|
||||||
SetDefaultAudioStreamIndex(source, userData, user);
|
var allowRememberingSelection = item == null || item.EnableRememberingTrackSelections;
|
||||||
SetDefaultSubtitleStreamIndex(source, userData, user);
|
|
||||||
|
SetDefaultAudioStreamIndex(source, userData, user, allowRememberingSelection);
|
||||||
|
SetDefaultSubtitleStreamIndex(source, userData, user, allowRememberingSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user)
|
private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
|
||||||
{
|
{
|
||||||
if (userData.SubtitleStreamIndex.HasValue && user.Configuration.RememberSubtitleSelections && user.Configuration.SubtitleMode != SubtitlePlaybackMode.None)
|
if (userData.SubtitleStreamIndex.HasValue && user.Configuration.RememberSubtitleSelections && user.Configuration.SubtitleMode != SubtitlePlaybackMode.None && allowRememberingSelection)
|
||||||
{
|
{
|
||||||
var index = userData.SubtitleStreamIndex.Value;
|
var index = userData.SubtitleStreamIndex.Value;
|
||||||
// Make sure the saved index is still valid
|
// Make sure the saved index is still valid
|
||||||
|
@ -304,9 +306,9 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
user.Configuration.SubtitleMode, audioLangage);
|
user.Configuration.SubtitleMode, audioLangage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user)
|
private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
|
||||||
{
|
{
|
||||||
if (userData.AudioStreamIndex.HasValue && user.Configuration.RememberAudioSelections)
|
if (userData.AudioStreamIndex.HasValue && user.Configuration.RememberAudioSelections && allowRememberingSelection)
|
||||||
{
|
{
|
||||||
var index = userData.AudioStreamIndex.Value;
|
var index = userData.AudioStreamIndex.Value;
|
||||||
// Make sure the saved index is still valid
|
// Make sure the saved index is still valid
|
||||||
|
|
|
@ -42,10 +42,21 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
|
|
||||||
_logger.Info("Copying recording stream to file {0}", targetFile);
|
_logger.Info("Copying recording stream to file {0}", targetFile);
|
||||||
|
|
||||||
var durationToken = new CancellationTokenSource(duration);
|
if (mediaSource.RunTimeTicks.HasValue)
|
||||||
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
|
{
|
||||||
|
// The media source already has a fixed duration
|
||||||
|
// But add another stop 1 minute later just in case the recording gets stuck for any reason
|
||||||
|
var durationToken = new CancellationTokenSource(duration.Add(TimeSpan.FromMinutes(1)));
|
||||||
|
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The media source if infinite so we need to handle stopping ourselves
|
||||||
|
var durationToken = new CancellationTokenSource(duration);
|
||||||
|
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
|
||||||
|
}
|
||||||
|
|
||||||
await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken).ConfigureAwait(false);
|
await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -591,7 +591,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
throw new ApplicationException("Tuner not found.");
|
throw new ApplicationException("Tuner not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Tuple<MediaSourceInfo, SemaphoreSlim>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
|
private async Task<Tuple<MediaSourceInfo, ITunerHost, SemaphoreSlim>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.Info("Streaming Channel " + channelId);
|
_logger.Info("Streaming Channel " + channelId);
|
||||||
|
|
||||||
|
@ -599,7 +599,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
|
var result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return new Tuple<MediaSourceInfo, ITunerHost, SemaphoreSlim>(result.Item1, hostInstance, result.Item2);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -797,8 +799,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
// HDHR doesn't seem to release the tuner right away after first probing with ffmpeg
|
// HDHR doesn't seem to release the tuner right away after first probing with ffmpeg
|
||||||
//await Task.Delay(3000, cancellationToken).ConfigureAwait(false);
|
//await Task.Delay(3000, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var duration = recordingEndDate - DateTime.UtcNow;
|
|
||||||
|
|
||||||
var recorder = await GetRecorder().ConfigureAwait(false);
|
var recorder = await GetRecorder().ConfigureAwait(false);
|
||||||
|
|
||||||
if (recorder is EncodedRecorder)
|
if (recorder is EncodedRecorder)
|
||||||
|
@ -816,6 +816,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
recording.DateLastUpdated = DateTime.UtcNow;
|
recording.DateLastUpdated = DateTime.UtcNow;
|
||||||
_recordingProvider.AddOrUpdate(recording);
|
_recordingProvider.AddOrUpdate(recording);
|
||||||
|
|
||||||
|
var duration = recordingEndDate - DateTime.UtcNow;
|
||||||
|
|
||||||
_logger.Info("Beginning recording. Will record for {0} minutes.", duration.TotalMinutes.ToString(CultureInfo.InvariantCulture));
|
_logger.Info("Beginning recording. Will record for {0} minutes.", duration.TotalMinutes.ToString(CultureInfo.InvariantCulture));
|
||||||
|
|
||||||
_logger.Info("Writing file to path: " + recordPath);
|
_logger.Info("Writing file to path: " + recordPath);
|
||||||
|
@ -823,10 +825,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
|
|
||||||
Action onStarted = () =>
|
Action onStarted = () =>
|
||||||
{
|
{
|
||||||
result.Item2.Release();
|
result.Item3.Release();
|
||||||
isResourceOpen = false;
|
isResourceOpen = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var pathWithDuration = result.Item2.ApplyDuration(mediaStreamInfo.Path, duration);
|
||||||
|
|
||||||
|
// If it supports supplying duration via url
|
||||||
|
if (!string.Equals(pathWithDuration, mediaStreamInfo.Path, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
mediaStreamInfo.Path = pathWithDuration;
|
||||||
|
mediaStreamInfo.RunTimeTicks = duration.Ticks;
|
||||||
|
}
|
||||||
|
|
||||||
await recorder.Record(mediaStreamInfo, recordPath, duration, onStarted, cancellationToken).ConfigureAwait(false);
|
await recorder.Record(mediaStreamInfo, recordPath, duration, onStarted, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
recording.Status = RecordingStatus.Completed;
|
recording.Status = RecordingStatus.Completed;
|
||||||
|
@ -836,7 +847,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
{
|
{
|
||||||
if (isResourceOpen)
|
if (isResourceOpen)
|
||||||
{
|
{
|
||||||
result.Item2.Release();
|
result.Item3.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
_libraryMonitor.ReportFileSystemChangeComplete(recordPath, false);
|
_libraryMonitor.ReportFileSystemChangeComplete(recordPath, false);
|
||||||
|
@ -916,13 +927,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
|
|
||||||
private async Task<IRecorder> GetRecorder()
|
private async Task<IRecorder> GetRecorder()
|
||||||
{
|
{
|
||||||
if (GetConfiguration().EnableRecordingEncoding)
|
var config = GetConfiguration();
|
||||||
|
|
||||||
|
if (config.EnableRecordingEncoding)
|
||||||
{
|
{
|
||||||
var regInfo = await _security.GetRegistrationStatus("embytvrecordingconversion").ConfigureAwait(false);
|
var regInfo = await _security.GetRegistrationStatus("embytvrecordingconversion").ConfigureAwait(false);
|
||||||
|
|
||||||
if (regInfo.IsValid)
|
if (regInfo.IsValid)
|
||||||
{
|
{
|
||||||
return new EncodedRecorder(_logger, _fileSystem, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer);
|
return new EncodedRecorder(_logger, _fileSystem, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.LiveTv;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
private readonly IApplicationPaths _appPaths;
|
private readonly IApplicationPaths _appPaths;
|
||||||
|
private readonly LiveTvOptions _liveTvOptions;
|
||||||
private bool _hasExited;
|
private bool _hasExited;
|
||||||
private Stream _logFileStream;
|
private Stream _logFileStream;
|
||||||
private string _targetPath;
|
private string _targetPath;
|
||||||
|
@ -30,17 +32,32 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
private readonly IJsonSerializer _json;
|
private readonly IJsonSerializer _json;
|
||||||
private readonly TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>();
|
private readonly TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>();
|
||||||
|
|
||||||
public EncodedRecorder(ILogger logger, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IApplicationPaths appPaths, IJsonSerializer json)
|
public EncodedRecorder(ILogger logger, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IApplicationPaths appPaths, IJsonSerializer json, LiveTvOptions liveTvOptions)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_appPaths = appPaths;
|
_appPaths = appPaths;
|
||||||
_json = json;
|
_json = json;
|
||||||
|
_liveTvOptions = liveTvOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
|
public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
if (mediaSource.RunTimeTicks.HasValue)
|
||||||
|
{
|
||||||
|
// The media source already has a fixed duration
|
||||||
|
// But add another stop 1 minute later just in case the recording gets stuck for any reason
|
||||||
|
var durationToken = new CancellationTokenSource(duration.Add(TimeSpan.FromMinutes(1)));
|
||||||
|
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The media source if infinite so we need to handle stopping ourselves
|
||||||
|
var durationToken = new CancellationTokenSource(duration);
|
||||||
|
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
|
||||||
|
}
|
||||||
|
|
||||||
_targetPath = targetFile;
|
_targetPath = targetFile;
|
||||||
_fileSystem.CreateDirectory(Path.GetDirectoryName(targetFile));
|
_fileSystem.CreateDirectory(Path.GetDirectoryName(targetFile));
|
||||||
|
|
||||||
|
@ -129,7 +146,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
{
|
{
|
||||||
var copyAudio = new[] { "aac", "mp3" };
|
var copyAudio = new[] { "aac", "mp3" };
|
||||||
var mediaStreams = mediaSource.MediaStreams ?? new List<MediaStream>();
|
var mediaStreams = mediaSource.MediaStreams ?? new List<MediaStream>();
|
||||||
if (mediaStreams.Any(i => i.Type == MediaStreamType.Audio && copyAudio.Contains(i.Codec, StringComparer.OrdinalIgnoreCase)))
|
if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings || mediaStreams.Any(i => i.Type == MediaStreamType.Audio && copyAudio.Contains(i.Codec, StringComparer.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
return "-codec:a:0 copy";
|
return "-codec:a:0 copy";
|
||||||
}
|
}
|
||||||
|
@ -140,7 +157,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
{
|
{
|
||||||
audioChannels = audioStream.Channels ?? audioChannels;
|
audioChannels = audioStream.Channels ?? audioChannels;
|
||||||
}
|
}
|
||||||
return "-codec:a:0 aac -strict experimental -ab 320000";
|
return "-codec:a:0 aac -strict experimental -ab 320000 -af \"async=1000\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool EncodeVideo(MediaSourceInfo mediaSource)
|
private bool EncodeVideo(MediaSourceInfo mediaSource)
|
||||||
|
|
|
@ -224,7 +224,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
||||||
|
|
||||||
var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
|
var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
//await AddMediaInfo(stream, false, resourcePool, cancellationToken).ConfigureAwait(false);
|
if (EnableMediaProbing)
|
||||||
|
{
|
||||||
|
await AddMediaInfo(stream, false, resourcePool, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
return new Tuple<MediaSourceInfo, SemaphoreSlim>(stream, resourcePool);
|
return new Tuple<MediaSourceInfo, SemaphoreSlim>(stream, resourcePool);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -239,6 +243,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
||||||
throw new LiveTvConflictException();
|
throw new LiveTvConflictException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual bool EnableMediaProbing
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
protected async Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
|
protected async Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -268,6 +277,25 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
||||||
return _semaphoreLocks.GetOrAdd(url, key => new SemaphoreSlim(1, 1));
|
return _semaphoreLocks.GetOrAdd(url, key => new SemaphoreSlim(1, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await AddMediaInfoInternal(mediaSource, isAudio, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
// Leave the resource locked. it will be released upstream
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// Release the resource if there's some kind of failure.
|
||||||
|
resourcePool.Release();
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task AddMediaInfoInternal(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
|
private async Task AddMediaInfoInternal(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var originalRuntime = mediaSource.RunTimeTicks;
|
var originalRuntime = mediaSource.RunTimeTicks;
|
||||||
|
|
|
@ -59,6 +59,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string ApplyDuration(string streamPath, TimeSpan duration)
|
||||||
|
{
|
||||||
|
streamPath += streamPath.IndexOf('?') == -1 ? "?" : "&";
|
||||||
|
streamPath += "duration=" + Convert.ToInt32(duration.TotalSeconds).ToString(CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
return streamPath;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<IEnumerable<Channels>> GetLineup(TunerHostInfo info, CancellationToken cancellationToken)
|
private async Task<IEnumerable<Channels>> GetLineup(TunerHostInfo info, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var options = new HttpRequestOptions
|
var options = new HttpRequestOptions
|
||||||
|
|
|
@ -146,5 +146,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
||||||
{
|
{
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string ApplyDuration(string streamPath, TimeSpan duration)
|
||||||
|
{
|
||||||
|
return streamPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,5 +164,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string ApplyDuration(string streamPath, TimeSpan duration)
|
||||||
|
{
|
||||||
|
return streamPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user