diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs
index 6556807c4d..06db1de745 100644
--- a/MediaBrowser.Api/StartupWizardService.cs
+++ b/MediaBrowser.Api/StartupWizardService.cs
@@ -68,7 +68,6 @@ namespace MediaBrowser.Api
_config.Configuration.EnableLocalizedGuids = true;
_config.Configuration.EnableCustomPathSubFolders = true;
_config.Configuration.EnableDateLastRefresh = true;
- _config.Configuration.MergeMetadataAndImagesByName = true;
_config.SaveConfiguration();
}
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 1c5d5b345e..761d107603 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -116,6 +116,10 @@ namespace MediaBrowser.Api.UserLibrary
{
item = user == null ? _libraryManager.RootFolder : user.RootFolder;
}
+ else if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase))
+ {
+ item = user == null ? _libraryManager.RootFolder : user.RootFolder;
+ }
// Default list type = children
diff --git a/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs b/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
index 386370596c..281dee3e07 100644
--- a/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
+++ b/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
@@ -122,7 +122,7 @@ namespace MediaBrowser.Dlna.Server
builder.Append("" + SecurityElement.Escape(_profile.SerialNumber) + "");
}
- builder.Append("uuid:" + SecurityElement.Escape(_serverUdn) + "");
+ builder.Append("uuid:" + SecurityElement.Escape(_serverId) + "");
builder.Append("" + SecurityElement.Escape(_serverAddress) + "");
if (!EnableAbsoluteUrls)
diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
index c6f81d8742..0bbe3f38af 100644
--- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
@@ -176,7 +176,7 @@ namespace MediaBrowser.LocalMetadata.Images
"default"
};
- if (item is MusicAlbum || item is MusicArtist)
+ if (item is MusicAlbum || item is MusicArtist || item is Photo)
{
// these prefer folder
names.Insert(0, "poster");
diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
index b488741d15..a4d4797ebc 100644
--- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
@@ -19,38 +19,40 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
}
- protected override string GetCommandLineArguments(EncodingJob job)
+ protected override string GetCommandLineArguments(EncodingJob state)
{
var audioTranscodeParams = new List();
- var bitrate = job.OutputAudioBitrate;
+ var bitrate = state.OutputAudioBitrate;
if (bitrate.HasValue)
{
audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(UsCulture));
}
- if (job.OutputAudioChannels.HasValue)
+ if (state.OutputAudioChannels.HasValue)
{
- audioTranscodeParams.Add("-ac " + job.OutputAudioChannels.Value.ToString(UsCulture));
+ audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(UsCulture));
}
- if (job.OutputAudioSampleRate.HasValue)
+ if (state.OutputAudioSampleRate.HasValue)
{
- audioTranscodeParams.Add("-ar " + job.OutputAudioSampleRate.Value.ToString(UsCulture));
+ audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(UsCulture));
}
- var threads = GetNumberOfThreads(job, false);
+ const string vn = " -vn";
- var inputModifier = GetInputModifier(job);
+ var threads = GetNumberOfThreads(state, false);
+
+ var inputModifier = GetInputModifier(state);
return string.Format("{0} {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"",
inputModifier,
- GetInputArgument(job),
+ GetInputArgument(state),
threads,
- " -vn",
+ vn,
string.Join(" ", audioTranscodeParams.ToArray()),
- job.OutputFilePath).Trim();
+ state.OutputFilePath).Trim();
}
protected override string GetOutputFileExtension(EncodingJob state)
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
index 98e4a58a64..3a4a12b354 100644
--- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
@@ -303,15 +303,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
return job.Options.CpuCoreLimit ?? 0;
}
- protected string GetInputModifier(EncodingJob job, bool genPts = true)
+ protected string GetInputModifier(EncodingJob state, bool genPts = true)
{
var inputModifier = string.Empty;
- var probeSize = GetProbeSizeArgument(job);
+ var probeSize = GetProbeSizeArgument(state);
inputModifier += " " + probeSize;
inputModifier = inputModifier.Trim();
- var userAgentParam = GetUserAgentParam(job);
+ var userAgentParam = GetUserAgentParam(state);
if (!string.IsNullOrWhiteSpace(userAgentParam))
{
@@ -320,35 +320,43 @@ namespace MediaBrowser.MediaEncoding.Encoder
inputModifier = inputModifier.Trim();
- inputModifier += " " + GetFastSeekCommandLineParameter(job.Options);
+ inputModifier += " " + GetFastSeekCommandLineParameter(state.Options);
inputModifier = inputModifier.Trim();
- if (job.IsVideoRequest && genPts)
+ if (state.IsVideoRequest && genPts)
{
inputModifier += " -fflags +genpts";
}
- if (!string.IsNullOrEmpty(job.InputAudioSync))
+ if (!string.IsNullOrEmpty(state.InputAudioSync))
{
- inputModifier += " -async " + job.InputAudioSync;
+ inputModifier += " -async " + state.InputAudioSync;
}
- if (!string.IsNullOrEmpty(job.InputVideoSync))
+ if (!string.IsNullOrEmpty(state.InputVideoSync))
{
- inputModifier += " -vsync " + job.InputVideoSync;
+ inputModifier += " -vsync " + state.InputVideoSync;
}
- if (job.ReadInputAtNativeFramerate)
+ if (state.ReadInputAtNativeFramerate)
{
inputModifier += " -re";
}
- var videoDecoder = GetVideoDecoder(job);
+ var videoDecoder = GetVideoDecoder(state);
if (!string.IsNullOrWhiteSpace(videoDecoder))
{
inputModifier += " " + videoDecoder;
}
+ //if (state.IsVideoRequest)
+ //{
+ // if (string.Equals(state.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase))
+ // {
+ // //inputModifier += " -noaccurate_seek";
+ // }
+ //}
+
return inputModifier;
}
@@ -392,11 +400,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
return null;
}
- private string GetUserAgentParam(EncodingJob job)
+ private string GetUserAgentParam(EncodingJob state)
{
string useragent = null;
- job.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent);
+ state.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent);
if (!string.IsNullOrWhiteSpace(useragent))
{
@@ -409,31 +417,31 @@ namespace MediaBrowser.MediaEncoding.Encoder
///
/// Gets the probe size argument.
///
- /// The job.
+ /// The state.
/// System.String.
- private string GetProbeSizeArgument(EncodingJob job)
+ private string GetProbeSizeArgument(EncodingJob state)
{
- if (job.PlayableStreamFileNames.Count > 0)
+ if (state.PlayableStreamFileNames.Count > 0)
{
- return MediaEncoder.GetProbeSizeArgument(job.PlayableStreamFileNames.ToArray(), job.InputProtocol);
+ return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
}
- return MediaEncoder.GetProbeSizeArgument(new[] { job.MediaPath }, job.InputProtocol);
+ return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol);
}
///
/// Gets the fast seek command line parameter.
///
- /// The options.
+ /// The request.
/// System.String.
/// The fast seek command line parameter.
- protected string GetFastSeekCommandLineParameter(EncodingJobOptions options)
+ protected string GetFastSeekCommandLineParameter(EncodingJobOptions request)
{
- var time = options.StartTimeTicks;
+ var time = request.StartTimeTicks ?? 0;
- if (time.HasValue && time.Value > 0)
+ if (time > 0)
{
- return string.Format("-ss {0}", MediaEncoder.GetTimeParameter(time.Value));
+ return string.Format("-ss {0}", MediaEncoder.GetTimeParameter(time));
}
return string.Empty;
@@ -442,34 +450,35 @@ namespace MediaBrowser.MediaEncoding.Encoder
///
/// Gets the input argument.
///
- /// The job.
+ /// The state.
/// System.String.
- protected string GetInputArgument(EncodingJob job)
+ protected string GetInputArgument(EncodingJob state)
{
- var arg = "-i " + GetInputPathArgument(job);
+ var arg = string.Format("-i {0}", GetInputPathArgument(state));
- if (job.SubtitleStream != null)
+ if (state.SubtitleStream != null)
{
- if (job.SubtitleStream.IsExternal && !job.SubtitleStream.IsTextSubtitleStream)
+ if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
{
- arg += " -i \"" + job.SubtitleStream.Path + "\"";
+ arg += " -i \"" + state.SubtitleStream.Path + "\"";
}
}
- return arg;
+ return arg.Trim();
}
- private string GetInputPathArgument(EncodingJob job)
+ private string GetInputPathArgument(EncodingJob state)
{
- var protocol = job.InputProtocol;
+ var protocol = state.InputProtocol;
+ var mediaPath = state.MediaPath ?? string.Empty;
- var inputPath = new[] { job.MediaPath };
+ var inputPath = new[] { mediaPath };
- if (job.IsInputVideo)
+ if (state.IsInputVideo)
{
- if (!(job.VideoType == VideoType.Iso && job.IsoMount == null))
+ if (!(state.VideoType == VideoType.Iso && state.IsoMount == null))
{
- inputPath = MediaEncoderHelpers.GetInputArgument(FileSystem, job.MediaPath, job.InputProtocol, job.IsoMount, job.PlayableStreamFileNames);
+ inputPath = MediaEncoderHelpers.GetInputArgument(FileSystem, mediaPath, state.InputProtocol, state.IsoMount, state.PlayableStreamFileNames);
}
}
@@ -491,7 +500,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}, false, cancellationToken).ConfigureAwait(false);
- AttachMediaStreamInfo(state, liveStreamResponse.MediaSource, state.Options);
+ AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, state.Options);
if (state.IsVideoRequest)
{
@@ -505,11 +514,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- private void AttachMediaStreamInfo(EncodingJob state,
+ private void AttachMediaSourceInfo(EncodingJob state,
MediaSourceInfo mediaSource,
EncodingJobOptions videoRequest)
{
- EncodingJobFactory.AttachMediaStreamInfo(state, mediaSource, videoRequest);
+ EncodingJobFactory.AttachMediaSourceInfo(state, mediaSource, videoRequest);
}
///
@@ -572,7 +581,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
param = "-preset superfast";
- param += " -crf 28";
+ param += " -crf 23";
}
else if (string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase))
@@ -582,6 +591,19 @@ namespace MediaBrowser.MediaEncoding.Encoder
param += " -crf 28";
}
+ // h264 (h264_qsv)
+ else if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
+ {
+ param = "-preset 7 -look_ahead 0";
+
+ }
+
+ // h264 (libnvenc)
+ else if (string.Equals(videoCodec, "libnvenc", StringComparison.OrdinalIgnoreCase))
+ {
+ param = "-preset high-performance";
+ }
+
// webm
else if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
{
@@ -644,9 +666,53 @@ namespace MediaBrowser.MediaEncoding.Encoder
param += " -profile:v " + state.Options.Profile;
}
- if (state.Options.Level.HasValue)
+ var levelString = state.Options.Level.HasValue ? state.Options.Level.Value.ToString(CultureInfo.InvariantCulture) : null;
+
+ if (!string.IsNullOrEmpty(levelString))
{
- param += " -level " + state.Options.Level.Value.ToString(UsCulture);
+ var h264Encoder = EncodingJobFactory.GetH264Encoder(state, GetEncodingOptions());
+
+ // h264_qsv and libnvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
+ if (String.Equals(h264Encoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) || String.Equals(h264Encoder, "libnvenc", StringComparison.OrdinalIgnoreCase))
+ {
+ switch (levelString)
+ {
+ case "30":
+ param += " -level 3";
+ break;
+ case "31":
+ param += " -level 3.1";
+ break;
+ case "32":
+ param += " -level 3.2";
+ break;
+ case "40":
+ param += " -level 4";
+ break;
+ case "41":
+ param += " -level 4.1";
+ break;
+ case "42":
+ param += " -level 4.2";
+ break;
+ case "50":
+ param += " -level 5";
+ break;
+ case "51":
+ param += " -level 5.1";
+ break;
+ case "52":
+ param += " -level 5.2";
+ break;
+ default:
+ param += " -level " + levelString;
+ break;
+ }
+ }
+ else
+ {
+ param += " -level " + levelString;
+ }
}
return "-pix_fmt yuv420p " + param;
@@ -658,15 +724,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (bitrate.HasValue)
{
- var hasFixedResolution = state.Options.HasFixedResolution;
-
if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
{
- if (hasFixedResolution)
- {
- return string.Format(" -minrate:v ({0}*.90) -maxrate:v ({0}*1.10) -bufsize:v {0} -b:v {0}", bitrate.Value.ToString(UsCulture));
- }
-
// With vpx when crf is used, b:v becomes a max rate
// https://trac.ffmpeg.org/wiki/vpxEncodingGuide. But higher bitrate source files -b:v causes judder so limite the bitrate but dont allow it to "saturate" the bitrate. So dont contrain it down just up.
return string.Format(" -maxrate:v {0} -bufsize:v ({0}*2) -b:v {0}", bitrate.Value.ToString(UsCulture));
@@ -677,20 +736,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
}
- // H264
- if (hasFixedResolution)
+ // h264
+ if (isHls)
{
- if (isHls)
- {
- return string.Format(" -b:v {0} -maxrate ({0}*.80) -bufsize {0}", bitrate.Value.ToString(UsCulture));
- }
-
- return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
+ return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}",
+ bitrate.Value.ToString(UsCulture),
+ (bitrate.Value * 2).ToString(UsCulture));
}
- return string.Format(" -maxrate {0} -bufsize {1}",
- bitrate.Value.ToString(UsCulture),
- (bitrate.Value * 2).ToString(UsCulture));
+ return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
}
return string.Empty;
@@ -698,20 +752,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
protected double? GetFramerateParam(EncodingJob state)
{
- if (state.Options.Framerate.HasValue)
+ if (state.Options != null)
{
- return state.Options.Framerate.Value;
- }
-
- var maxrate = state.Options.MaxFramerate;
+ if (state.Options.Framerate.HasValue)
+ {
+ return state.Options.Framerate.Value;
+ }
- if (maxrate.HasValue && state.VideoStream != null)
- {
- var contentRate = state.VideoStream.AverageFrameRate ?? state.VideoStream.RealFrameRate;
+ var maxrate = state.Options.MaxFramerate;
- if (contentRate.HasValue && contentRate.Value > maxrate.Value)
+ if (maxrate.HasValue && state.VideoStream != null)
{
- return maxrate;
+ var contentRate = state.VideoStream.AverageFrameRate ?? state.VideoStream.RealFrameRate;
+
+ if (contentRate.HasValue && contentRate.Value > maxrate.Value)
+ {
+ return maxrate;
+ }
}
}
@@ -852,7 +909,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
- filters.Add(string.Format("scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam));
+ filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,{0})/2)*2:trunc(ow/dar/2)*2", maxWidthParam));
}
// If a max height was requested
@@ -863,6 +920,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
filters.Add(string.Format("scale=trunc(oh*a/2)*2:min(ih\\,{0})", maxHeightParam));
}
+ if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
+ {
+ if (filters.Count > 1)
+ {
+ //filters[filters.Count - 1] += ":flags=fast_bilinear";
+ }
+ }
+
var output = string.Empty;
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
@@ -917,8 +982,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
seconds.ToString(UsCulture));
}
+ var mediaPath = state.MediaPath ?? string.Empty;
+
return string.Format("subtitles='{0}:si={1}',setpts=PTS -{2}/TB",
- MediaEncoder.EscapeSubtitleFilterPath(state.MediaPath),
+ MediaEncoder.EscapeSubtitleFilterPath(mediaPath),
state.InternalSubtitleStreamOffset.ToString(UsCulture),
seconds.ToString(UsCulture));
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
index 9cdc4a7bf1..27072efe1b 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
@@ -10,6 +10,7 @@ using MediaBrowser.Model.MediaInfo;
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -66,38 +67,56 @@ namespace MediaBrowser.MediaEncoding.Encoder
? mediaSources.First()
: mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));
- AttachMediaStreamInfo(state, mediaSource, options);
+ var videoRequest = state.Options;
- state.OutputAudioBitrate = GetAudioBitrateParam(request, state.AudioStream);
+ AttachMediaSourceInfo(state, mediaSource, videoRequest);
+
+ //var container = Path.GetExtension(state.RequestedUrl);
+
+ //if (string.IsNullOrEmpty(container))
+ //{
+ // container = request.Static ?
+ // state.InputContainer :
+ // (Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.');
+ //}
+
+ //state.OutputContainer = (container ?? string.Empty).TrimStart('.');
+
+ state.OutputAudioBitrate = GetAudioBitrateParam(state.Options, state.AudioStream);
state.OutputAudioSampleRate = request.AudioSampleRate;
- state.OutputAudioCodec = GetAudioCodec(request);
+ state.OutputAudioCodec = state.Options.AudioCodec;
- state.OutputAudioChannels = GetNumAudioChannelsParam(request, state.AudioStream, state.OutputAudioCodec);
+ state.OutputAudioChannels = GetNumAudioChannelsParam(state.Options, state.AudioStream, state.OutputAudioCodec);
- if (isVideoRequest)
+ if (videoRequest != null)
{
- state.OutputVideoCodec = GetVideoCodec(request);
- state.OutputVideoBitrate = GetVideoBitrateParamValue(request, state.VideoStream);
+ state.OutputVideoCodec = state.Options.VideoCodec;
+ state.OutputVideoBitrate = GetVideoBitrateParamValue(state.Options, state.VideoStream);
if (state.OutputVideoBitrate.HasValue)
{
var resolution = ResolutionNormalizer.Normalize(
- state.VideoStream == null ? (int?)null : state.VideoStream.BitRate,
- state.OutputVideoBitrate.Value,
- state.VideoStream == null ? null : state.VideoStream.Codec,
+ state.VideoStream == null ? (int?)null : state.VideoStream.BitRate,
+ state.OutputVideoBitrate.Value,
+ state.VideoStream == null ? null : state.VideoStream.Codec,
state.OutputVideoCodec,
- request.MaxWidth,
- request.MaxHeight);
+ videoRequest.MaxWidth,
+ videoRequest.MaxHeight);
- request.MaxWidth = resolution.MaxWidth;
- request.MaxHeight = resolution.MaxHeight;
+ videoRequest.MaxWidth = resolution.MaxWidth;
+ videoRequest.MaxHeight = resolution.MaxHeight;
}
}
ApplyDeviceProfileSettings(state);
- TryStreamCopy(state, request);
+ if (videoRequest != null)
+ {
+ TryStreamCopy(state, videoRequest);
+ }
+
+ //state.OutputFilePath = GetOutputFilePath(state);
return state;
}
@@ -119,7 +138,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- internal static void AttachMediaStreamInfo(EncodingJob state,
+ internal static void AttachMediaSourceInfo(EncodingJob state,
MediaSourceInfo mediaSource,
EncodingJobOptions videoRequest)
{
@@ -131,11 +150,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.RunTimeTicks = mediaSource.RunTimeTicks;
state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
- if (mediaSource.ReadAtNativeFramerate)
- {
- state.ReadInputAtNativeFramerate = true;
- }
-
if (mediaSource.VideoType.HasValue)
{
state.VideoType = mediaSource.VideoType.Value;
@@ -156,6 +170,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
state.InputBitrate = mediaSource.Bitrate;
state.InputFileSize = mediaSource.Size;
+ state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
if (state.ReadInputAtNativeFramerate ||
mediaSource.Protocol == MediaProtocol.File && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase))
@@ -165,6 +180,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.InputAudioSync = "1";
}
+ if (string.Equals(mediaSource.Container, "wma", StringComparison.OrdinalIgnoreCase))
+ {
+ // Seeing some stuttering when transcoding wma to audio-only HLS
+ state.InputAudioSync = "1";
+ }
+
var mediaStreams = mediaSource.MediaStreams;
if (videoRequest != null)
@@ -210,19 +231,21 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// System.Nullable{VideoCodecs}.
private static string InferVideoCodec(string container)
{
- if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase))
+ var ext = "." + (container ?? string.Empty);
+
+ if (string.Equals(ext, ".asf", StringComparison.OrdinalIgnoreCase))
{
return "wmv";
}
- if (string.Equals(container, "webm", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
{
return "vpx";
}
- if (string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ogv", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
{
return "theora";
}
- if (string.Equals(container, "m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(ext, ".m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ts", StringComparison.OrdinalIgnoreCase))
{
return "h264";
}
@@ -232,35 +255,37 @@ namespace MediaBrowser.MediaEncoding.Encoder
private string InferAudioCodec(string container)
{
- if (string.Equals(container, "mp3", StringComparison.OrdinalIgnoreCase))
+ var ext = "." + (container ?? string.Empty);
+
+ if (string.Equals(ext, ".mp3", StringComparison.OrdinalIgnoreCase))
{
return "mp3";
}
- if (string.Equals(container, "aac", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase))
{
return "aac";
}
- if (string.Equals(container, "wma", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase))
{
return "wma";
}
- if (string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase))
{
return "vorbis";
}
- if (string.Equals(container, "oga", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase))
{
return "vorbis";
}
- if (string.Equals(container, "ogv", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
{
return "vorbis";
}
- if (string.Equals(container, "webm", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
{
return "vorbis";
}
- if (string.Equals(container, "webma", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase))
{
return "vorbis";
}
@@ -398,15 +423,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (bitrate.HasValue)
{
- var hasFixedResolution = state.Options.HasFixedResolution;
-
if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
{
- if (hasFixedResolution)
- {
- return string.Format(" -minrate:v ({0}*.90) -maxrate:v ({0}*1.10) -bufsize:v {0} -b:v {0}", bitrate.Value.ToString(UsCulture));
- }
-
// With vpx when crf is used, b:v becomes a max rate
// https://trac.ffmpeg.org/wiki/vpxEncodingGuide. But higher bitrate source files -b:v causes judder so limite the bitrate but dont allow it to "saturate" the bitrate. So dont contrain it down just up.
return string.Format(" -maxrate:v {0} -bufsize:v ({0}*2) -b:v {0}", bitrate.Value.ToString(UsCulture));
@@ -417,20 +435,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
}
- // H264
- if (hasFixedResolution)
+ // h264
+ if (isHls)
{
- if (isHls)
- {
- return string.Format(" -b:v {0} -maxrate ({0}*.80) -bufsize {0}", bitrate.Value.ToString(UsCulture));
- }
-
- return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
+ return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}",
+ bitrate.Value.ToString(UsCulture),
+ (bitrate.Value * 2).ToString(UsCulture));
}
- return string.Format(" -maxrate {0} -bufsize {1}",
- bitrate.Value.ToString(UsCulture),
- (bitrate.Value * 2).ToString(UsCulture));
+ return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
}
return string.Empty;
@@ -466,11 +479,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
///
/// Gets the name of the output audio codec
///
- /// The request.
+ /// The state.
/// System.String.
- private string GetAudioCodec(EncodingJobOptions request)
+ internal static string GetAudioEncoder(EncodingJob state)
{
- var codec = request.AudioCodec;
+ var codec = state.OutputAudioCodec;
if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase))
{
@@ -489,40 +502,56 @@ namespace MediaBrowser.MediaEncoding.Encoder
return "wmav2";
}
- return (codec ?? string.Empty).ToLower();
+ return codec.ToLower();
}
///
/// Gets the name of the output video codec
///
- /// The request.
+ /// The state.
+ /// The options.
/// System.String.
- private string GetVideoCodec(EncodingJobOptions request)
+ internal static string GetVideoEncoder(EncodingJob state, EncodingOptions options)
{
- var codec = request.VideoCodec;
+ var codec = state.OutputVideoCodec;
- if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
+ if (!string.IsNullOrEmpty(codec))
{
- return "libx264";
- }
- if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase))
- {
- return "libx265";
- }
- if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase))
- {
- return "libvpx";
- }
- if (string.Equals(codec, "wmv", StringComparison.OrdinalIgnoreCase))
- {
- return "wmv2";
+ if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
+ {
+ return GetH264Encoder(state, options);
+ }
+ if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase))
+ {
+ return "libvpx";
+ }
+ if (string.Equals(codec, "wmv", StringComparison.OrdinalIgnoreCase))
+ {
+ return "wmv2";
+ }
+ if (string.Equals(codec, "theora", StringComparison.OrdinalIgnoreCase))
+ {
+ return "libtheora";
+ }
+
+ return codec.ToLower();
}
- if (string.Equals(codec, "theora", StringComparison.OrdinalIgnoreCase))
+
+ return "copy";
+ }
+
+ internal static string GetH264Encoder(EncodingJob state, EncodingOptions options)
+ {
+ if (string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
{
- return "libtheora";
+ // It's currently failing on live tv
+ if (state.RunTimeTicks.HasValue)
+ {
+ return "h264_qsv";
+ }
}
- return (codec ?? string.Empty).ToLower();
+ return "libx264";
}
internal static bool CanStreamCopyVideo(EncodingJobOptions request, MediaStream videoStream)
diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
index 127145aec3..9d051b38b7 100644
--- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
@@ -21,14 +21,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
protected override string GetCommandLineArguments(EncodingJob state)
{
// Get the output codec name
- var videoCodec = state.OutputVideoCodec;
+ var videoCodec = EncodingJobFactory.GetVideoEncoder(state, GetEncodingOptions());
var format = string.Empty;
var keyFrame = string.Empty;
- if (string.Equals(Path.GetExtension(state.OutputFilePath), ".mp4", StringComparison.OrdinalIgnoreCase) &&
- state.Options.Context == EncodingContext.Streaming)
+ if (string.Equals(Path.GetExtension(state.OutputFilePath), ".mp4", StringComparison.OrdinalIgnoreCase))
{
+ // Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js
format = " -f mp4 -movflags frag_keyframe+empty_moov";
}
@@ -53,42 +53,49 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// Gets video arguments to pass to ffmpeg
///
/// The state.
- /// The video codec.
+ /// The video codec.
/// System.String.
- private string GetVideoArguments(EncodingJob state, string codec)
+ private string GetVideoArguments(EncodingJob state, string videoCodec)
{
- var args = "-codec:v:0 " + codec;
+ var args = "-codec:v:0 " + videoCodec;
if (state.EnableMpegtsM2TsMode)
{
args += " -mpegts_m2ts_mode 1";
}
- // See if we can save come cpu cycles by avoiding encoding
- if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
+ var isOutputMkv = string.Equals(state.Options.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase);
+
+ if (state.RunTimeTicks.HasValue)
{
- return state.VideoStream != null && IsH264(state.VideoStream) && string.Equals(state.Options.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) ?
- args + " -bsf:v h264_mp4toannexb" :
- args;
+ //args += " -copyts -avoid_negative_ts disabled -start_at_zero";
}
- if (state.Options.Context == EncodingContext.Streaming)
+ if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
- 5.ToString(UsCulture));
+ if (state.VideoStream != null && IsH264(state.VideoStream) &&
+ (string.Equals(state.Options.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) || isOutputMkv))
+ {
+ args += " -bsf:v h264_mp4toannexb";
+ }
- args += keyFrameArg;
+ return args;
}
+ var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
+ 5.ToString(UsCulture));
+
+ args += keyFrameArg;
+
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
// Add resolution params, if specified
if (!hasGraphicalSubs)
{
- args += GetOutputSizeParam(state, codec);
+ args += GetOutputSizeParam(state, videoCodec);
}
- var qualityParam = GetVideoQualityParam(state, codec, false);
+ var qualityParam = GetVideoQualityParam(state, videoCodec, false);
if (!string.IsNullOrEmpty(qualityParam))
{
@@ -98,7 +105,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
// This is for internal graphical subs
if (hasGraphicalSubs)
{
- args += GetGraphicalSubtitleParam(state, codec);
+ args += GetGraphicalSubtitleParam(state, videoCodec);
}
return args;
@@ -118,11 +125,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
// Get the output codec name
- var codec = state.OutputAudioCodec;
+ var codec = EncodingJobFactory.GetAudioEncoder(state);
var args = "-codec:a:0 " + codec;
- if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
{
return args;
}
diff --git a/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs b/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs
index dd6c77e66d..c4b96ea2ef 100644
--- a/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs
@@ -16,14 +16,12 @@ namespace MediaBrowser.Model.Configuration
public bool EnableIntrosFromUpcomingStreamingMovies { get; set; }
public int TrailerLimit { get; set; }
- public string[] Tags { get; set; }
public CinemaModeConfiguration()
{
EnableIntrosParentalControl = true;
EnableIntrosFromSimilarMovies = true;
TrailerLimit = 2;
- Tags = new[] { "thx" };
}
}
}
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 0b472ec223..3cb543e5d5 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -161,8 +161,6 @@ namespace MediaBrowser.Model.Configuration
///
/// The dashboard source path.
public string DashboardSourcePath { get; set; }
-
- public bool MergeMetadataAndImagesByName { get; set; }
///
/// Gets or sets the image saving convention.
diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
index 8897edcbdc..f09a8b3a7b 100644
--- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs
+++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
@@ -51,7 +51,7 @@ namespace MediaBrowser.Model.Dto
public string TranscodingUrl { get; set; }
public string TranscodingSubProtocol { get; set; }
public string TranscodingContainer { get; set; }
-
+
public MediaSourceInfo()
{
Formats = new List();
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index 32ea474258..64a0e6d5b2 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -375,7 +375,12 @@ namespace MediaBrowser.Providers.Manager
}
string filename;
- var folderName = item is MusicAlbum || item is MusicArtist ? "folder" : "poster";
+ var folderName = item is MusicAlbum ||
+ item is MusicArtist ||
+ item is PhotoAlbum ||
+ (saveLocally && _config.Configuration.ImageSavingConvention == ImageSavingConvention.Legacy) ?
+ "folder" :
+ "poster";
switch (type)
{
diff --git a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
index 8e934f348e..1a5c35df83 100644
--- a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
+++ b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
@@ -35,7 +35,6 @@ namespace MediaBrowser.Server.Implementations.Configuration
public ServerConfigurationManager(IApplicationPaths applicationPaths, ILogManager logManager, IXmlSerializer xmlSerializer, IFileSystem fileSystem)
: base(applicationPaths, logManager, xmlSerializer, fileSystem)
{
- UpdateItemsByNamePath();
UpdateMetadataPath();
}
@@ -73,7 +72,6 @@ namespace MediaBrowser.Server.Implementations.Configuration
///
protected override void OnConfigurationUpdated()
{
- UpdateItemsByNamePath();
UpdateMetadataPath();
base.OnConfigurationUpdated();
@@ -86,19 +84,6 @@ namespace MediaBrowser.Server.Implementations.Configuration
UpdateTranscodingTempPath();
}
- ///
- /// Updates the items by name path.
- ///
- private void UpdateItemsByNamePath()
- {
- if (!Configuration.MergeMetadataAndImagesByName)
- {
- ((ServerApplicationPaths)ApplicationPaths).ItemsByNamePath = string.IsNullOrEmpty(Configuration.ItemsByNamePath) ?
- null :
- Configuration.ItemsByNamePath;
- }
- }
-
///
/// Updates the metadata path.
///
diff --git a/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs b/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
index edc329ec42..5b72860b6e 100644
--- a/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
+++ b/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
@@ -17,6 +17,7 @@ using System.Threading;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Common.IO;
+using MoreLinq;
namespace MediaBrowser.Server.Implementations.Intros
{
@@ -28,8 +29,9 @@ namespace MediaBrowser.Server.Implementations.Intros
private readonly IConfigurationManager _serverConfig;
private readonly ILibraryManager _libraryManager;
private readonly IFileSystem _fileSystem;
+ private readonly IMediaSourceManager _mediaSourceManager;
- public DefaultIntroProvider(ISecurityManager security, IChannelManager channelManager, ILocalizationManager localization, IConfigurationManager serverConfig, ILibraryManager libraryManager, IFileSystem fileSystem)
+ public DefaultIntroProvider(ISecurityManager security, IChannelManager channelManager, ILocalizationManager localization, IConfigurationManager serverConfig, ILibraryManager libraryManager, IFileSystem fileSystem, IMediaSourceManager mediaSourceManager)
{
_security = security;
_channelManager = channelManager;
@@ -37,6 +39,7 @@ namespace MediaBrowser.Server.Implementations.Intros
_serverConfig = serverConfig;
_libraryManager = libraryManager;
_fileSystem = fileSystem;
+ _mediaSourceManager = mediaSourceManager;
}
public async Task> GetIntros(BaseItem item, User user)
@@ -82,7 +85,7 @@ namespace MediaBrowser.Server.Implementations.Intros
{
IncludeItemTypes = new[] { typeof(Movie).Name }
- }, new string[]{});
+ }, new string[] { });
var itemsWithTrailers = inputItems
.Where(i =>
@@ -164,6 +167,10 @@ namespace MediaBrowser.Server.Implementations.Intros
GetCustomIntros(config) :
new List();
+ var mediaInfoIntros = !string.IsNullOrWhiteSpace(config.MediaInfoIntroPath) ?
+ GetMediaInfoIntros(config, item) :
+ new List();
+
var trailerLimit = config.TrailerLimit;
// Avoid implicitly captured closure
@@ -185,7 +192,8 @@ namespace MediaBrowser.Server.Implementations.Intros
.ThenByDescending(i => (i.IsPlayed ? 0 : 1))
.Select(i => i.IntroInfo)
.Take(trailerLimit)
- .Concat(customIntros.Take(1));
+ .Concat(customIntros.Take(1))
+ .Concat(mediaInfoIntros);
}
private bool IsDuplicate(BaseItem playingContent, BaseItem test)
@@ -228,6 +236,134 @@ namespace MediaBrowser.Server.Implementations.Intros
}
}
+ private IEnumerable GetMediaInfoIntros(CinemaModeConfiguration options, BaseItem item)
+ {
+ try
+ {
+ var hasMediaSources = item as IHasMediaSources;
+
+ if (hasMediaSources == null)
+ {
+ return new List();
+ }
+
+ var mediaSource = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false)
+ .FirstOrDefault();
+
+ if (mediaSource == null)
+ {
+ return new List();
+ }
+
+ var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
+ var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
+
+ var allIntros = GetCustomIntroFiles(options, false, true)
+ .OrderBy(i => Guid.NewGuid())
+ .Select(i => new IntroInfo
+ {
+ Path = i
+
+ }).ToList();
+
+ var returnResult = new List();
+
+ if (videoStream != null)
+ {
+ returnResult.AddRange(GetMediaInfoIntrosByVideoStream(allIntros, videoStream).Take(1));
+ }
+
+ if (audioStream != null)
+ {
+ returnResult.AddRange(GetMediaInfoIntrosByAudioStream(allIntros, audioStream).Take(1));
+ }
+
+ returnResult.AddRange(GetMediaInfoIntrosByTags(allIntros, item.Tags).Take(1));
+
+ return returnResult.DistinctBy(i => i.Path, StringComparer.OrdinalIgnoreCase);
+ }
+ catch (IOException)
+ {
+ return new List();
+ }
+ }
+
+ private IEnumerable GetMediaInfoIntrosByVideoStream(List allIntros, MediaStream stream)
+ {
+ var codec = stream.Codec;
+
+ if (string.IsNullOrWhiteSpace(codec))
+ {
+ return new List();
+ }
+
+ return allIntros
+ .Where(i => IsMatch(i.Path, codec));
+ }
+
+ private IEnumerable GetMediaInfoIntrosByAudioStream(List allIntros, MediaStream stream)
+ {
+ var codec = stream.Codec;
+
+ if (string.IsNullOrWhiteSpace(codec))
+ {
+ return new List();
+ }
+
+ return allIntros
+ .Where(i => IsAudioMatch(i.Path, stream));
+ }
+
+ private IEnumerable GetMediaInfoIntrosByTags(List allIntros, List tags)
+ {
+ return allIntros
+ .Where(i => tags.Any(t => IsMatch(i.Path, t)));
+ }
+
+ private bool IsMatch(string file, string attribute)
+ {
+ var filename = Path.GetFileNameWithoutExtension(file) ?? string.Empty;
+ filename = Normalize(filename);
+
+ if (string.IsNullOrWhiteSpace(filename))
+ {
+ return false;
+ }
+
+ attribute = Normalize(attribute);
+ if (string.IsNullOrWhiteSpace(attribute))
+ {
+ return false;
+ }
+
+ return string.Equals(filename, attribute, StringComparison.OrdinalIgnoreCase);
+ }
+
+ private string Normalize(string value)
+ {
+ return value;
+ }
+
+ private bool IsAudioMatch(string path, MediaStream stream)
+ {
+ if (!string.IsNullOrWhiteSpace(stream.Codec))
+ {
+ if (IsMatch(path, stream.Codec))
+ {
+ return true;
+ }
+ }
+ if (!string.IsNullOrWhiteSpace(stream.Profile))
+ {
+ if (IsMatch(path, stream.Profile))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private IEnumerable GetCustomIntroFiles(CinemaModeConfiguration options, bool enableCustomIntros, bool enableMediaInfoIntros)
{
var list = new List();
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index df0f0045e3..e4cb58346a 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -1536,6 +1536,10 @@ namespace MediaBrowser.Server.Implementations.Library
{
video = dbItem;
}
+ else
+ {
+ return null;
+ }
}
}
catch (Exception ex)
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index cd91684ce1..ee16141042 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -742,7 +742,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
try
{
- var result = await GetChannelStreamInternal(timer.ChannelId, null, CancellationToken.None);
+ var result = await GetChannelStreamInternal(timer.ChannelId, null, CancellationToken.None).ConfigureAwait(false);
var mediaStreamInfo = result.Item1;
var isResourceOpen = true;
@@ -771,14 +771,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
httpRequestOptions.CancellationToken = linkedToken;
_logger.Info("Writing file to path: " + recordPath);
- using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET"))
+ _logger.Info("Opening recording stream from tuner provider");
+ using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET").ConfigureAwait(false))
{
+ _logger.Info("Opened recording stream from tuner provider");
+
using (var output = _fileSystem.GetFileStream(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
result.Item2.Release();
isResourceOpen = false;
- await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken);
+ _logger.Info("Copying recording stream to file stream");
+
+ await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken).ConfigureAwait(false);
}
}
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/de.json b/MediaBrowser.Server.Implementations/Localization/Core/de.json
index f948bc3dcf..30e3d9215e 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/de.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/de.json
@@ -1,5 +1,5 @@
{
- "DbUpgradeMessage": "Please wait while your Emby Server database is upgraded. {0}% complete.",
+ "DbUpgradeMessage": "Bitte warten Sie w\u00e4hrend die Emby Datenbank aktualisiert wird. {0}% verarbeitet.",
"AppDeviceValues": "App: {0}, Ger\u00e4t: {1}",
"UserDownloadingItemWithValues": "{0} l\u00e4dt {1} herunter",
"FolderTypeMixed": "Gemischte Inhalte",
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/es-MX.json b/MediaBrowser.Server.Implementations/Localization/Core/es-MX.json
index c510f30e24..630c7a0379 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/es-MX.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/es-MX.json
@@ -1,5 +1,5 @@
{
- "DbUpgradeMessage": "Please wait while your Emby Server database is upgraded. {0}% complete.",
+ "DbUpgradeMessage": "Por favor espere mientras la base de datos de su Servidor Emby es actualizada. {0}% completo.",
"AppDeviceValues": "App: {0}, Dispositivo: {1}",
"UserDownloadingItemWithValues": "{0} esta descargando {1}",
"FolderTypeMixed": "Contenido mezclado",
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/fr.json b/MediaBrowser.Server.Implementations/Localization/Core/fr.json
index 2ef9fc53c0..25c722989c 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/fr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/fr.json
@@ -1,5 +1,5 @@
{
- "DbUpgradeMessage": "Please wait while your Emby Server database is upgraded. {0}% complete.",
+ "DbUpgradeMessage": "Veuillez patienter pendant que la base de donn\u00e9e de votre Emby Serveur se met \u00e0 jour. Termin\u00e9e \u00e0 {0}%.",
"AppDeviceValues": "Application : {0}, Appareil: {1}",
"UserDownloadingItemWithValues": "{0} est en train de t\u00e9l\u00e9charger {1}",
"FolderTypeMixed": "Contenus m\u00e9lang\u00e9s",
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/kk.json b/MediaBrowser.Server.Implementations/Localization/Core/kk.json
index 654287d454..93252c30b8 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/kk.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/kk.json
@@ -1,5 +1,5 @@
{
- "DbUpgradeMessage": "Please wait while your Emby Server database is upgraded. {0}% complete.",
+ "DbUpgradeMessage": "Emby Server \u0434\u0435\u0440\u0435\u043a\u049b\u043e\u0440\u044b\u04a3\u044b\u0437\u0434\u044b\u04a3 \u0436\u0430\u04a3\u0493\u044b\u0440\u0442\u044b\u043b\u0443\u044b\u043d \u043a\u04af\u0442\u0435 \u0442\u04b1\u0440\u044b\u04a3\u044b\u0437. {0} % \u0430\u044f\u049b\u0442\u0430\u043b\u0434\u044b.",
"AppDeviceValues": "\u049a\u043e\u043b\u0434\u0430\u043d\u0431\u0430: {0}, \u049a\u04b1\u0440\u044b\u043b\u0493\u044b: {1}",
"UserDownloadingItemWithValues": "{0} \u043c\u044b\u043d\u0430\u043d\u044b \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443\u0434\u0430: {1}",
"FolderTypeMixed": "\u0410\u0440\u0430\u043b\u0430\u0441 \u043c\u0430\u0437\u043c\u04b1\u043d",
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/nl.json b/MediaBrowser.Server.Implementations/Localization/Core/nl.json
index 0533821142..a83182ee8d 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/nl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/nl.json
@@ -1,5 +1,5 @@
{
- "DbUpgradeMessage": "Please wait while your Emby Server database is upgraded. {0}% complete.",
+ "DbUpgradeMessage": "Even geduld svp terwijl de Emby Server database ge-upgrade wordt. {0}% gereed.",
"AppDeviceValues": "App: {0}, Apparaat: {1}",
"UserDownloadingItemWithValues": "{0} download {1}",
"FolderTypeMixed": "Gemengde inhoud",
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/pt-BR.json b/MediaBrowser.Server.Implementations/Localization/Core/pt-BR.json
index a2d5ccf61e..b714fd44c4 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/pt-BR.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/pt-BR.json
@@ -1,5 +1,5 @@
{
- "DbUpgradeMessage": "Please wait while your Emby Server database is upgraded. {0}% complete.",
+ "DbUpgradeMessage": "Por favor, aguarde enquanto a base de dados do Servidor Emby \u00e9 atualizada. {0}% completado.",
"AppDeviceValues": "App: {0}, Dispositivo: {1}",
"UserDownloadingItemWithValues": "{0} est\u00e1 fazendo download de {1}",
"FolderTypeMixed": "Conte\u00fado misto",
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/ru.json b/MediaBrowser.Server.Implementations/Localization/Core/ru.json
index 6f2997ffa5..0aacc53621 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ru.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ru.json
@@ -1,5 +1,5 @@
{
- "DbUpgradeMessage": "Please wait while your Emby Server database is upgraded. {0}% complete.",
+ "DbUpgradeMessage": "\u041f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435, \u043f\u043e\u043a\u0430 \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0432\u0430\u0448\u0435\u043c Emby Server \u043c\u043e\u0434\u0435\u0440\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f. {0} % \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e.",
"AppDeviceValues": "\u041f\u0440\u0438\u043b.: {0}, \u0423\u0441\u0442\u0440.: {1}",
"UserDownloadingItemWithValues": "{0} \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 {1}",
"FolderTypeMixed": "\u0420\u0430\u0437\u043d\u043e\u0442\u0438\u043f\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435",
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
index efd37fa00e..456a1fcc12 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
@@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Server.Implementations.Sync
{
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 12cd5c385b..227026154c 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -356,6 +356,11 @@ namespace MediaBrowser.WebDashboard.Api
DeleteFoldersByName(Path.Combine(bowerPath, "Sortable"), "st");
DeleteFoldersByName(Path.Combine(bowerPath, "Swiper"), "src");
+ _fileSystem.DeleteDirectory(Path.Combine(bowerPath, "marked"), true);
+ _fileSystem.DeleteDirectory(Path.Combine(bowerPath, "marked-element"), true);
+ _fileSystem.DeleteDirectory(Path.Combine(bowerPath, "prism"), true);
+ _fileSystem.DeleteDirectory(Path.Combine(bowerPath, "prism-element"), true);
+
if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
{
// Delete things that are unneeded in an attempt to keep the output as trim as possible
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 1657922919..efb2d4b690 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -107,6 +107,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
@@ -161,9 +164,6 @@
PreserveNewest
-
- PreserveNewest
-
PreserveNewest