add new guide settings

This commit is contained in:
Luke Pulverenti 2016-09-30 02:50:06 -04:00
parent dcfda6d777
commit 6a7fabc3bd
14 changed files with 256 additions and 166 deletions

View File

@ -104,6 +104,26 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableUserData { get; set; }
public string SortBy { get; set; }
public SortOrder? SortOrder { get; set; }
/// <summary>
/// Gets the order by.
/// </summary>
/// <returns>IEnumerable{ItemSortBy}.</returns>
public string[] GetOrderBy()
{
var val = SortBy;
if (string.IsNullOrEmpty(val))
{
return new string[] { };
}
return val.Split(',');
}
public GetChannels()
{
AddCurrentProgram = true;
@ -650,6 +670,8 @@ namespace MediaBrowser.Api.LiveTv
{
public string Id { get; set; }
public string Container { get; set; }
public long T { get; set; }
public long S { get; set; }
}
public class LiveTvService : BaseApiService
@ -681,9 +703,35 @@ namespace MediaBrowser.Api.LiveTv
outputHeaders["Content-Type"] = MimeTypes.GetMimeType(filePath);
long startPosition = 0;
if (request.T > 0)
{
var now = DateTime.UtcNow;
var totalTicks = now.Ticks - request.S;
if (totalTicks > 0)
{
double requestedOffset = request.T;
requestedOffset = Math.Max(0, requestedOffset - TimeSpan.FromSeconds(10).Ticks);
var pct = requestedOffset / totalTicks;
Logger.Info("Live stream offset pct {0}", pct);
var bytes = new FileInfo(filePath).Length;
Logger.Info("Live stream total bytes {0}", bytes);
startPosition = Convert.ToInt64(pct * bytes);
}
}
Logger.Info("Live stream starting byte position {0}", startPosition);
var streamSource = new ProgressiveFileCopier(_fileSystem, filePath, outputHeaders, null, Logger, CancellationToken.None)
{
AllowEndOfFile = false
AllowEndOfFile = false,
StartPosition = startPosition
};
return ResultFactory.GetAsyncStreamWriter(streamSource);
@ -848,6 +896,8 @@ namespace MediaBrowser.Api.LiveTv
IsNews = request.IsNews,
IsKids = request.IsKids,
IsSports = request.IsSports,
SortBy = request.GetOrderBy(),
SortOrder = request.SortOrder ?? SortOrder.Ascending,
AddCurrentProgram = request.AddCurrentProgram
}, CancellationToken.None).ConfigureAwait(false);

View File

@ -2602,6 +2602,7 @@ namespace MediaBrowser.Api.Playback
inputModifier += " " + GetFastSeekCommandLineParameter(state.Request);
inputModifier = inputModifier.Trim();
//inputModifier += " -fflags +genpts+ignidx+igndts";
if (state.VideoRequest != null && genPts)
{
inputModifier += " -fflags +genpts";

View File

@ -151,6 +151,8 @@ namespace MediaBrowser.Controller.Entities
public Dictionary<string, string> ExcludeProviderIds { get; set; }
public bool EnableGroupByMetadataKey { get; set; }
public List<Tuple<string, SortOrder>> OrderBy { get; set; }
public InternalItemsQuery()
{
GroupByPresentationUniqueKey = true;
@ -193,6 +195,7 @@ namespace MediaBrowser.Controller.Entities
TrailerTypes = new TrailerType[] { };
AirDays = new DayOfWeek[] { };
SeriesStatuses = new SeriesStatus[] { };
OrderBy = new List<Tuple<string, SortOrder>>();
}
public InternalItemsQuery(User user)

View File

@ -13,11 +13,13 @@ namespace MediaBrowser.Controller.LiveTv
public int ConsumerCount { get; set; }
public ITunerHost TunerHost { get; set; }
public string OriginalStreamId { get; set; }
public bool EnableStreamSharing { get; set; }
public LiveStream(MediaSourceInfo mediaSource)
{
OriginalMediaSource = mediaSource;
OpenedMediaSource = mediaSource;
EnableStreamSharing = true;
}
public async Task Open(CancellationToken cancellationToken)

View File

@ -235,6 +235,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
throw new ResourceNotFoundException("ffprobe not found");
}
path = newPaths.Item1;
if (!ValidateVersion(path))
{
throw new ResourceNotFoundException("ffmpeg version 3.0 or greater is required.");

View File

@ -215,13 +215,26 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("MaxWidth", item.MaxWidth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxWidth.Value) : string.Empty));
list.Add(new NameValuePair("MaxHeight", item.MaxHeight.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxHeight.Value) : string.Empty));
if (StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls"))
var forceStartPosition = false;
long startPositionTicks = item.StartPositionTicks;
//if (item.MediaSource.DateLiveStreamOpened.HasValue && startPositionTicks == 0)
//{
// var elapsed = DateTime.UtcNow - item.MediaSource.DateLiveStreamOpened.Value;
// elapsed -= TimeSpan.FromSeconds(20);
// if (elapsed.TotalSeconds >= 0)
// {
// startPositionTicks = elapsed.Ticks + startPositionTicks;
// forceStartPosition = true;
// }
//}
if (StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls") && !forceStartPosition)
{
list.Add(new NameValuePair("StartTimeTicks", string.Empty));
}
else
{
list.Add(new NameValuePair("StartTimeTicks", StringHelper.ToStringCultureInvariant(item.StartPositionTicks)));
list.Add(new NameValuePair("StartTimeTicks", StringHelper.ToStringCultureInvariant(startPositionTicks)));
}
list.Add(new NameValuePair("Level", item.VideoLevel.HasValue ? StringHelper.ToStringCultureInvariant(item.VideoLevel.Value) : string.Empty));

View File

@ -1,4 +1,5 @@

using MediaBrowser.Model.Entities;
namespace MediaBrowser.Model.LiveTv
{
/// <summary>
@ -85,9 +86,18 @@ namespace MediaBrowser.Model.LiveTv
public bool? IsSports { get; set; }
public bool? IsSeries { get; set; }
public string[] SortBy { get; set; }
/// <summary>
/// The sort order to return results with
/// </summary>
/// <value>The sort order.</value>
public SortOrder? SortOrder { get; set; }
public LiveTvChannelQuery()
{
EnableUserData = true;
SortBy = new string[] { };
}
}
}

View File

@ -60,7 +60,6 @@ namespace MediaBrowser.Model.LiveTv
public TunerHostInfo()
{
IsEnabled = true;
AllowHWTranscoding = true;
}
}

View File

@ -483,7 +483,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
if (existingTimer != null)
{
if (existingTimer.Status == RecordingStatus.Cancelled)
if (existingTimer.Status == RecordingStatus.Cancelled ||
existingTimer.Status == RecordingStatus.Completed)
{
existingTimer.Status = RecordingStatus.New;
_timerProvider.Update(existingTimer);
@ -832,12 +833,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return result.Item2;
}
private MediaSourceInfo CloneMediaSource(MediaSourceInfo mediaSource, int consumerId)
private MediaSourceInfo CloneMediaSource(MediaSourceInfo mediaSource, int consumerId, bool enableStreamSharing)
{
var json = _jsonSerializer.SerializeToString(mediaSource);
mediaSource = _jsonSerializer.DeserializeFromString<MediaSourceInfo>(json);
mediaSource.Id = consumerId.ToString(CultureInfo.InvariantCulture) + "_" + mediaSource.Id;
mediaSource.Id = Guid.NewGuid().ToString("N") + "_" + mediaSource.Id;
if (mediaSource.DateLiveStreamOpened.HasValue && enableStreamSharing)
{
var ticks = (DateTime.UtcNow - mediaSource.DateLiveStreamOpened.Value).Ticks - TimeSpan.FromSeconds(10).Ticks;
ticks = Math.Max(0, ticks);
mediaSource.Path += "?t=" + ticks.ToString(CultureInfo.InvariantCulture) + "&s=" + mediaSource.DateLiveStreamOpened.Value.Ticks.ToString(CultureInfo.InvariantCulture);
}
return mediaSource;
}
@ -850,14 +858,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var result = _liveStreams.Values.FirstOrDefault(i => string.Equals(i.OriginalStreamId, streamId, StringComparison.OrdinalIgnoreCase));
if (result != null)
if (result != null && result.EnableStreamSharing)
{
//result.ConsumerCount++;
result.ConsumerCount++;
//_logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount);
_logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount);
//_liveStreamsSemaphore.Release();
//return new Tuple<LiveStream, MediaSourceInfo, ITunerHost>(result, CloneMediaSource(result.OpenedMediaSource, result.ConsumerCount - 1), result.TunerHost);
var openedMediaSource = CloneMediaSource(result.OpenedMediaSource, result.ConsumerCount - 1, result.EnableStreamSharing);
_liveStreamsSemaphore.Release();
return new Tuple<LiveStream, MediaSourceInfo, ITunerHost>(result, openedMediaSource, result.TunerHost);
}
try
@ -868,16 +877,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
_liveStreams[result.OpenedMediaSource.Id] = result;
var openedMediaSource = CloneMediaSource(result.OpenedMediaSource, 0, result.EnableStreamSharing);
_liveStreams[openedMediaSource.Id] = result;
result.ConsumerCount++;
result.TunerHost = hostInstance;
result.OriginalStreamId = streamId;
_logger.Info("Returning mediasource streamId {0}, mediaSource.Id {1}, mediaSource.LiveStreamId {2}",
streamId, result.OpenedMediaSource.Id, result.OpenedMediaSource.LiveStreamId);
streamId, openedMediaSource.Id, openedMediaSource.LiveStreamId);
return new Tuple<LiveStream, MediaSourceInfo, ITunerHost>(result, CloneMediaSource(result.OpenedMediaSource, 0), hostInstance);
return new Tuple<LiveStream, MediaSourceInfo, ITunerHost>(result, openedMediaSource, hostInstance);
}
catch (FileNotFoundException)
{
@ -925,7 +936,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public async Task CloseLiveStream(string id, CancellationToken cancellationToken)
{
// Ignore the consumer id
id = id.Substring(id.IndexOf('_') + 1);
//id = id.Substring(id.IndexOf('_') + 1);
await _liveStreamsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
@ -1143,8 +1154,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
try
{
var allMediaSources =
await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false);
var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false);
var liveStreamInfo = await GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None)
.ConfigureAwait(false);

View File

@ -141,7 +141,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
var maxBitrate = 25000000;
videoArgs = string.Format(
"-codec:v:0 libx264 -force_key_frames \"expr:gte(t,n_forced*5)\" {0} -pix_fmt yuv420p -preset superfast -crf 23 -b:v {1} -maxrate {1} -bufsize ({1}*2) -vsync -1 -profile:v high -level 41",
"-codec:v:0 libx264 -force_key_frames \"expr:gte(t,n_forced*5)\" {0} -pix_fmt yuv420p -preset superfast -crf 23 -b:v {1} -maxrate {1} -bufsize ({1}*2) -vsync -1 -profile:v high -level 41 -tune zerolatency",
GetOutputSizeParam(),
maxBitrate.ToString(CultureInfo.InvariantCulture));
}
@ -151,16 +151,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
var durationParam = " -t " + _mediaEncoder.GetTimeParameter(duration.Ticks);
var commandLineArgs = "-fflags +genpts -async 1 -vsync -1 -i \"{0}\"{4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
var inputModifiers = "-fflags +genpts -async 1 -vsync -1";
var commandLineArgs = "-i \"{0}\"{4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
long startTimeTicks = 0;
//if (mediaSource.DateLiveStreamOpened.HasValue)
//{
// var elapsed = DateTime.UtcNow - mediaSource.DateLiveStreamOpened.Value;
// elapsed -= TimeSpan.FromSeconds(10);
// if (elapsed.TotalSeconds >= 0)
// {
// startTimeTicks = elapsed.Ticks + startTimeTicks;
// }
//}
if (mediaSource.ReadAtNativeFramerate)
{
commandLineArgs = "-re " + commandLineArgs;
inputModifiers += " -re";
}
if (startTimeTicks > 0)
{
inputModifiers = "-ss " + _mediaEncoder.GetTimeParameter(startTimeTicks) + " " + inputModifiers;
}
commandLineArgs = string.Format(commandLineArgs, inputTempFile, targetFile, videoArgs, GetAudioArgs(mediaSource), durationParam);
return commandLineArgs;
return inputModifiers + " " + commandLineArgs;
}
private string GetAudioArgs(MediaSourceInfo mediaSource)

View File

@ -148,7 +148,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var topFolder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false);
var channels = _libraryManager.GetItemList(new InternalItemsQuery
var internalQuery = new InternalItemsQuery(user)
{
IsMovie = query.IsMovie,
IsNews = query.IsNews,
@ -156,109 +156,32 @@ namespace MediaBrowser.Server.Implementations.LiveTv
IsSports = query.IsSports,
IsSeries = query.IsSeries,
IncludeItemTypes = new[] { typeof(LiveTvChannel).Name },
SortBy = new[] { ItemSortBy.SortName },
TopParentIds = new[] { topFolder.Id.ToString("N") }
SortOrder = query.SortOrder ?? SortOrder.Ascending,
TopParentIds = new[] { topFolder.Id.ToString("N") },
IsFavorite = query.IsFavorite,
IsLiked = query.IsLiked,
StartIndex = query.StartIndex,
Limit = query.Limit
};
}).Cast<LiveTvChannel>();
internalQuery.OrderBy.AddRange(query.SortBy.Select(i => new Tuple<string, SortOrder>(i, query.SortOrder ?? SortOrder.Ascending)));
if (user != null)
if (query.EnableFavoriteSorting)
{
// Avoid implicitly captured closure
var currentUser = user;
channels = channels
.Where(i => i.IsVisible(currentUser))
.OrderBy(i =>
{
double number = 0;
if (!string.IsNullOrEmpty(i.Number))
{
double.TryParse(i.Number, out number);
}
return number;
});
if (query.IsFavorite.HasValue)
{
var val = query.IsFavorite.Value;
channels = channels
.Where(i => _userDataManager.GetUserData(user, i).IsFavorite == val);
}
if (query.IsLiked.HasValue)
{
var val = query.IsLiked.Value;
channels = channels
.Where(i =>
{
var likes = _userDataManager.GetUserData(user, i).Likes;
return likes.HasValue && likes.Value == val;
});
}
if (query.IsDisliked.HasValue)
{
var val = query.IsDisliked.Value;
channels = channels
.Where(i =>
{
var likes = _userDataManager.GetUserData(user, i).Likes;
return likes.HasValue && likes.Value != val;
});
}
internalQuery.OrderBy.Insert(0, new Tuple<string, SortOrder>(ItemSortBy.IsFavoriteOrLiked, SortOrder.Descending));
}
var enableFavoriteSorting = query.EnableFavoriteSorting;
channels = channels.OrderBy(i =>
if (!internalQuery.OrderBy.Any(i => string.Equals(i.Item1, ItemSortBy.SortName, StringComparison.OrdinalIgnoreCase)))
{
if (enableFavoriteSorting)
{
var userData = _userDataManager.GetUserData(user, i);
if (userData.IsFavorite)
{
return 0;
}
if (userData.Likes.HasValue)
{
if (!userData.Likes.Value)
{
return 3;
}
return 1;
}
}
return 2;
});
var allChannels = channels.ToList();
IEnumerable<LiveTvChannel> allEnumerable = allChannels;
if (query.StartIndex.HasValue)
{
allEnumerable = allEnumerable.Skip(query.StartIndex.Value);
internalQuery.OrderBy.Add(new Tuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending));
}
if (query.Limit.HasValue)
{
allEnumerable = allEnumerable.Take(query.Limit.Value);
}
var channelResult = _libraryManager.GetItemsResult(internalQuery);
var result = new QueryResult<LiveTvChannel>
{
Items = allEnumerable.ToArray(),
TotalRecordCount = allChannels.Count
Items = channelResult.Items.Cast<LiveTvChannel>().ToArray(),
TotalRecordCount = channelResult.TotalRecordCount
};
return result;

View File

@ -104,8 +104,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
});
}
private Dictionary<string, DiscoverResponse> _modelCache = new Dictionary<string, DiscoverResponse>();
private async Task<string> GetModelInfo(TunerHostInfo info, CancellationToken cancellationToken)
{
lock (_modelCache)
{
DiscoverResponse response;
if (_modelCache.TryGetValue(info.Url, out response))
{
return response.ModelNumber;
}
}
try
{
using (var stream = await _httpClient.Get(new HttpRequestOptions()
@ -119,6 +129,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
var response = JsonSerializer.DeserializeFromStream<DiscoverResponse>(stream);
lock (_modelCache)
{
_modelCache[info.Id] = response;
}
return response.ModelNumber;
}
}
@ -126,8 +141,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
if (ex.StatusCode.HasValue && ex.StatusCode.Value == System.Net.HttpStatusCode.NotFound)
{
var defaultValue = "HDHR";
// HDHR4 doesn't have this api
return "HDHR";
lock (_modelCache)
{
_modelCache[info.Id] = new DiscoverResponse
{
ModelNumber = defaultValue
};
}
return defaultValue;
}
throw;
@ -427,18 +450,21 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
try
{
string model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false);
model = model ?? string.Empty;
if (info.AllowHWTranscoding && (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1))
if (info.AllowHWTranscoding)
{
list.Add(await GetMediaSource(info, hdhrId, "heavy").ConfigureAwait(false));
string model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false);
model = model ?? string.Empty;
list.Add(await GetMediaSource(info, hdhrId, "internet540").ConfigureAwait(false));
list.Add(await GetMediaSource(info, hdhrId, "internet480").ConfigureAwait(false));
list.Add(await GetMediaSource(info, hdhrId, "internet360").ConfigureAwait(false));
list.Add(await GetMediaSource(info, hdhrId, "internet240").ConfigureAwait(false));
list.Add(await GetMediaSource(info, hdhrId, "mobile").ConfigureAwait(false));
if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1))
{
list.Add(await GetMediaSource(info, hdhrId, "heavy").ConfigureAwait(false));
list.Add(await GetMediaSource(info, hdhrId, "internet540").ConfigureAwait(false));
list.Add(await GetMediaSource(info, hdhrId, "internet480").ConfigureAwait(false));
list.Add(await GetMediaSource(info, hdhrId, "internet360").ConfigureAwait(false));
list.Add(await GetMediaSource(info, hdhrId, "internet240").ConfigureAwait(false));
list.Add(await GetMediaSource(info, hdhrId, "mobile").ConfigureAwait(false));
}
}
}
catch
@ -474,6 +500,23 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var mediaSource = await GetMediaSource(info, hdhrId, profile).ConfigureAwait(false);
var liveStream = new HdHomerunLiveStream(mediaSource, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
if (info.AllowHWTranscoding)
{
var model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false);
if ((model ?? string.Empty).IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1)
{
liveStream.EnableStreamSharing = !info.AllowHWTranscoding;
}
else
{
liveStream.EnableStreamSharing = true;
}
}
else
{
liveStream.EnableStreamSharing = true;
}
return liveStream;
}
@ -484,6 +527,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return;
}
lock (_modelCache)
{
_modelCache.Clear();
}
try
{
// Test it by pulling down the lineup

View File

@ -52,11 +52,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
StartStreamingToTempFile(output, tempFile, url, taskCompletionSource, _liveStreamCancellationTokenSource.Token);
await taskCompletionSource.Task.ConfigureAwait(false);
//OpenedMediaSource.Protocol = MediaProtocol.File;
//OpenedMediaSource.Path = tempFile;
//OpenedMediaSource.ReadAtNativeFramerate = true;
OpenedMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + Path.GetFileNameWithoutExtension(tempFile) + "/stream.ts";
OpenedMediaSource.Protocol = MediaProtocol.Http;
await taskCompletionSource.Task.ConfigureAwait(false);
//await Task.Delay(5000).ConfigureAwait(false);
}
public override Task Close()

View File

@ -1730,28 +1730,28 @@ namespace MediaBrowser.Server.Implementations.Persistence
return true;
}
if (query.SortBy != null && query.SortBy.Length > 0)
var sortingFields = query.SortBy.ToList();
sortingFields.AddRange(query.OrderBy.Select(i => i.Item1));
if (sortingFields.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase))
{
if (query.SortBy.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase))
{
return true;
}
if (query.SortBy.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase))
{
return true;
}
if (query.SortBy.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase))
{
return true;
}
if (query.SortBy.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase))
{
return true;
}
if (query.SortBy.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase))
{
return true;
}
return true;
}
if (sortingFields.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase))
{
return true;
}
if (sortingFields.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase))
{
return true;
}
if (sortingFields.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase))
{
return true;
}
if (sortingFields.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase))
{
return true;
}
if (query.IsFavoriteOrLiked.HasValue)
@ -2151,34 +2151,41 @@ namespace MediaBrowser.Server.Implementations.Persistence
private string GetOrderByText(InternalItemsQuery query)
{
var orderBy = query.OrderBy.ToList();
var enableOrderInversion = true;
if (orderBy.Count == 0)
{
orderBy.AddRange(query.SortBy.Select(i => new Tuple<string, SortOrder>(i, query.SortOrder)));
}
else
{
enableOrderInversion = false;
}
if (query.SimilarTo != null)
{
if (query.SortBy == null || query.SortBy.Length == 0)
if (orderBy.Count == 0)
{
if (query.User != null)
{
query.SortBy = new[] { "SimilarityScore", ItemSortBy.Random };
}
else
{
query.SortBy = new[] { "SimilarityScore", ItemSortBy.Random };
}
orderBy.Add(new Tuple<string, SortOrder>("SimilarityScore", SortOrder.Descending));
orderBy.Add(new Tuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending));
query.SortOrder = SortOrder.Descending;
enableOrderInversion = false;
}
}
if (query.SortBy == null || query.SortBy.Length == 0)
query.OrderBy = orderBy;
if (orderBy.Count == 0)
{
return string.Empty;
}
var isAscending = query.SortOrder != SortOrder.Descending;
return " ORDER BY " + string.Join(",", query.SortBy.Select(i =>
return " ORDER BY " + string.Join(",", orderBy.Select(i =>
{
var columnMap = MapOrderByField(i, query);
var columnAscending = isAscending;
if (columnMap.Item2)
var columnMap = MapOrderByField(i.Item1, query);
var columnAscending = i.Item2 == SortOrder.Ascending;
if (columnMap.Item2 && enableOrderInversion)
{
columnAscending = !columnAscending;
}