apply codec profile conditions

This commit is contained in:
Luke Pulverenti 2014-03-24 13:54:45 -04:00
parent 501dedb13c
commit a94a98dc6c
15 changed files with 270 additions and 82 deletions

View file

@ -211,12 +211,7 @@ namespace MediaBrowser.Api
private void UpdateItem(BaseItemDto request, BaseItem item) private void UpdateItem(BaseItemDto request, BaseItem item)
{ {
item.Name = request.Name; item.Name = request.Name;
item.ForcedSortName = request.ForcedSortName;
// Only set the forced value if they changed it, or there's already one
if (!string.Equals(item.SortName, request.SortName) || !string.IsNullOrEmpty(item.ForcedSortName))
{
item.ForcedSortName = request.SortName;
}
var hasBudget = item as IHasBudget; var hasBudget = item as IHasBudget;
if (hasBudget != null) if (hasBudget != null)

View file

@ -1168,18 +1168,23 @@ namespace MediaBrowser.Api.Playback
protected double? GetFramerateParam(StreamState state) protected double? GetFramerateParam(StreamState state)
{ {
if (state.VideoRequest != null && state.VideoRequest.Framerate.HasValue) if (state.VideoRequest != null)
{ {
return state.VideoRequest.Framerate.Value; if (state.VideoRequest.Framerate.HasValue)
}
if (state.VideoStream != null)
{
var contentRate = state.VideoStream.AverageFrameRate ?? state.VideoStream.RealFrameRate;
if (contentRate.HasValue && contentRate.Value > 23.976)
{ {
return 23.976; return state.VideoRequest.Framerate.Value;
}
var maxrate = state.VideoRequest.MaxFramerate ?? 23.976;
if (state.VideoStream != null)
{
var contentRate = state.VideoStream.AverageFrameRate ?? state.VideoStream.RealFrameRate;
if (contentRate.HasValue && contentRate.Value > maxrate)
{
return maxrate;
}
} }
} }
@ -1265,17 +1270,38 @@ namespace MediaBrowser.Api.Playback
{ {
if (videoRequest != null) if (videoRequest != null)
{ {
request.StartTimeTicks = long.Parse(val, UsCulture); videoRequest.MaxWidth = int.Parse(val, UsCulture);
} }
} }
else if (i == 12) else if (i == 12)
{ {
if (videoRequest != null) if (videoRequest != null)
{ {
videoRequest.Profile = val; videoRequest.MaxHeight = int.Parse(val, UsCulture);
} }
} }
else if (i == 13) else if (i == 13)
{
if (videoRequest != null)
{
videoRequest.Framerate = int.Parse(val, UsCulture);
}
}
else if (i == 14)
{
if (videoRequest != null)
{
request.StartTimeTicks = long.Parse(val, UsCulture);
}
}
else if (i == 15)
{
if (videoRequest != null)
{
videoRequest.Profile = val;
}
}
else if (i == 16)
{ {
if (videoRequest != null) if (videoRequest != null)
{ {

View file

@ -145,6 +145,9 @@ namespace MediaBrowser.Api.Playback
[ApiMember(Name = "Framerate", Description = "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", IsRequired = false, DataType = "double", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "Framerate", Description = "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", IsRequired = false, DataType = "double", ParameterType = "query", Verb = "GET")]
public double? Framerate { get; set; } public double? Framerate { get; set; }
[ApiMember(Name = "MaxFramerate", Description = "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", IsRequired = false, DataType = "double", ParameterType = "query", Verb = "GET")]
public double? MaxFramerate { get; set; }
/// <summary> /// <summary>
/// Gets or sets the profile. /// Gets or sets the profile.
/// </summary> /// </summary>

View file

@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace MediaBrowser.Controller.Dlna namespace MediaBrowser.Controller.Dlna
@ -18,6 +19,13 @@ namespace MediaBrowser.Controller.Dlna
{ {
return (Codec ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); return (Codec ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
} }
public bool ContainsCodec(string codec)
{
var codecs = GetCodecs();
return codecs.Count == 0 || codecs.Contains(codec, StringComparer.OrdinalIgnoreCase);
}
} }
public enum CodecType public enum CodecType

View file

@ -32,9 +32,7 @@ namespace MediaBrowser.Controller.Dlna
public enum TranscodingSettingType public enum TranscodingSettingType
{ {
VideoLevel = 0, VideoProfile = 0
VideoProfile = 1,
MaxAudioChannels = 2
} }
public enum TranscodeSeekInfo public enum TranscodeSeekInfo

View file

@ -34,7 +34,20 @@ namespace MediaBrowser.Dlna.PlayTo
public int? SubtitleStreamIndex { get; set; } public int? SubtitleStreamIndex { get; set; }
public string DeviceProfileName { get; set; } public string DeviceProfileName { get; set; }
public int? MaxAudioChannels { get; set; }
public int? AudioBitrate { get; set; }
public int? VideoBitrate { get; set; }
public int? VideoLevel { get; set; }
public int? MaxWidth { get; set; }
public int? MaxHeight { get; set; }
public int? MaxFramerate { get; set; }
public PlaylistItem() public PlaylistItem()
{ {
TranscodingSettings = new List<TranscodingSetting>(); TranscodingSettings = new List<TranscodingSetting>();

View file

@ -24,13 +24,16 @@ namespace MediaBrowser.Dlna.PlayTo
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
if (profile.CodecProfiles.Where(i => i.Type == CodecType.AudioCodec) var directPlay = profile.DirectPlayProfiles
.All(i => IsCodecProfileSupported(i, item.Path, null, audioStream))) .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, audioStream));
{
var directPlay = profile.DirectPlayProfiles
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, audioStream));
if (directPlay != null) if (directPlay != null)
{
var audioCodec = audioStream == null ? null : audioStream.Codec;
// Make sure audio codec profiles are satisfied
if (!string.IsNullOrEmpty(audioCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.AudioCodec && i.ContainsCodec(audioCodec))
.All(i => AreConditionsSatisfied(i.Conditions, item.Path, null, audioStream)))
{ {
playlistItem.Transcode = false; playlistItem.Transcode = false;
playlistItem.Container = Path.GetExtension(item.Path); playlistItem.Container = Path.GetExtension(item.Path);
@ -48,8 +51,15 @@ namespace MediaBrowser.Dlna.PlayTo
playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList(); playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList();
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.'); playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
playlistItem.AudioCodec = transcodingProfile.AudioCodec; playlistItem.AudioCodec = transcodingProfile.AudioCodec;
var audioTranscodingConditions = profile.CodecProfiles
.Where(i => i.Type == CodecType.AudioCodec && i.ContainsCodec(transcodingProfile.AudioCodec))
.Take(1)
.SelectMany(i => i.Conditions);
ApplyTranscodingConditions(playlistItem, audioTranscodingConditions);
} }
return playlistItem; return playlistItem;
} }
@ -81,7 +91,7 @@ namespace MediaBrowser.Dlna.PlayTo
playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList(); playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList();
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.'); playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
} }
return playlistItem; return playlistItem;
} }
@ -96,18 +106,28 @@ namespace MediaBrowser.Dlna.PlayTo
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
if (profile.CodecProfiles.Where(i => i.Type == CodecType.VideoCodec || i.Type == CodecType.VideoAudioCodec) var directPlay = profile.DirectPlayProfiles
.All(i => IsCodecProfileSupported(i, item.Path, videoStream, audioStream))) .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, videoStream, audioStream));
if (directPlay != null)
{ {
var directPlay = profile.DirectPlayProfiles var videoCodec = videoStream == null ? null : videoStream.Codec;
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, videoStream, audioStream));
if (directPlay != null) // Make sure video codec profiles are satisfied
if (!string.IsNullOrEmpty(videoCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.VideoCodec && i.ContainsCodec(videoCodec))
.All(i => AreConditionsSatisfied(i.Conditions, item.Path, videoStream, audioStream)))
{ {
playlistItem.Transcode = false; var audioCodec = audioStream == null ? null : audioStream.Codec;
playlistItem.Container = Path.GetExtension(item.Path);
return playlistItem; // Make sure audio codec profiles are satisfied
if (string.IsNullOrEmpty(audioCodec) || profile.CodecProfiles.Where(i => i.Type == CodecType.VideoAudioCodec && i.ContainsCodec(audioCodec))
.All(i => AreConditionsSatisfied(i.Conditions, item.Path, videoStream, audioStream)))
{
playlistItem.Transcode = false;
playlistItem.Container = Path.GetExtension(item.Path);
return playlistItem;
}
} }
} }
@ -121,11 +141,113 @@ namespace MediaBrowser.Dlna.PlayTo
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.'); playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',').FirstOrDefault(); playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',').FirstOrDefault();
playlistItem.VideoCodec = transcodingProfile.VideoCodec; playlistItem.VideoCodec = transcodingProfile.VideoCodec;
var videoTranscodingConditions = profile.CodecProfiles
.Where(i => i.Type == CodecType.VideoCodec && i.ContainsCodec(transcodingProfile.VideoCodec))
.Take(1)
.SelectMany(i => i.Conditions);
ApplyTranscodingConditions(playlistItem, videoTranscodingConditions);
var audioTranscodingConditions = profile.CodecProfiles
.Where(i => i.Type == CodecType.VideoAudioCodec && i.ContainsCodec(transcodingProfile.AudioCodec))
.Take(1)
.SelectMany(i => i.Conditions);
ApplyTranscodingConditions(playlistItem, audioTranscodingConditions);
} }
return playlistItem; return playlistItem;
} }
private void ApplyTranscodingConditions(PlaylistItem item, IEnumerable<ProfileCondition> conditions)
{
foreach (var condition in conditions.Where(i => !string.IsNullOrEmpty(i.Value)))
{
var value = condition.Value;
switch (condition.Property)
{
case ProfileConditionValue.AudioBitrate:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.AudioBitrate = num;
}
break;
}
case ProfileConditionValue.AudioChannels:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.MaxAudioChannels = num;
}
break;
}
case ProfileConditionValue.Filesize:
case ProfileConditionValue.AudioProfile:
case ProfileConditionValue.Has64BitOffsets:
case ProfileConditionValue.VideoBitDepth:
case ProfileConditionValue.VideoPacketLength:
case ProfileConditionValue.VideoProfile:
case ProfileConditionValue.VideoTimestamp:
{
// Not supported yet
break;
}
case ProfileConditionValue.Height:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.MaxHeight = num;
}
break;
}
case ProfileConditionValue.VideoBitrate:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.VideoBitrate = num;
}
break;
}
case ProfileConditionValue.VideoFramerate:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.MaxFramerate = num;
}
break;
}
case ProfileConditionValue.VideoLevel:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.VideoLevel = num;
}
break;
}
case ProfileConditionValue.Width:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.MaxWidth = num;
}
break;
}
default:
throw new ArgumentException("Unrecognized ProfileConditionValue");
}
}
}
private bool IsSupported(DirectPlayProfile profile, Photo item) private bool IsSupported(DirectPlayProfile profile, Photo item)
{ {
var mediaPath = item.Path; var mediaPath = item.Path;
@ -142,7 +264,7 @@ namespace MediaBrowser.Dlna.PlayTo
return true; return true;
} }
private bool IsSupported(DirectPlayProfile profile, Audio item, MediaStream audioStream) private bool IsSupported(DirectPlayProfile profile, Audio item, MediaStream audioStream)
{ {
var mediaPath = item.Path; var mediaPath = item.Path;
@ -222,22 +344,9 @@ namespace MediaBrowser.Dlna.PlayTo
return true; return true;
} }
private bool IsCodecProfileSupported(CodecProfile profile, string mediaPath, MediaStream videoStream, MediaStream audioStream) private bool AreConditionsSatisfied(IEnumerable<ProfileCondition> conditions, string mediaPath, MediaStream videoStream, MediaStream audioStream)
{ {
var codecs = profile.GetCodecs(); return conditions.All(i => IsConditionSatisfied(i, mediaPath, videoStream, audioStream));
var stream = profile.Type == CodecType.VideoCodec ? videoStream : audioStream;
var existingCodec = (stream == null ? null : stream.Codec) ?? string.Empty;
if (codecs.Count == 0 || codecs.Contains(existingCodec, StringComparer.OrdinalIgnoreCase))
{
// Check additional conditions
if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, videoStream, audioStream)))
{
return false;
}
}
return true;
} }
/// <summary> /// <summary>

View file

@ -18,7 +18,7 @@ namespace MediaBrowser.Dlna.PlayTo
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
internal static string GetAudioUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress) internal static string GetAudioUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress)
{ {
var dlnaCommand = BuildDlnaUrl(item.DeviceProfileName, item.MediaSourceId, deviceProperties.UUID, !item.Transcode, null, item.AudioCodec, item.AudioStreamIndex, item.SubtitleStreamIndex, null, 128000, item.StartPositionTicks, item.TranscodingSettings); var dlnaCommand = BuildDlnaUrl(deviceProperties, item);
return string.Format("{0}/audio/{1}/stream{2}?{3}", serverAddress, item.ItemId, "." + item.Container.TrimStart('.'), dlnaCommand); return string.Format("{0}/audio/{1}/stream{2}?{3}", serverAddress, item.ItemId, "." + item.Container.TrimStart('.'), dlnaCommand);
} }
@ -33,7 +33,7 @@ namespace MediaBrowser.Dlna.PlayTo
/// <returns>The url to send to the device</returns> /// <returns>The url to send to the device</returns>
internal static string GetVideoUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress) internal static string GetVideoUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress)
{ {
var dlnaCommand = BuildDlnaUrl(item.DeviceProfileName, item.MediaSourceId, deviceProperties.UUID, !item.Transcode, item.VideoCodec, item.AudioCodec, item.AudioStreamIndex, item.SubtitleStreamIndex, 1500000, 128000, item.StartPositionTicks, item.TranscodingSettings); var dlnaCommand = BuildDlnaUrl(deviceProperties, item);
return string.Format("{0}/Videos/{1}/stream{2}?{3}", serverAddress, item.ItemId, item.Container, dlnaCommand); return string.Format("{0}/Videos/{1}/stream{2}?{3}", serverAddress, item.ItemId, item.Container, dlnaCommand);
} }
@ -41,30 +41,33 @@ namespace MediaBrowser.Dlna.PlayTo
/// <summary> /// <summary>
/// Builds the dlna URL. /// Builds the dlna URL.
/// </summary> /// </summary>
private static string BuildDlnaUrl(string deviceProfileName, string mediaSourceId, string deviceID, bool isStatic, string videoCodec, string audioCodec, int? audiostreamIndex, int? subtitleIndex, int? videoBitrate, int? audioBitrate, long? startPositionTicks, List<TranscodingSetting> settings) private static string BuildDlnaUrl(DeviceInfo deviceProperties, PlaylistItem item)
{ {
var profile = settings.Where(i => i.Name == TranscodingSettingType.VideoProfile).Select(i => i.Value).FirstOrDefault(); var profile = item.TranscodingSettings.Where(i => i.Name == TranscodingSettingType.VideoProfile)
var videoLevel = settings.Where(i => i.Name == TranscodingSettingType.VideoLevel).Select(i => i.Value).FirstOrDefault(); .Select(i => i.Value)
var maxAudioChannels = settings.Where(i => i.Name == TranscodingSettingType.MaxAudioChannels).Select(i => i.Value).FirstOrDefault(); .FirstOrDefault();
var usCulture = new CultureInfo("en-US"); var usCulture = new CultureInfo("en-US");
var list = new List<string> var list = new List<string>
{ {
deviceProfileName ?? string.Empty, item.DeviceProfileName ?? string.Empty,
deviceID ?? string.Empty, deviceProperties.UUID ?? string.Empty,
mediaSourceId ?? string.Empty, item.MediaSourceId ?? string.Empty,
isStatic.ToString().ToLower(), (!item.Transcode).ToString().ToLower(),
videoCodec ?? string.Empty, item.VideoCodec ?? string.Empty,
audioCodec ?? string.Empty, item.AudioCodec ?? string.Empty,
audiostreamIndex.HasValue ? audiostreamIndex.Value.ToString(usCulture) : string.Empty, item.AudioStreamIndex.HasValue ? item.AudioStreamIndex.Value.ToString(usCulture) : string.Empty,
subtitleIndex.HasValue ? subtitleIndex.Value.ToString(usCulture) : string.Empty, item.SubtitleStreamIndex.HasValue ? item.SubtitleStreamIndex.Value.ToString(usCulture) : string.Empty,
videoBitrate.HasValue ? videoBitrate.Value.ToString(usCulture) : string.Empty, item.VideoBitrate.HasValue ? item.VideoBitrate.Value.ToString(usCulture) : string.Empty,
audioBitrate.HasValue ? audioBitrate.Value.ToString(usCulture) : string.Empty, item.AudioBitrate.HasValue ? item.AudioBitrate.Value.ToString(usCulture) : string.Empty,
maxAudioChannels ?? string.Empty, item.MaxAudioChannels.HasValue ? item.MaxAudioChannels.Value.ToString(usCulture) : string.Empty,
startPositionTicks.HasValue ? startPositionTicks.Value.ToString(usCulture) : string.Empty, item.MaxFramerate.HasValue ? item.MaxFramerate.Value.ToString(usCulture) : string.Empty,
item.MaxWidth.HasValue ? item.MaxWidth.Value.ToString(usCulture) : string.Empty,
item.MaxHeight.HasValue ? item.MaxHeight.Value.ToString(usCulture) : string.Empty,
item.StartPositionTicks.ToString(usCulture),
profile ?? string.Empty, profile ?? string.Empty,
videoLevel ?? string.Empty item.VideoLevel.HasValue ? item.VideoLevel.Value.ToString(usCulture) : string.Empty
}; };
return string.Format("Params={0}", string.Join(";", list.ToArray())); return string.Format("Params={0}", string.Join(";", list.ToArray()));

View file

@ -34,7 +34,6 @@ namespace MediaBrowser.Dlna.Profiles
Settings = new [] Settings = new []
{ {
new TranscodingSetting {Name = TranscodingSettingType.VideoLevel, Value = "3"},
new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"} new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"}
} }
} }
@ -54,6 +53,24 @@ namespace MediaBrowser.Dlna.Profiles
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
} }
}; };
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.VideoCodec,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "3",
IsRequired = false
}
}
}
};
} }
} }
} }

View file

@ -6,10 +6,12 @@ namespace MediaBrowser.Dlna.Profiles
{ {
public SonyPs3Profile() public SonyPs3Profile()
{ {
Name = "Sony Bravia (2010)"; Name = "Sony PlayStation 3";
Identification = new DeviceIdentification Identification = new DeviceIdentification
{ {
FriendlyName = "PLAYSTATION 3",
Headers = new[] Headers = new[]
{ {
new HttpHeaderInfo new HttpHeaderInfo

View file

@ -44,7 +44,6 @@ namespace MediaBrowser.Dlna.Profiles
Settings = new [] Settings = new []
{ {
new TranscodingSetting {Name = TranscodingSettingType.VideoLevel, Value = "3"},
new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"} new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"}
} }
}, },

View file

@ -49,8 +49,6 @@ namespace MediaBrowser.Dlna.Profiles
Settings = new [] Settings = new []
{ {
new TranscodingSetting {Name = TranscodingSettingType.MaxAudioChannels, Value = "6"},
new TranscodingSetting {Name = TranscodingSettingType.VideoLevel, Value = "3"},
new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"} new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"}
} }
}, },
@ -229,6 +227,13 @@ namespace MediaBrowser.Dlna.Profiles
Property = ProfileConditionValue.VideoBitrate, Property = ProfileConditionValue.VideoBitrate,
Value = "10240000", Value = "10240000",
IsRequired = false IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "3",
IsRequired = false
} }
} }
}, },
@ -264,6 +269,13 @@ namespace MediaBrowser.Dlna.Profiles
Property = ProfileConditionValue.VideoBitrate, Property = ProfileConditionValue.VideoBitrate,
Value = "15360000", Value = "15360000",
IsRequired = false IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "3",
IsRequired = false
} }
} }
}, },
@ -294,7 +306,7 @@ namespace MediaBrowser.Dlna.Profiles
{ {
Condition = ProfileConditionType.LessThanEqual, Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels, Property = ProfileConditionValue.AudioChannels,
Value = "6", Value = "2",
IsRequired = false IsRequired = false
}, },
new ProfileCondition new ProfileCondition

View file

@ -69,6 +69,7 @@ namespace MediaBrowser.Model.Dto
/// </summary> /// </summary>
/// <value>The name of the sort.</value> /// <value>The name of the sort.</value>
public string SortName { get; set; } public string SortName { get; set; }
public string ForcedSortName { get; set; }
/// <summary> /// <summary>
/// Gets or sets the video3 D format. /// Gets or sets the video3 D format.

View file

@ -107,7 +107,8 @@ namespace MediaBrowser.Providers.Manager
// Next run metadata providers // Next run metadata providers
if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None) if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None)
{ {
var providers = GetProviders(item, refreshResult.DateLastMetadataRefresh.HasValue, refreshOptions).ToList(); var providers = GetProviders(item, refreshResult.DateLastMetadataRefresh.HasValue, refreshOptions)
.ToList();
if (providers.Count > 0 || !refreshResult.DateLastMetadataRefresh.HasValue) if (providers.Count > 0 || !refreshResult.DateLastMetadataRefresh.HasValue)
{ {

View file

@ -741,6 +741,7 @@ namespace MediaBrowser.Server.Implementations.Dto
{ {
dto.LockedFields = item.LockedFields; dto.LockedFields = item.LockedFields;
dto.LockData = item.IsLocked; dto.LockData = item.IsLocked;
dto.ForcedSortName = item.ForcedSortName;
} }
var hasBudget = item as IHasBudget; var hasBudget = item as IHasBudget;