fixes #912 - Add special views for Dlna
This commit is contained in:
parent
383b9999da
commit
6f45ea0823
|
@ -39,8 +39,8 @@ namespace MediaBrowser.Api.Images
|
||||||
|
|
||||||
[Route("/Items/{Id}/Images/{Type}", "GET")]
|
[Route("/Items/{Id}/Images/{Type}", "GET")]
|
||||||
[Route("/Items/{Id}/Images/{Type}/{Index}", "GET")]
|
[Route("/Items/{Id}/Images/{Type}/{Index}", "GET")]
|
||||||
[Route("/Items/{Id}/Images/{Type}/{Index}/{Tag}/{Format}/{MaxWidth}/{MaxHeight}", "GET")]
|
[Route("/Items/{Id}/Images/{Type}/{Index}/{Tag}/{Format}/{MaxWidth}/{MaxHeight}/{PercentPlayed}", "GET")]
|
||||||
[Route("/Items/{Id}/Images/{Type}/{Index}/{Tag}/{Format}/{MaxWidth}/{MaxHeight}", "HEAD")]
|
[Route("/Items/{Id}/Images/{Type}/{Index}/{Tag}/{Format}/{MaxWidth}/{MaxHeight}/{PercentPlayed}", "HEAD")]
|
||||||
[Api(Description = "Gets an item image")]
|
[Api(Description = "Gets an item image")]
|
||||||
public class GetItemImage : ImageRequest
|
public class GetItemImage : ImageRequest
|
||||||
{
|
{
|
||||||
|
@ -583,7 +583,7 @@ namespace MediaBrowser.Api.Images
|
||||||
Width = request.Width,
|
Width = request.Width,
|
||||||
OutputFormat = request.Format,
|
OutputFormat = request.Format,
|
||||||
AddPlayedIndicator = request.AddPlayedIndicator,
|
AddPlayedIndicator = request.AddPlayedIndicator,
|
||||||
PercentPlayed = request.PercentPlayed,
|
PercentPlayed = request.PercentPlayed ?? 0,
|
||||||
UnplayedCount = request.UnplayedCount,
|
UnplayedCount = request.UnplayedCount,
|
||||||
BackgroundColor = request.BackgroundColor
|
BackgroundColor = request.BackgroundColor
|
||||||
};
|
};
|
||||||
|
|
|
@ -169,7 +169,7 @@
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
</PostBuildEvent>
|
</PostBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
<Target Name="BeforeBuild">
|
<Target Name="BeforeBuild">
|
||||||
|
|
|
@ -1516,6 +1516,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
state.RunTimeTicks = item.RunTimeTicks;
|
state.RunTimeTicks = item.RunTimeTicks;
|
||||||
state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
|
state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
|
||||||
state.InputBitrate = mediaSource.Bitrate;
|
state.InputBitrate = mediaSource.Bitrate;
|
||||||
|
state.InputFileSize = mediaSource.Size;
|
||||||
mediaStreams = mediaSource.MediaStreams;
|
mediaStreams = mediaSource.MediaStreams;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1530,6 +1531,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
state.MediaPath = mediaSource.Path;
|
state.MediaPath = mediaSource.Path;
|
||||||
state.InputProtocol = mediaSource.Protocol;
|
state.InputProtocol = mediaSource.Protocol;
|
||||||
state.InputContainer = mediaSource.Container;
|
state.InputContainer = mediaSource.Container;
|
||||||
|
state.InputFileSize = mediaSource.Size;
|
||||||
state.InputBitrate = mediaSource.Bitrate;
|
state.InputBitrate = mediaSource.Bitrate;
|
||||||
|
|
||||||
if (item is Video)
|
if (item is Video)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using MediaBrowser.Common.IO;
|
using System.Linq;
|
||||||
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
@ -153,7 +154,25 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
|
|
||||||
using (state)
|
using (state)
|
||||||
{
|
{
|
||||||
var throttleLimit = state.InputBitrate.HasValue ? (state.InputBitrate.Value / 8) : 0;
|
var limits = new List<long>();
|
||||||
|
if (state.InputBitrate.HasValue)
|
||||||
|
{
|
||||||
|
// Bytes per second
|
||||||
|
limits.Add((state.InputBitrate.Value / 8));
|
||||||
|
}
|
||||||
|
if (state.InputFileSize.HasValue && state.RunTimeTicks.HasValue)
|
||||||
|
{
|
||||||
|
var totalSeconds = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds;
|
||||||
|
|
||||||
|
if (totalSeconds > 1)
|
||||||
|
{
|
||||||
|
var timeBasedLimit = state.InputFileSize.Value / totalSeconds;
|
||||||
|
limits.Add(Convert.ToInt64(timeBasedLimit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take the greater of the above to methods, just to be safe
|
||||||
|
var throttleLimit = limits.Count > 0 ? limits.Max() : 0;
|
||||||
|
|
||||||
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
|
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
|
||||||
{
|
{
|
||||||
|
@ -166,8 +185,8 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
// Pad by 20% to play it safe
|
// Pad by 20% to play it safe
|
||||||
ThrottleLimit = Convert.ToInt64(1.2 * throttleLimit),
|
ThrottleLimit = Convert.ToInt64(1.2 * throttleLimit),
|
||||||
|
|
||||||
// Three minutes
|
// 3.5 minutes
|
||||||
MinThrottlePosition = throttleLimit * 180
|
MinThrottlePosition = throttleLimit * 210
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
public long? RunTimeTicks;
|
public long? RunTimeTicks;
|
||||||
|
|
||||||
public long? InputBitrate { get; set; }
|
public long? InputBitrate { get; set; }
|
||||||
|
public long? InputFileSize { get; set; }
|
||||||
|
|
||||||
public string OutputAudioSync = "1";
|
public string OutputAudioSync = "1";
|
||||||
public string OutputVideoSync = "vfr";
|
public string OutputVideoSync = "vfr";
|
||||||
|
|
|
@ -6,6 +6,7 @@ using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Persistence;
|
||||||
|
using MediaBrowser.Controller.TV;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
|
@ -26,7 +27,7 @@ namespace MediaBrowser.Api
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The user id.</value>
|
/// <value>The user id.</value>
|
||||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
public Guid UserId { get; set; }
|
public string UserId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Skips over a given number of items within the results. Use for paging.
|
/// Skips over a given number of items within the results. Use for paging.
|
||||||
|
@ -195,6 +196,7 @@ namespace MediaBrowser.Api
|
||||||
|
|
||||||
private readonly IItemRepository _itemRepo;
|
private readonly IItemRepository _itemRepo;
|
||||||
private readonly IDtoService _dtoService;
|
private readonly IDtoService _dtoService;
|
||||||
|
private readonly ITVSeriesManager _tvSeriesManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="TvShowsService" /> class.
|
/// Initializes a new instance of the <see cref="TvShowsService" /> class.
|
||||||
|
@ -202,13 +204,14 @@ namespace MediaBrowser.Api
|
||||||
/// <param name="userManager">The user manager.</param>
|
/// <param name="userManager">The user manager.</param>
|
||||||
/// <param name="userDataManager">The user data repository.</param>
|
/// <param name="userDataManager">The user data repository.</param>
|
||||||
/// <param name="libraryManager">The library manager.</param>
|
/// <param name="libraryManager">The library manager.</param>
|
||||||
public TvShowsService(IUserManager userManager, IUserDataManager userDataManager, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService)
|
public TvShowsService(IUserManager userManager, IUserDataManager userDataManager, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService, ITVSeriesManager tvSeriesManager)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_userDataManager = userDataManager;
|
_userDataManager = userDataManager;
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_itemRepo = itemRepo;
|
_itemRepo = itemRepo;
|
||||||
_dtoService = dtoService;
|
_dtoService = dtoService;
|
||||||
|
_tvSeriesManager = tvSeriesManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -270,129 +273,26 @@ namespace MediaBrowser.Api
|
||||||
/// <returns>System.Object.</returns>
|
/// <returns>System.Object.</returns>
|
||||||
public object Get(GetNextUpEpisodes request)
|
public object Get(GetNextUpEpisodes request)
|
||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(request.UserId);
|
var result = _tvSeriesManager.GetNextUp(new NextUpQuery
|
||||||
|
{
|
||||||
|
Limit = request.Limit,
|
||||||
|
ParentId = request.ParentId,
|
||||||
|
SeriesId = request.SeriesId,
|
||||||
|
StartIndex = request.StartIndex,
|
||||||
|
UserId = request.UserId
|
||||||
|
});
|
||||||
|
|
||||||
var itemsList = GetNextUpEpisodes(request)
|
var user = _userManager.GetUserById(new Guid(request.UserId));
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var pagedItems = ApplyPaging(itemsList, request.StartIndex, request.Limit);
|
|
||||||
|
|
||||||
var fields = request.GetItemFields().ToList();
|
var fields = request.GetItemFields().ToList();
|
||||||
|
|
||||||
var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray();
|
var returnItems = result.Items.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray();
|
||||||
|
|
||||||
var result = new ItemsResult
|
return ToOptimizedSerializedResultUsingCache(new ItemsResult
|
||||||
{
|
{
|
||||||
TotalRecordCount = itemsList.Count,
|
TotalRecordCount = result.TotalRecordCount,
|
||||||
Items = returnItems
|
Items = returnItems
|
||||||
};
|
});
|
||||||
|
|
||||||
return ToOptimizedSerializedResultUsingCache(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Episode> GetNextUpEpisodes(GetNextUpEpisodes request)
|
|
||||||
{
|
|
||||||
var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId)
|
|
||||||
.OfType<Series>();
|
|
||||||
|
|
||||||
// Avoid implicitly captured closure
|
|
||||||
return GetNextUpEpisodes(request, items);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Episode> GetNextUpEpisodes(GetNextUpEpisodes request, IEnumerable<Series> series)
|
|
||||||
{
|
|
||||||
var user = _userManager.GetUserById(request.UserId);
|
|
||||||
|
|
||||||
// Avoid implicitly captured closure
|
|
||||||
var currentUser = user;
|
|
||||||
|
|
||||||
return FilterSeries(request, series)
|
|
||||||
.AsParallel()
|
|
||||||
.Select(i => GetNextUp(i, currentUser))
|
|
||||||
.Where(i => i.Item1 != null)
|
|
||||||
.OrderByDescending(i =>
|
|
||||||
{
|
|
||||||
var episode = i.Item1;
|
|
||||||
|
|
||||||
var seriesUserData = _userDataManager.GetUserData(user.Id, episode.Series.GetUserDataKey());
|
|
||||||
|
|
||||||
if (seriesUserData.IsFavorite)
|
|
||||||
{
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seriesUserData.Likes.HasValue)
|
|
||||||
{
|
|
||||||
return seriesUserData.Likes.Value ? 1 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
})
|
|
||||||
.ThenByDescending(i => i.Item2)
|
|
||||||
.ThenByDescending(i => i.Item1.PremiereDate ?? DateTime.MinValue)
|
|
||||||
.Select(i => i.Item1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the next up.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="series">The series.</param>
|
|
||||||
/// <param name="user">The user.</param>
|
|
||||||
/// <returns>Task{Episode}.</returns>
|
|
||||||
private Tuple<Episode, DateTime> GetNextUp(Series series, User user)
|
|
||||||
{
|
|
||||||
// Get them in display order, then reverse
|
|
||||||
var allEpisodes = series.GetSeasons(user, true, true)
|
|
||||||
.SelectMany(i => i.GetEpisodes(user, true, true))
|
|
||||||
.Reverse()
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
Episode lastWatched = null;
|
|
||||||
var lastWatchedDate = DateTime.MinValue;
|
|
||||||
Episode nextUp = null;
|
|
||||||
|
|
||||||
// Go back starting with the most recent episodes
|
|
||||||
foreach (var episode in allEpisodes)
|
|
||||||
{
|
|
||||||
var userData = _userDataManager.GetUserData(user.Id, episode.GetUserDataKey());
|
|
||||||
|
|
||||||
if (userData.Played)
|
|
||||||
{
|
|
||||||
if (lastWatched != null || nextUp == null)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastWatched = episode;
|
|
||||||
lastWatchedDate = userData.LastPlayedDate ?? DateTime.MinValue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (episode.LocationType != LocationType.Virtual)
|
|
||||||
{
|
|
||||||
nextUp = episode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastWatched != null)
|
|
||||||
{
|
|
||||||
return new Tuple<Episode, DateTime>(nextUp, lastWatchedDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Tuple<Episode, DateTime>(null, lastWatchedDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<Series> FilterSeries(GetNextUpEpisodes request, IEnumerable<Series> items)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(request.SeriesId))
|
|
||||||
{
|
|
||||||
var id = new Guid(request.SeriesId);
|
|
||||||
|
|
||||||
items = items.Where(i => i.Id == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -122,7 +122,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PostBuildEvent Condition=" '$(ConfigurationName)' != 'Release Mono' ">if '$(ConfigurationName)' == 'Release' (
|
<PostBuildEvent Condition=" '$(ConfigurationName)' != 'Release Mono' ">if '$(ConfigurationName)' == 'Release' (
|
||||||
xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i
|
xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i
|
||||||
|
|
|
@ -116,7 +116,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PostBuildEvent Condition=" '$(ConfigurationName)' != 'Release Mono' ">if '$(ConfigurationName)' == 'Release' (
|
<PostBuildEvent Condition=" '$(ConfigurationName)' != 'Release Mono' ">if '$(ConfigurationName)' == 'Release' (
|
||||||
xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i
|
xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Model.Channels;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Channels
|
namespace MediaBrowser.Controller.Channels
|
||||||
{
|
{
|
||||||
|
@ -17,5 +21,31 @@ namespace MediaBrowser.Controller.Channels
|
||||||
|
|
||||||
return base.IsVisible(user);
|
return base.IsVisible(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task<QueryResult<BaseItem>> GetUserItems(UserItemsQuery query)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Don't blow up here because it could cause parent screens with other content to fail
|
||||||
|
return await ChannelManager.GetChannelItemsInternal(new ChannelItemQuery
|
||||||
|
{
|
||||||
|
ChannelId = Id.ToString("N"),
|
||||||
|
Limit = query.Limit,
|
||||||
|
StartIndex = query.StartIndex,
|
||||||
|
UserId = query.User.Id.ToString("N"),
|
||||||
|
SortBy = query.SortBy,
|
||||||
|
SortOrder = query.SortOrder
|
||||||
|
|
||||||
|
}, CancellationToken.None);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Already logged at lower levels
|
||||||
|
return new QueryResult<BaseItem>
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Model.Channels;
|
using MediaBrowser.Model.Channels;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Channels
|
namespace MediaBrowser.Controller.Channels
|
||||||
{
|
{
|
||||||
|
@ -33,5 +36,32 @@ namespace MediaBrowser.Controller.Channels
|
||||||
{
|
{
|
||||||
return ExternalId;
|
return ExternalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task<QueryResult<BaseItem>> GetUserItems(UserItemsQuery query)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Don't blow up here because it could cause parent screens with other content to fail
|
||||||
|
return await ChannelManager.GetChannelItemsInternal(new ChannelItemQuery
|
||||||
|
{
|
||||||
|
ChannelId = ChannelId,
|
||||||
|
FolderId = Id.ToString("N"),
|
||||||
|
Limit = query.Limit,
|
||||||
|
StartIndex = query.StartIndex,
|
||||||
|
UserId = query.User.Id.ToString("N"),
|
||||||
|
SortBy = query.SortBy,
|
||||||
|
SortOrder = query.SortOrder
|
||||||
|
|
||||||
|
}, CancellationToken.None);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Already logged at lower levels
|
||||||
|
return new QueryResult<BaseItem>
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,6 @@ namespace MediaBrowser.Controller.Channels
|
||||||
{
|
{
|
||||||
public class ChannelVideoItem : Video, IChannelMediaItem
|
public class ChannelVideoItem : Video, IChannelMediaItem
|
||||||
{
|
{
|
||||||
public static IChannelManager ChannelManager { get; set; }
|
|
||||||
|
|
||||||
public string ExternalId { get; set; }
|
public string ExternalId { get; set; }
|
||||||
|
|
||||||
public string ChannelId { get; set; }
|
public string ChannelId { get; set; }
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace MediaBrowser.Controller.Drawing
|
||||||
|
|
||||||
public int? UnplayedCount { get; set; }
|
public int? UnplayedCount { get; set; }
|
||||||
|
|
||||||
public double? PercentPlayed { get; set; }
|
public double PercentPlayed { get; set; }
|
||||||
|
|
||||||
public string BackgroundColor { get; set; }
|
public string BackgroundColor { get; set; }
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ namespace MediaBrowser.Controller.Drawing
|
||||||
return (!Quality.HasValue || Quality.Value == 100) &&
|
return (!Quality.HasValue || Quality.Value == 100) &&
|
||||||
IsOutputFormatDefault(originalImagePath) &&
|
IsOutputFormatDefault(originalImagePath) &&
|
||||||
!AddPlayedIndicator &&
|
!AddPlayedIndicator &&
|
||||||
!PercentPlayed.HasValue &&
|
PercentPlayed.Equals(0) &&
|
||||||
!UnplayedCount.HasValue &&
|
!UnplayedCount.HasValue &&
|
||||||
string.IsNullOrEmpty(BackgroundColor);
|
string.IsNullOrEmpty(BackgroundColor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
using MediaBrowser.Controller.LiveTv;
|
||||||
|
@ -240,6 +241,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
public static IFileSystem FileSystem { get; set; }
|
public static IFileSystem FileSystem { get; set; }
|
||||||
public static IUserDataManager UserDataManager { get; set; }
|
public static IUserDataManager UserDataManager { get; set; }
|
||||||
public static ILiveTvManager LiveTvManager { get; set; }
|
public static ILiveTvManager LiveTvManager { get; set; }
|
||||||
|
public static IChannelManager ChannelManager { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a <see cref="System.String" /> that represents this instance.
|
/// Returns a <see cref="System.String" /> that represents this instance.
|
||||||
|
|
|
@ -6,6 +6,8 @@ using MediaBrowser.Controller.Localization;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using MoreLinq;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -14,7 +16,6 @@ using System.Linq;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MoreLinq;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities
|
namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
|
@ -24,6 +25,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
public class Folder : BaseItem, IHasThemeMedia, IHasTags
|
public class Folder : BaseItem, IHasThemeMedia, IHasTags
|
||||||
{
|
{
|
||||||
public static IUserManager UserManager { get; set; }
|
public static IUserManager UserManager { get; set; }
|
||||||
|
public static IUserViewManager UserViewManager { get; set; }
|
||||||
|
|
||||||
public List<Guid> ThemeSongIds { get; set; }
|
public List<Guid> ThemeSongIds { get; set; }
|
||||||
public List<Guid> ThemeVideoIds { get; set; }
|
public List<Guid> ThemeVideoIds { get; set; }
|
||||||
|
@ -770,6 +772,24 @@ namespace MediaBrowser.Controller.Entities
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual Task<QueryResult<BaseItem>> GetUserItems(UserItemsQuery query)
|
||||||
|
{
|
||||||
|
var user = query.User;
|
||||||
|
|
||||||
|
var items = query.Recursive
|
||||||
|
? GetRecursiveChildren(user)
|
||||||
|
: GetChildren(user, true);
|
||||||
|
|
||||||
|
var result = SortAndFilter(items, query);
|
||||||
|
|
||||||
|
return Task.FromResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
return UserViewBuilder.SortAndFilter(items, null, query, LibraryManager, UserDataManager);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets allowed children of an item
|
/// Gets allowed children of an item
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -944,7 +964,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
.OfType<CollectionFolder>()
|
.OfType<CollectionFolder>()
|
||||||
.SelectMany(i => i.PhysicalLocations)
|
.SelectMany(i => i.PhysicalLocations)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return LinkedChildren
|
return LinkedChildren
|
||||||
.Select(i =>
|
.Select(i =>
|
||||||
{
|
{
|
||||||
|
@ -985,10 +1005,10 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// Gets the linked children.
|
/// Gets the linked children.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||||
public IEnumerable<Tuple<LinkedChild,BaseItem>> GetLinkedChildrenInfos()
|
public IEnumerable<Tuple<LinkedChild, BaseItem>> GetLinkedChildrenInfos()
|
||||||
{
|
{
|
||||||
return LinkedChildren
|
return LinkedChildren
|
||||||
.Select(i => new Tuple<LinkedChild,BaseItem>(i, GetLinkedChild(i)))
|
.Select(i => new Tuple<LinkedChild, BaseItem>(i, GetLinkedChild(i)))
|
||||||
.Where(i => i.Item2 != null);
|
.Where(i => i.Item2 != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1183,7 +1203,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
var isUnplayed = true;
|
var isUnplayed = true;
|
||||||
|
|
||||||
var itemUserData = UserDataManager.GetUserData(user.Id, child.GetUserDataKey());
|
var itemUserData = UserDataManager.GetUserData(user.Id, child.GetUserDataKey());
|
||||||
|
|
||||||
// Incrememt totalPercentPlayed
|
// Incrememt totalPercentPlayed
|
||||||
if (itemUserData != null)
|
if (itemUserData != null)
|
||||||
{
|
{
|
||||||
|
|
35
MediaBrowser.Controller/Entities/UserItemsQuery.cs
Normal file
35
MediaBrowser.Controller/Entities/UserItemsQuery.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public class UserItemsQuery
|
||||||
|
{
|
||||||
|
public bool Recursive { get; set; }
|
||||||
|
|
||||||
|
public int? StartIndex { get; set; }
|
||||||
|
|
||||||
|
public int? Limit { get; set; }
|
||||||
|
|
||||||
|
public string[] SortBy { get; set; }
|
||||||
|
|
||||||
|
public SortOrder SortOrder { get; set; }
|
||||||
|
|
||||||
|
public User User { get; set; }
|
||||||
|
|
||||||
|
public Func<BaseItem, User, bool> Filter { get; set; }
|
||||||
|
|
||||||
|
public bool? IsFolder { get; set; }
|
||||||
|
public bool? IsFavorite { get; set; }
|
||||||
|
public bool? IsPlayed { get; set; }
|
||||||
|
public bool? IsResumable { get; set; }
|
||||||
|
|
||||||
|
public string[] MediaTypes { get; set; }
|
||||||
|
|
||||||
|
public UserItemsQuery()
|
||||||
|
{
|
||||||
|
SortBy = new string[] { };
|
||||||
|
MediaTypes = new string[] { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Library;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -14,6 +16,17 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UserRootFolder : Folder
|
public class UserRootFolder : Folder
|
||||||
{
|
{
|
||||||
|
public override async Task<QueryResult<BaseItem>> GetUserItems(UserItemsQuery query)
|
||||||
|
{
|
||||||
|
var result = await UserViewManager.GetUserViews(new UserViewQuery
|
||||||
|
{
|
||||||
|
UserId = query.User.Id.ToString("N")
|
||||||
|
|
||||||
|
}, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return SortAndFilter(result, query);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the children of this folder from the actual file system
|
/// Get the children of this folder from the actual file system
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
using MediaBrowser.Controller.Entities.Movies;
|
using MediaBrowser.Controller.TV;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
|
||||||
using MediaBrowser.Controller.Library;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.LiveTv;
|
using MediaBrowser.Model.Querying;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
@ -14,56 +11,37 @@ namespace MediaBrowser.Controller.Entities
|
||||||
public class UserView : Folder
|
public class UserView : Folder
|
||||||
{
|
{
|
||||||
public string ViewType { get; set; }
|
public string ViewType { get; set; }
|
||||||
public static IUserViewManager UserViewManager { get; set; }
|
public Guid ParentId { get; set; }
|
||||||
|
|
||||||
|
public static ITVSeriesManager TVSeriesManager;
|
||||||
|
|
||||||
|
public override Task<QueryResult<BaseItem>> GetUserItems(UserItemsQuery query)
|
||||||
|
{
|
||||||
|
return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager)
|
||||||
|
.GetUserItems(this, ViewType, query);
|
||||||
|
}
|
||||||
|
|
||||||
public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
|
public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
|
||||||
{
|
{
|
||||||
var mediaFolders = GetMediaFolders(user);
|
var result = GetUserItems(new UserItemsQuery
|
||||||
|
|
||||||
switch (ViewType)
|
|
||||||
{
|
{
|
||||||
case CollectionType.LiveTvChannels:
|
User = user
|
||||||
return LiveTvManager.GetInternalChannels(new LiveTvChannelQuery
|
|
||||||
{
|
|
||||||
UserId = user.Id.ToString("N")
|
|
||||||
|
|
||||||
}, CancellationToken.None).Result.Items;
|
}).Result;
|
||||||
case CollectionType.LiveTvRecordingGroups:
|
|
||||||
return LiveTvManager.GetInternalRecordings(new RecordingQuery
|
|
||||||
{
|
|
||||||
UserId = user.Id.ToString("N"),
|
|
||||||
Status = RecordingStatus.Completed
|
|
||||||
|
|
||||||
}, CancellationToken.None).Result.Items;
|
return result.Items;
|
||||||
case CollectionType.LiveTv:
|
|
||||||
return GetLiveTvFolders(user).Result;
|
|
||||||
case CollectionType.Folders:
|
|
||||||
return user.RootFolder.GetChildren(user, includeLinkedChildren);
|
|
||||||
case CollectionType.Games:
|
|
||||||
return mediaFolders.SelectMany(i => i.GetRecursiveChildren(user, includeLinkedChildren))
|
|
||||||
.OfType<GameSystem>();
|
|
||||||
case CollectionType.BoxSets:
|
|
||||||
return mediaFolders.SelectMany(i => i.GetRecursiveChildren(user, includeLinkedChildren))
|
|
||||||
.OfType<BoxSet>();
|
|
||||||
case CollectionType.TvShows:
|
|
||||||
return mediaFolders.SelectMany(i => i.GetRecursiveChildren(user, includeLinkedChildren))
|
|
||||||
.OfType<Series>();
|
|
||||||
case CollectionType.Trailers:
|
|
||||||
return mediaFolders.SelectMany(i => i.GetRecursiveChildren(user, includeLinkedChildren))
|
|
||||||
.OfType<Trailer>();
|
|
||||||
default:
|
|
||||||
return mediaFolders.SelectMany(i => i.GetChildren(user, includeLinkedChildren));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IEnumerable<BaseItem>> GetLiveTvFolders(User user)
|
public override IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true)
|
||||||
{
|
{
|
||||||
var list = new List<BaseItem>();
|
var result = GetUserItems(new UserItemsQuery
|
||||||
|
{
|
||||||
|
User = user,
|
||||||
|
Recursive = true
|
||||||
|
|
||||||
list.Add(await UserViewManager.GetUserView(CollectionType.LiveTvChannels, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
|
}).Result;
|
||||||
list.Add(await UserViewManager.GetUserView(CollectionType.LiveTvRecordingGroups, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
|
|
||||||
|
|
||||||
return list;
|
return result.Items;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
|
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
|
||||||
|
@ -71,16 +49,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
return GetChildren(user, false);
|
return GetChildren(user, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<Folder> GetMediaFolders(User user)
|
|
||||||
{
|
|
||||||
var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
|
|
||||||
|
|
||||||
return user.RootFolder
|
|
||||||
.GetChildren(user, true, true)
|
|
||||||
.OfType<Folder>()
|
|
||||||
.Where(i => !excludeFolderIds.Contains(i.Id) && !IsExcludedFromGrouping(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsExcludedFromGrouping(Folder folder)
|
public static bool IsExcludedFromGrouping(Folder folder)
|
||||||
{
|
{
|
||||||
var standaloneTypes = new List<string>
|
var standaloneTypes = new List<string>
|
||||||
|
|
614
MediaBrowser.Controller/Entities/UserViewBuilder.cs
Normal file
614
MediaBrowser.Controller/Entities/UserViewBuilder.cs
Normal file
|
@ -0,0 +1,614 @@
|
||||||
|
using MediaBrowser.Controller.Channels;
|
||||||
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.LiveTv;
|
||||||
|
using MediaBrowser.Controller.TV;
|
||||||
|
using MediaBrowser.Model.Channels;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.LiveTv;
|
||||||
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public class UserViewBuilder
|
||||||
|
{
|
||||||
|
private readonly IChannelManager _channelManager;
|
||||||
|
private readonly ILiveTvManager _liveTvManager;
|
||||||
|
private readonly IUserViewManager _userViewManager;
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly IUserDataManager _userDataManager;
|
||||||
|
private readonly ITVSeriesManager _tvSeriesManager;
|
||||||
|
|
||||||
|
public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager)
|
||||||
|
{
|
||||||
|
_userViewManager = userViewManager;
|
||||||
|
_liveTvManager = liveTvManager;
|
||||||
|
_channelManager = channelManager;
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
_logger = logger;
|
||||||
|
_userDataManager = userDataManager;
|
||||||
|
_tvSeriesManager = tvSeriesManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<QueryResult<BaseItem>> GetUserItems(Folder parent, string viewType, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
var user = query.User;
|
||||||
|
|
||||||
|
switch (viewType)
|
||||||
|
{
|
||||||
|
case CollectionType.Channels:
|
||||||
|
{
|
||||||
|
var result = await _channelManager.GetChannelsInternal(new ChannelQuery
|
||||||
|
{
|
||||||
|
UserId = user.Id.ToString("N"),
|
||||||
|
Limit = query.Limit,
|
||||||
|
StartIndex = query.StartIndex
|
||||||
|
|
||||||
|
}, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return GetResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
case CollectionType.LiveTvChannels:
|
||||||
|
{
|
||||||
|
var result = await _liveTvManager.GetInternalChannels(new LiveTvChannelQuery
|
||||||
|
{
|
||||||
|
UserId = query.User.Id.ToString("N"),
|
||||||
|
Limit = query.Limit,
|
||||||
|
StartIndex = query.StartIndex
|
||||||
|
|
||||||
|
}, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return GetResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
case CollectionType.LiveTvNowPlaying:
|
||||||
|
{
|
||||||
|
var result = await _liveTvManager.GetRecommendedProgramsInternal(new RecommendedProgramQuery
|
||||||
|
{
|
||||||
|
UserId = query.User.Id.ToString("N"),
|
||||||
|
Limit = query.Limit,
|
||||||
|
IsAiring = true
|
||||||
|
|
||||||
|
}, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return GetResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
case CollectionType.LiveTvRecordingGroups:
|
||||||
|
{
|
||||||
|
var result = await _liveTvManager.GetInternalRecordings(new RecordingQuery
|
||||||
|
{
|
||||||
|
UserId = query.User.Id.ToString("N"),
|
||||||
|
Status = RecordingStatus.Completed,
|
||||||
|
Limit = query.Limit,
|
||||||
|
StartIndex = query.StartIndex
|
||||||
|
|
||||||
|
}, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return GetResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
case CollectionType.LiveTv:
|
||||||
|
{
|
||||||
|
var result = await GetLiveTvFolders(user).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return GetResult(result, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
case CollectionType.Folders:
|
||||||
|
return GetResult(user.RootFolder.GetChildren(user, true), query);
|
||||||
|
|
||||||
|
case CollectionType.Games:
|
||||||
|
return await GetGameView(user, parent, query).ConfigureAwait(false);
|
||||||
|
|
||||||
|
case CollectionType.BoxSets:
|
||||||
|
return GetResult(GetMediaFolders(user).SelectMany(i => i.GetRecursiveChildren(user)).OfType<BoxSet>(), query);
|
||||||
|
|
||||||
|
case CollectionType.TvShows:
|
||||||
|
return await GetTvView(parent, user, query).ConfigureAwait(false);
|
||||||
|
|
||||||
|
case CollectionType.Music:
|
||||||
|
return await GetMusicFolders(parent, user, query).ConfigureAwait(false);
|
||||||
|
|
||||||
|
case CollectionType.Movies:
|
||||||
|
return await GetMovieFolders(parent, user, query).ConfigureAwait(false);
|
||||||
|
|
||||||
|
case CollectionType.GameGenres:
|
||||||
|
return GetGameGenres(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.GameSystems:
|
||||||
|
return GetGameSystems(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.LatestGames:
|
||||||
|
return GetLatestGames(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.RecentlyPlayedGames:
|
||||||
|
return GetRecentlyPlayedGames(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.GameFavorites:
|
||||||
|
return GetFavoriteGames(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.TvSeries:
|
||||||
|
return GetTvSeries(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.TvGenres:
|
||||||
|
return GetTvGenres(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.TvResume:
|
||||||
|
return GetTvResume(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.TvNextUp:
|
||||||
|
return GetTvNextUp(parent, query);
|
||||||
|
|
||||||
|
case CollectionType.TvLatest:
|
||||||
|
return GetTvLatest(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.MovieFavorites:
|
||||||
|
return GetFavoriteMovies(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.MovieLatest:
|
||||||
|
return GetMovieLatest(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.MovieGenres:
|
||||||
|
return GetMovieGenres(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.MovieResume:
|
||||||
|
return GetMovieResume(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.MovieMovies:
|
||||||
|
return GetMovieMovies(parent, user, query);
|
||||||
|
|
||||||
|
case CollectionType.MovieCollections:
|
||||||
|
return GetMovieCollections(parent, user, query);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetSpecialItemsLimit()
|
||||||
|
{
|
||||||
|
return 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<QueryResult<BaseItem>> GetMusicFolders(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
if (query.Recursive)
|
||||||
|
{
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).OfType<MusicArtist>(), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<QueryResult<BaseItem>> GetMovieFolders(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
if (query.Recursive)
|
||||||
|
{
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie || i is BoxSet), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
var list = new List<BaseItem>();
|
||||||
|
|
||||||
|
list.Add(await GetUserView(CollectionType.MovieResume, user, "0", parent).ConfigureAwait(false));
|
||||||
|
list.Add(await GetUserView(CollectionType.MovieLatest, user, "1", parent).ConfigureAwait(false));
|
||||||
|
list.Add(await GetUserView(CollectionType.MovieMovies, user, "2", parent).ConfigureAwait(false));
|
||||||
|
list.Add(await GetUserView(CollectionType.MovieCollections, user, "3", parent).ConfigureAwait(false));
|
||||||
|
list.Add(await GetUserView(CollectionType.MovieFavorites, user, "4", parent).ConfigureAwait(false));
|
||||||
|
list.Add(await GetUserView(CollectionType.MovieGenres, user, "5", parent).ConfigureAwait(false));
|
||||||
|
|
||||||
|
return GetResult(list, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetFavoriteMovies(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
query.IsFavorite = true;
|
||||||
|
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetMovieCollections(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is BoxSet), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
|
||||||
|
query.SortOrder = SortOrder.Descending;
|
||||||
|
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), GetSpecialItemsLimit(), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
|
||||||
|
query.SortOrder = SortOrder.Descending;
|
||||||
|
query.IsResumable = true;
|
||||||
|
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), GetSpecialItemsLimit(), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetMovieGenres(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty })
|
||||||
|
.Where(i => i is Movie)
|
||||||
|
.SelectMany(i => i.Genres)
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Select(i =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _libraryManager.GetGenre(i);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Full exception logged at lower levels
|
||||||
|
_logger.Error("Error getting genre");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
.Where(i => i != null);
|
||||||
|
|
||||||
|
return GetResult(genres, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<QueryResult<BaseItem>> GetTvView(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
if (query.Recursive)
|
||||||
|
{
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series || i is Season || i is Episode), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
var list = new List<BaseItem>();
|
||||||
|
|
||||||
|
list.Add(await GetUserView(CollectionType.TvResume, user, "0", parent).ConfigureAwait(false));
|
||||||
|
list.Add(await GetUserView(CollectionType.TvNextUp, user, "1", parent).ConfigureAwait(false));
|
||||||
|
list.Add(await GetUserView(CollectionType.TvLatest, user, "2", parent).ConfigureAwait(false));
|
||||||
|
list.Add(await GetUserView(CollectionType.TvSeries, user, "3", parent).ConfigureAwait(false));
|
||||||
|
//list.Add(await GetUserView(CollectionType.TvFavorites, user, "4", parent).ConfigureAwait(false));
|
||||||
|
list.Add(await GetUserView(CollectionType.TvGenres, user, "5", parent).ConfigureAwait(false));
|
||||||
|
|
||||||
|
return GetResult(list, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<QueryResult<BaseItem>> GetGameView(User user, Folder parent, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
if (query.Recursive)
|
||||||
|
{
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
var list = new List<BaseItem>();
|
||||||
|
|
||||||
|
list.Add(await GetUserView(CollectionType.LatestGames, user, "0", parent).ConfigureAwait(false));
|
||||||
|
list.Add(await GetUserView(CollectionType.RecentlyPlayedGames, user, "1", parent).ConfigureAwait(false));
|
||||||
|
list.Add(await GetUserView(CollectionType.GameFavorites, user, "2", parent).ConfigureAwait(false));
|
||||||
|
list.Add(await GetUserView(CollectionType.GameSystems, user, "3", parent).ConfigureAwait(false));
|
||||||
|
list.Add(await GetUserView(CollectionType.GameGenres, user, "4", parent).ConfigureAwait(false));
|
||||||
|
|
||||||
|
return GetResult(list, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetLatestGames(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
|
||||||
|
query.SortOrder = SortOrder.Descending;
|
||||||
|
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), GetSpecialItemsLimit(), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetRecentlyPlayedGames(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
query.IsPlayed = true;
|
||||||
|
query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
|
||||||
|
query.SortOrder = SortOrder.Descending;
|
||||||
|
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), GetSpecialItemsLimit(), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetFavoriteGames(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
query.IsFavorite = true;
|
||||||
|
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
|
||||||
|
query.SortOrder = SortOrder.Descending;
|
||||||
|
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), GetSpecialItemsLimit(), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetTvNextUp(Folder parent, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
var parentFolders = GetMediaFolders(parent, query.User, new[] { CollectionType.TvShows, string.Empty });
|
||||||
|
|
||||||
|
var result = _tvSeriesManager.GetNextUp(new NextUpQuery
|
||||||
|
{
|
||||||
|
Limit = query.Limit,
|
||||||
|
StartIndex = query.StartIndex,
|
||||||
|
UserId = query.User.Id.ToString("N")
|
||||||
|
|
||||||
|
}, parentFolders);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetTvResume(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
|
||||||
|
query.SortOrder = SortOrder.Descending;
|
||||||
|
query.IsResumable = true;
|
||||||
|
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), GetSpecialItemsLimit(), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetTvSeries(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Series>(), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetTvGenres(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty })
|
||||||
|
.OfType<Series>()
|
||||||
|
.SelectMany(i => i.Genres)
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Select(i =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _libraryManager.GetGenre(i);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Full exception logged at lower levels
|
||||||
|
_logger.Error("Error getting genre");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
.Where(i => i != null);
|
||||||
|
|
||||||
|
return GetResult(genres, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetGameSystems(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<GameSystem>(), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetGameGenres(Folder parent, User user, UserItemsQuery query)
|
||||||
|
{
|
||||||
|
var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.Games })
|
||||||
|
.OfType<Game>()
|
||||||
|
.SelectMany(i => i.Genres)
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Select(i =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _libraryManager.GetGameGenre(i);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Full exception logged at lower levels
|
||||||
|
_logger.Error("Error getting game genre");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
.Where(i => i != null);
|
||||||
|
|
||||||
|
return GetResult(genres, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetResult<T>(QueryResult<T> result)
|
||||||
|
where T : BaseItem
|
||||||
|
{
|
||||||
|
return new QueryResult<BaseItem>
|
||||||
|
{
|
||||||
|
Items = result.Items,
|
||||||
|
TotalRecordCount = result.TotalRecordCount
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items,
|
||||||
|
UserItemsQuery query)
|
||||||
|
where T : BaseItem
|
||||||
|
{
|
||||||
|
return GetResult(items, null, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items,
|
||||||
|
int? totalRecordLimit,
|
||||||
|
UserItemsQuery query)
|
||||||
|
where T : BaseItem
|
||||||
|
{
|
||||||
|
return SortAndFilter(items, totalRecordLimit, query, _libraryManager, _userDataManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items,
|
||||||
|
int? totalRecordLimit,
|
||||||
|
UserItemsQuery query,
|
||||||
|
ILibraryManager libraryManager,
|
||||||
|
IUserDataManager userDataManager)
|
||||||
|
{
|
||||||
|
var user = query.User;
|
||||||
|
|
||||||
|
items = items.Where(i => Filter(i, user, query, userDataManager));
|
||||||
|
|
||||||
|
return Sort(items, totalRecordLimit, query, libraryManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static QueryResult<BaseItem> Sort(IEnumerable<BaseItem> items,
|
||||||
|
int? totalRecordLimit,
|
||||||
|
UserItemsQuery query,
|
||||||
|
ILibraryManager libraryManager)
|
||||||
|
{
|
||||||
|
var user = query.User;
|
||||||
|
|
||||||
|
items = libraryManager.ReplaceVideosWithPrimaryVersions(items);
|
||||||
|
|
||||||
|
if (query.SortBy.Length > 0)
|
||||||
|
{
|
||||||
|
items = libraryManager.Sort(items, user, query.SortBy, query.SortOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
|
||||||
|
var totalCount = itemsArray.Length;
|
||||||
|
|
||||||
|
if (query.Limit.HasValue)
|
||||||
|
{
|
||||||
|
itemsArray = itemsArray.Skip(query.StartIndex ?? 0).Take(query.Limit.Value).ToArray();
|
||||||
|
}
|
||||||
|
else if (query.StartIndex.HasValue)
|
||||||
|
{
|
||||||
|
itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new QueryResult<BaseItem>
|
||||||
|
{
|
||||||
|
TotalRecordCount = totalCount,
|
||||||
|
Items = itemsArray
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool Filter(BaseItem item, User user, UserItemsQuery query, IUserDataManager userDataManager)
|
||||||
|
{
|
||||||
|
if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.Filter != null && !query.Filter(item, user))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserItemData userData = null;
|
||||||
|
|
||||||
|
if (query.IsFavorite.HasValue)
|
||||||
|
{
|
||||||
|
userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
|
||||||
|
|
||||||
|
if (userData.IsFavorite != query.IsFavorite.Value)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.IsResumable.HasValue)
|
||||||
|
{
|
||||||
|
userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
|
||||||
|
var isResumable = userData.PlaybackPositionTicks > 0;
|
||||||
|
|
||||||
|
if (isResumable != query.IsResumable.Value)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.IsPlayed.HasValue)
|
||||||
|
{
|
||||||
|
if (item.IsPlayed(user) != query.IsPlayed.Value)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<Folder> GetMediaFolders(User user)
|
||||||
|
{
|
||||||
|
var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
|
||||||
|
|
||||||
|
return user.RootFolder
|
||||||
|
.GetChildren(user, true, true)
|
||||||
|
.OfType<Folder>()
|
||||||
|
.Where(i => !excludeFolderIds.Contains(i.Id) && !UserView.IsExcludedFromGrouping(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<Folder> GetMediaFolders(User user, string[] viewTypes)
|
||||||
|
{
|
||||||
|
return GetMediaFolders(user)
|
||||||
|
.Where(i =>
|
||||||
|
{
|
||||||
|
var folder = i as ICollectionFolder;
|
||||||
|
|
||||||
|
return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<Folder> GetMediaFolders(Folder parent, User user, string[] viewTypes)
|
||||||
|
{
|
||||||
|
if (parent == null || parent is UserView)
|
||||||
|
{
|
||||||
|
return GetMediaFolders(user, viewTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new[] { parent };
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<BaseItem> GetRecursiveChildren(Folder parent, User user, string[] viewTypes)
|
||||||
|
{
|
||||||
|
if (parent == null || parent is UserView)
|
||||||
|
{
|
||||||
|
return GetMediaFolders(user, viewTypes).SelectMany(i => i.GetRecursiveChildren(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent.GetRecursiveChildren(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<BaseItem>> GetLiveTvFolders(User user)
|
||||||
|
{
|
||||||
|
var list = new List<BaseItem>();
|
||||||
|
|
||||||
|
list.Add(await _userViewManager.GetUserView(CollectionType.LiveTvNowPlaying, user, "0", CancellationToken.None).ConfigureAwait(false));
|
||||||
|
list.Add(await _userViewManager.GetUserView(CollectionType.LiveTvChannels, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
|
||||||
|
list.Add(await _userViewManager.GetUserView(CollectionType.LiveTvRecordingGroups, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<UserView> GetUserView(string type, User user, string sortName, Folder parent)
|
||||||
|
{
|
||||||
|
var view = await _userViewManager.GetUserView(type, user, sortName, CancellationToken.None)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (parent.Id != view.ParentId)
|
||||||
|
{
|
||||||
|
view.ParentId = parent.Id;
|
||||||
|
await view.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -244,6 +244,15 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
Task<QueryResult<ProgramInfoDto>> GetRecommendedPrograms(RecommendedProgramQuery query,
|
Task<QueryResult<ProgramInfoDto>> GetRecommendedPrograms(RecommendedProgramQuery query,
|
||||||
CancellationToken cancellationToken);
|
CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the recommended programs internal.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The query.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task<QueryResult<LiveTvProgram>>.</returns>
|
||||||
|
Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query,
|
||||||
|
CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the live tv information.
|
/// Gets the live tv information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -157,7 +157,9 @@
|
||||||
<Compile Include="Entities\IHasAwards.cs" />
|
<Compile Include="Entities\IHasAwards.cs" />
|
||||||
<Compile Include="Entities\Photo.cs" />
|
<Compile Include="Entities\Photo.cs" />
|
||||||
<Compile Include="Entities\PhotoAlbum.cs" />
|
<Compile Include="Entities\PhotoAlbum.cs" />
|
||||||
|
<Compile Include="Entities\UserItemsQuery.cs" />
|
||||||
<Compile Include="Entities\UserView.cs" />
|
<Compile Include="Entities\UserView.cs" />
|
||||||
|
<Compile Include="Entities\UserViewBuilder.cs" />
|
||||||
<Compile Include="FileOrganization\IFileOrganizationService.cs" />
|
<Compile Include="FileOrganization\IFileOrganizationService.cs" />
|
||||||
<Compile Include="Library\DeleteOptions.cs" />
|
<Compile Include="Library\DeleteOptions.cs" />
|
||||||
<Compile Include="Library\ILibraryPostScanTask.cs" />
|
<Compile Include="Library\ILibraryPostScanTask.cs" />
|
||||||
|
@ -336,6 +338,7 @@
|
||||||
<Compile Include="Sync\ISyncRepository.cs" />
|
<Compile Include="Sync\ISyncRepository.cs" />
|
||||||
<Compile Include="Themes\IAppThemeManager.cs" />
|
<Compile Include="Themes\IAppThemeManager.cs" />
|
||||||
<Compile Include="Themes\InternalThemeImage.cs" />
|
<Compile Include="Themes\InternalThemeImage.cs" />
|
||||||
|
<Compile Include="TV\ITVSeriesManager.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||||
|
@ -360,7 +363,7 @@ xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i
|
||||||
<PreBuildEvent>
|
<PreBuildEvent>
|
||||||
</PreBuildEvent>
|
</PreBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
<Target Name="BeforeBuild">
|
<Target Name="BeforeBuild">
|
||||||
|
|
24
MediaBrowser.Controller/TV/ITVSeriesManager.cs
Normal file
24
MediaBrowser.Controller/TV/ITVSeriesManager.cs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.TV
|
||||||
|
{
|
||||||
|
public interface ITVSeriesManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the next up.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The query.</param>
|
||||||
|
/// <returns>QueryResult<BaseItem>.</returns>
|
||||||
|
QueryResult<BaseItem> GetNextUp(NextUpQuery query);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the next up.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="parentsFolders">The parents folders.</param>
|
||||||
|
/// <returns>QueryResult<BaseItem>.</returns>
|
||||||
|
QueryResult<BaseItem> GetNextUp(NextUpQuery request, IEnumerable<Folder> parentsFolders);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Channels;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
|
@ -22,8 +21,6 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
private readonly IDlnaManager _dlna;
|
private readonly IDlnaManager _dlna;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IUserViewManager _userViewManager;
|
|
||||||
private readonly IChannelManager _channelManager;
|
|
||||||
|
|
||||||
public ContentDirectory(IDlnaManager dlna,
|
public ContentDirectory(IDlnaManager dlna,
|
||||||
IUserDataManager userDataManager,
|
IUserDataManager userDataManager,
|
||||||
|
@ -32,7 +29,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
IServerConfigurationManager config,
|
IServerConfigurationManager config,
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IHttpClient httpClient, IUserViewManager userViewManager, IChannelManager channelManager)
|
IHttpClient httpClient)
|
||||||
: base(logger, httpClient)
|
: base(logger, httpClient)
|
||||||
{
|
{
|
||||||
_dlna = dlna;
|
_dlna = dlna;
|
||||||
|
@ -41,8 +38,6 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_config = config;
|
_config = config;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_userViewManager = userViewManager;
|
|
||||||
_channelManager = channelManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int SystemUpdateId
|
private int SystemUpdateId
|
||||||
|
@ -78,9 +73,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
_userDataManager,
|
_userDataManager,
|
||||||
user,
|
user,
|
||||||
SystemUpdateId,
|
SystemUpdateId,
|
||||||
_config,
|
_config)
|
||||||
_userViewManager,
|
|
||||||
_channelManager)
|
|
||||||
.ProcessControlRequest(request);
|
.ProcessControlRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,18 @@
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Controller.Channels;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
|
||||||
using MediaBrowser.Controller.Entities.Movies;
|
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Playlists;
|
|
||||||
using MediaBrowser.Dlna.Didl;
|
using MediaBrowser.Dlna.Didl;
|
||||||
using MediaBrowser.Dlna.Server;
|
using MediaBrowser.Dlna.Server;
|
||||||
using MediaBrowser.Dlna.Service;
|
using MediaBrowser.Dlna.Service;
|
||||||
using MediaBrowser.Model.Channels;
|
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Library;
|
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -45,21 +37,17 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
private readonly DidlBuilder _didlBuilder;
|
private readonly DidlBuilder _didlBuilder;
|
||||||
|
|
||||||
private readonly DeviceProfile _profile;
|
private readonly DeviceProfile _profile;
|
||||||
private readonly IUserViewManager _userViewManager;
|
|
||||||
private readonly IChannelManager _channelManager;
|
|
||||||
|
|
||||||
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, IUserViewManager userViewManager, IChannelManager channelManager)
|
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config)
|
||||||
: base(config, logger)
|
: base(config, logger)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_userDataManager = userDataManager;
|
_userDataManager = userDataManager;
|
||||||
_user = user;
|
_user = user;
|
||||||
_systemUpdateId = systemUpdateId;
|
_systemUpdateId = systemUpdateId;
|
||||||
_userViewManager = userViewManager;
|
|
||||||
_channelManager = channelManager;
|
|
||||||
_profile = profile;
|
_profile = profile;
|
||||||
|
|
||||||
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress);
|
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, userDataManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
|
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
|
||||||
|
@ -202,7 +190,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
var childrenResult = (await GetChildrenSorted(folder, user, sortCriteria, start, requested).ConfigureAwait(false));
|
var childrenResult = (await GetUserItems(folder, user, sortCriteria, start, requested).ConfigureAwait(false));
|
||||||
totalCount = childrenResult.TotalRecordCount;
|
totalCount = childrenResult.TotalRecordCount;
|
||||||
|
|
||||||
result.DocumentElement.AppendChild(_didlBuilder.GetFolderElement(result, folder, totalCount, filter, id));
|
result.DocumentElement.AppendChild(_didlBuilder.GetFolderElement(result, folder, totalCount, filter, id));
|
||||||
|
@ -213,7 +201,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
{
|
{
|
||||||
var folder = (Folder)item;
|
var folder = (Folder)item;
|
||||||
|
|
||||||
var childrenResult = (await GetChildrenSorted(folder, user, sortCriteria, start, requested).ConfigureAwait(false));
|
var childrenResult = (await GetUserItems(folder, user, sortCriteria, start, requested).ConfigureAwait(false));
|
||||||
totalCount = childrenResult.TotalRecordCount;
|
totalCount = childrenResult.TotalRecordCount;
|
||||||
|
|
||||||
provided = childrenResult.Items.Length;
|
provided = childrenResult.Items.Length;
|
||||||
|
@ -223,7 +211,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
if (i.IsFolder)
|
if (i.IsFolder)
|
||||||
{
|
{
|
||||||
var f = (Folder)i;
|
var f = (Folder)i;
|
||||||
var childCount = (await GetChildrenSorted(f, user, sortCriteria, null, 0).ConfigureAwait(false))
|
var childCount = (await GetUserItems(f, user, sortCriteria, null, 0).ConfigureAwait(false))
|
||||||
.TotalRecordCount;
|
.TotalRecordCount;
|
||||||
|
|
||||||
result.DocumentElement.AppendChild(_didlBuilder.GetFolderElement(result, f, childCount, filter));
|
result.DocumentElement.AppendChild(_didlBuilder.GetFolderElement(result, f, childCount, filter));
|
||||||
|
@ -321,216 +309,97 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||||
|
|
||||||
private async Task<QueryResult<BaseItem>> GetChildrenSorted(Folder folder, User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit)
|
private async Task<QueryResult<BaseItem>> GetChildrenSorted(Folder folder, User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit)
|
||||||
{
|
{
|
||||||
// TODO: Make a recursive version of GetChildrenSorted (although sorting isn't needed)
|
var sortOrders = new List<string>();
|
||||||
var result = folder.GetRecursiveChildren(user, true);
|
if (!folder.IsPreSorted)
|
||||||
|
{
|
||||||
|
sortOrders.Add(ItemSortBy.SortName);
|
||||||
|
}
|
||||||
|
|
||||||
var items = FilterUnsupportedContent(result);
|
var mediaTypes = new List<string>();
|
||||||
|
bool? isFolder = null;
|
||||||
|
|
||||||
if (search.SearchType == SearchType.Audio)
|
if (search.SearchType == SearchType.Audio)
|
||||||
{
|
{
|
||||||
items = items.OfType<Audio>();
|
mediaTypes.Add(MediaType.Audio);
|
||||||
|
isFolder = false;
|
||||||
}
|
}
|
||||||
else if (search.SearchType == SearchType.Video)
|
else if (search.SearchType == SearchType.Video)
|
||||||
{
|
{
|
||||||
items = items.OfType<Video>();
|
mediaTypes.Add(MediaType.Video);
|
||||||
|
isFolder = false;
|
||||||
}
|
}
|
||||||
else if (search.SearchType == SearchType.Image)
|
else if (search.SearchType == SearchType.Image)
|
||||||
{
|
{
|
||||||
items = items.OfType<Photo>();
|
mediaTypes.Add(MediaType.Photo);
|
||||||
|
isFolder = false;
|
||||||
}
|
}
|
||||||
else if (search.SearchType == SearchType.Playlist)
|
else if (search.SearchType == SearchType.Playlist)
|
||||||
{
|
{
|
||||||
items = items.OfType<Playlist>();
|
//items = items.OfType<Playlist>();
|
||||||
|
isFolder = true;
|
||||||
}
|
}
|
||||||
else if (search.SearchType == SearchType.MusicAlbum)
|
else if (search.SearchType == SearchType.MusicAlbum)
|
||||||
{
|
{
|
||||||
items = items.OfType<MusicAlbum>();
|
//items = items.OfType<MusicAlbum>();
|
||||||
|
isFolder = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return await folder.GetUserItems(new UserItemsQuery
|
||||||
|
{
|
||||||
|
Limit = limit,
|
||||||
|
StartIndex = startIndex,
|
||||||
|
SortBy = sortOrders.ToArray(),
|
||||||
|
SortOrder = sort.SortOrder,
|
||||||
|
User = user,
|
||||||
|
Recursive = true,
|
||||||
|
Filter = FilterUnsupportedContent,
|
||||||
|
IsFolder = isFolder,
|
||||||
|
MediaTypes = mediaTypes.ToArray()
|
||||||
|
|
||||||
items = SortItems(items, user, sort);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
return ToResult(items, startIndex, limit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<QueryResult<BaseItem>> GetChildrenSorted(Folder folder, User user, SortCriteria sort, int? startIndex, int? limit)
|
private async Task<QueryResult<BaseItem>> GetUserItems(Folder folder, User user, SortCriteria sort, int? startIndex, int? limit)
|
||||||
{
|
{
|
||||||
if (folder is UserRootFolder)
|
var sortOrders = new List<string>();
|
||||||
|
if (!folder.IsPreSorted)
|
||||||
{
|
{
|
||||||
var result = await _userViewManager.GetUserViews(new UserViewQuery
|
sortOrders.Add(ItemSortBy.SortName);
|
||||||
{
|
|
||||||
UserId = user.Id.ToString("N")
|
|
||||||
|
|
||||||
}, CancellationToken.None).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return ToResult(result, startIndex, limit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var view = folder as UserView;
|
return await folder.GetUserItems(new UserItemsQuery
|
||||||
|
|
||||||
if (view != null)
|
|
||||||
{
|
{
|
||||||
var result = await GetUserViewChildren(view, user, sort).ConfigureAwait(false);
|
Limit = limit,
|
||||||
|
StartIndex = startIndex,
|
||||||
|
SortBy = sortOrders.ToArray(),
|
||||||
|
SortOrder = sort.SortOrder,
|
||||||
|
User = user,
|
||||||
|
Filter = FilterUnsupportedContent
|
||||||
|
|
||||||
return ToResult(result, startIndex, limit);
|
}).ConfigureAwait(false);
|
||||||
}
|
|
||||||
|
|
||||||
var channel = folder as Channel;
|
|
||||||
|
|
||||||
if (channel != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Don't blow up here because it could cause parent screens with other content to fail
|
|
||||||
return await _channelManager.GetChannelItemsInternal(new ChannelItemQuery
|
|
||||||
{
|
|
||||||
ChannelId = channel.Id.ToString("N"),
|
|
||||||
Limit = limit,
|
|
||||||
StartIndex = startIndex,
|
|
||||||
UserId = user.Id.ToString("N")
|
|
||||||
|
|
||||||
}, CancellationToken.None);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Already logged at lower levels
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var channelFolderItem = folder as ChannelFolderItem;
|
|
||||||
|
|
||||||
if (channelFolderItem != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Don't blow up here because it could cause parent screens with other content to fail
|
|
||||||
return await _channelManager.GetChannelItemsInternal(new ChannelItemQuery
|
|
||||||
{
|
|
||||||
ChannelId = channelFolderItem.ChannelId,
|
|
||||||
FolderId = channelFolderItem.Id.ToString("N"),
|
|
||||||
Limit = limit,
|
|
||||||
StartIndex = startIndex,
|
|
||||||
UserId = user.Id.ToString("N")
|
|
||||||
|
|
||||||
}, CancellationToken.None);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Already logged at lower levels
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ToResult(GetPlainFolderChildrenSorted(folder, user, sort), startIndex, limit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueryResult<BaseItem> ToResult(IEnumerable<BaseItem> items, int? startIndex, int? limit)
|
private bool FilterUnsupportedContent(BaseItem i, User user)
|
||||||
{
|
{
|
||||||
var list = items.ToArray();
|
// Unplayable
|
||||||
var totalCount = list.Length;
|
if (i.LocationType == LocationType.Virtual && !i.IsFolder)
|
||||||
|
|
||||||
if (startIndex.HasValue)
|
|
||||||
{
|
{
|
||||||
list = list.Skip(startIndex.Value).ToArray();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (limit.HasValue)
|
// Unplayable
|
||||||
|
var supportsPlaceHolder = i as ISupportsPlaceHolders;
|
||||||
|
if (supportsPlaceHolder != null && supportsPlaceHolder.IsPlaceHolder)
|
||||||
{
|
{
|
||||||
list = list.Take(limit.Value).ToArray();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new QueryResult<BaseItem>
|
if (i is Game || i is Book)
|
||||||
{
|
{
|
||||||
Items = list,
|
//return false;
|
||||||
TotalRecordCount = totalCount
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<IEnumerable<BaseItem>> GetUserViewChildren(UserView folder, User user, SortCriteria sort)
|
|
||||||
{
|
|
||||||
if (string.Equals(folder.ViewType, CollectionType.Channels, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
var result = await _channelManager.GetChannelsInternal(new ChannelQuery()
|
|
||||||
{
|
|
||||||
UserId = user.Id.ToString("N")
|
|
||||||
|
|
||||||
}, CancellationToken.None).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return result.Items;
|
|
||||||
}
|
|
||||||
if (string.Equals(folder.ViewType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return SortItems(folder.GetChildren(user, true).OfType<Series>(), user, sort);
|
|
||||||
}
|
|
||||||
if (string.Equals(folder.ViewType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return SortItems(folder.GetRecursiveChildren(user, true).OfType<Movie>(), user, sort);
|
|
||||||
}
|
|
||||||
if (string.Equals(folder.ViewType, CollectionType.Music, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return SortItems(folder.GetChildren(user, true).OfType<MusicArtist>(), user, sort);
|
|
||||||
}
|
|
||||||
if (string.Equals(folder.ViewType, CollectionType.Folders, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return SortItems(folder.GetChildren(user, true), user, sort);
|
|
||||||
}
|
|
||||||
if (string.Equals(folder.ViewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return SortItems(folder.GetChildren(user, true), user, sort);
|
|
||||||
}
|
|
||||||
if (string.Equals(folder.ViewType, CollectionType.LiveTvRecordingGroups, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return SortItems(folder.GetChildren(user, true), user, sort);
|
|
||||||
}
|
|
||||||
if (string.Equals(folder.ViewType, CollectionType.LiveTvChannels, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return SortItems(folder.GetChildren(user, true), user, sort);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetPlainFolderChildrenSorted(folder, user, sort);
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<BaseItem> GetPlainFolderChildrenSorted(Folder folder, User user, SortCriteria sort)
|
|
||||||
{
|
|
||||||
var items = folder.GetChildren(user, true);
|
|
||||||
|
|
||||||
items = FilterUnsupportedContent(items);
|
|
||||||
|
|
||||||
if (folder.IsPreSorted)
|
|
||||||
{
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SortItems(items, user, sort);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<BaseItem> SortItems(IEnumerable<BaseItem> items, User user, SortCriteria sort)
|
|
||||||
{
|
|
||||||
return _libraryManager.Sort(items, user, new[] { ItemSortBy.SortName }, sort.SortOrder);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<BaseItem> FilterUnsupportedContent(IEnumerable<BaseItem> items)
|
|
||||||
{
|
|
||||||
return items.Where(i =>
|
|
||||||
{
|
|
||||||
// Unplayable
|
|
||||||
if (i.LocationType == LocationType.Virtual && !i.IsFolder)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unplayable
|
|
||||||
var supportsPlaceHolder = i as ISupportsPlaceHolders;
|
|
||||||
if (supportsPlaceHolder != null && supportsPlaceHolder.IsPlaceHolder)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i is Game || i is Book)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BaseItem GetItemFromObjectId(string id, User user)
|
private BaseItem GetItemFromObjectId(string id, User user)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System.IO;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
|
@ -6,16 +6,16 @@ using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Entities.Movies;
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Playlists;
|
using MediaBrowser.Controller.Playlists;
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.Didl
|
namespace MediaBrowser.Dlna.Didl
|
||||||
{
|
{
|
||||||
|
@ -32,12 +32,14 @@ namespace MediaBrowser.Dlna.Didl
|
||||||
private readonly IImageProcessor _imageProcessor;
|
private readonly IImageProcessor _imageProcessor;
|
||||||
private readonly string _serverAddress;
|
private readonly string _serverAddress;
|
||||||
private readonly User _user;
|
private readonly User _user;
|
||||||
|
private readonly IUserDataManager _userDataManager;
|
||||||
|
|
||||||
public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress)
|
public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, IUserDataManager userDataManager)
|
||||||
{
|
{
|
||||||
_profile = profile;
|
_profile = profile;
|
||||||
_imageProcessor = imageProcessor;
|
_imageProcessor = imageProcessor;
|
||||||
_serverAddress = serverAddress;
|
_serverAddress = serverAddress;
|
||||||
|
_userDataManager = userDataManager;
|
||||||
_user = user;
|
_user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,7 +679,20 @@ namespace MediaBrowser.Dlna.Didl
|
||||||
|
|
||||||
var result = element.OwnerDocument;
|
var result = element.OwnerDocument;
|
||||||
|
|
||||||
var albumartUrlInfo = GetImageUrl(imageInfo, _profile.MaxAlbumArtWidth, _profile.MaxAlbumArtHeight, "jpg");
|
var playbackPercentage = 0;
|
||||||
|
|
||||||
|
if (item is Video)
|
||||||
|
{
|
||||||
|
var userData = _userDataManager.GetUserDataDto(item, _user);
|
||||||
|
|
||||||
|
playbackPercentage = Convert.ToInt32(userData.PlayedPercentage ?? 0);
|
||||||
|
if (playbackPercentage >= 100)
|
||||||
|
{
|
||||||
|
playbackPercentage = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var albumartUrlInfo = GetImageUrl(imageInfo, _profile.MaxAlbumArtWidth, _profile.MaxAlbumArtHeight, playbackPercentage, "jpg");
|
||||||
|
|
||||||
var icon = result.CreateElement("upnp", "albumArtURI", NS_UPNP);
|
var icon = result.CreateElement("upnp", "albumArtURI", NS_UPNP);
|
||||||
var profile = result.CreateAttribute("dlna", "profileID", NS_DLNA);
|
var profile = result.CreateAttribute("dlna", "profileID", NS_DLNA);
|
||||||
|
@ -687,7 +702,7 @@ namespace MediaBrowser.Dlna.Didl
|
||||||
element.AppendChild(icon);
|
element.AppendChild(icon);
|
||||||
|
|
||||||
// TOOD: Remove these default values
|
// TOOD: Remove these default values
|
||||||
var iconUrlInfo = GetImageUrl(imageInfo, _profile.MaxIconWidth ?? 48, _profile.MaxIconHeight ?? 48, "jpg");
|
var iconUrlInfo = GetImageUrl(imageInfo, _profile.MaxIconWidth ?? 48, _profile.MaxIconHeight ?? 48, playbackPercentage, "jpg");
|
||||||
icon = result.CreateElement("upnp", "icon", NS_UPNP);
|
icon = result.CreateElement("upnp", "icon", NS_UPNP);
|
||||||
icon.InnerText = iconUrlInfo.Url;
|
icon.InnerText = iconUrlInfo.Url;
|
||||||
element.AppendChild(icon);
|
element.AppendChild(icon);
|
||||||
|
@ -703,18 +718,19 @@ namespace MediaBrowser.Dlna.Didl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddImageResElement(item, element, 4096, 4096, "jpg", "JPEG_LRG");
|
AddImageResElement(item, element, 4096, 4096, playbackPercentage, "jpg", "JPEG_LRG");
|
||||||
AddImageResElement(item, element, 4096, 4096, "png", "PNG_LRG");
|
AddImageResElement(item, element, 4096, 4096, playbackPercentage, "png", "PNG_LRG");
|
||||||
AddImageResElement(item, element, 1024, 768, "jpg", "JPEG_MED");
|
AddImageResElement(item, element, 1024, 768, playbackPercentage, "jpg", "JPEG_MED");
|
||||||
AddImageResElement(item, element, 640, 480, "jpg", "JPEG_SM");
|
AddImageResElement(item, element, 640, 480, playbackPercentage, "jpg", "JPEG_SM");
|
||||||
AddImageResElement(item, element, 160, 160, "jpg", "JPEG_TN");
|
AddImageResElement(item, element, 160, 160, playbackPercentage, "jpg", "JPEG_TN");
|
||||||
AddImageResElement(item, element, 160, 160, "png", "PNG_TN");
|
AddImageResElement(item, element, 160, 160, playbackPercentage, "png", "PNG_TN");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddImageResElement(BaseItem item,
|
private void AddImageResElement(BaseItem item,
|
||||||
XmlElement element,
|
XmlElement element,
|
||||||
int maxWidth,
|
int maxWidth,
|
||||||
int maxHeight,
|
int maxHeight,
|
||||||
|
int playbackPercentage,
|
||||||
string format,
|
string format,
|
||||||
string org_Pn)
|
string org_Pn)
|
||||||
{
|
{
|
||||||
|
@ -727,7 +743,7 @@ namespace MediaBrowser.Dlna.Didl
|
||||||
|
|
||||||
var result = element.OwnerDocument;
|
var result = element.OwnerDocument;
|
||||||
|
|
||||||
var albumartUrlInfo = GetImageUrl(imageInfo, maxWidth, maxHeight, format);
|
var albumartUrlInfo = GetImageUrl(imageInfo, maxWidth, maxHeight, playbackPercentage, format);
|
||||||
|
|
||||||
var res = result.CreateElement(string.Empty, "res", NS_DIDL);
|
var res = result.CreateElement(string.Empty, "res", NS_DIDL);
|
||||||
|
|
||||||
|
@ -849,16 +865,18 @@ namespace MediaBrowser.Dlna.Didl
|
||||||
internal int? Height;
|
internal int? Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImageUrlInfo GetImageUrl(ImageDownloadInfo info, int maxWidth, int maxHeight, string format)
|
private ImageUrlInfo GetImageUrl(ImageDownloadInfo info, int maxWidth, int maxHeight, int playbackPercentage, string format)
|
||||||
{
|
{
|
||||||
var url = string.Format("{0}/Items/{1}/Images/{2}/0/{3}/{4}/{5}/{6}",
|
var url = string.Format("{0}/Items/{1}/Images/{2}/0/{3}/{4}/{5}/{6}/{7}",
|
||||||
_serverAddress,
|
_serverAddress,
|
||||||
info.ItemId,
|
info.ItemId,
|
||||||
info.Type,
|
info.Type,
|
||||||
info.ImageTag,
|
info.ImageTag,
|
||||||
format,
|
format,
|
||||||
maxWidth,
|
maxWidth.ToString(CultureInfo.InvariantCulture),
|
||||||
maxHeight);
|
maxHeight.ToString(CultureInfo.InvariantCulture),
|
||||||
|
playbackPercentage.ToString(CultureInfo.InvariantCulture)
|
||||||
|
);
|
||||||
|
|
||||||
var width = info.Width;
|
var width = info.Width;
|
||||||
var height = info.Height;
|
var height = info.Height;
|
||||||
|
|
|
@ -34,14 +34,15 @@ namespace MediaBrowser.Dlna.Main
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IDlnaManager _dlnaManager;
|
private readonly IDlnaManager _dlnaManager;
|
||||||
private readonly IImageProcessor _imageProcessor;
|
private readonly IImageProcessor _imageProcessor;
|
||||||
|
private readonly IUserDataManager _userDataManager;
|
||||||
|
|
||||||
private SsdpHandler _ssdpHandler;
|
private SsdpHandler _ssdpHandler;
|
||||||
private DeviceDiscovery _deviceDiscovery;
|
private DeviceDiscovery _deviceDiscovery;
|
||||||
|
|
||||||
private readonly List<string> _registeredServerIds = new List<string>();
|
private readonly List<string> _registeredServerIds = new List<string>();
|
||||||
private bool _dlnaServerStarted;
|
private bool _dlnaServerStarted;
|
||||||
|
|
||||||
public DlnaEntryPoint(IServerConfigurationManager config, ILogManager logManager, IServerApplicationHost appHost, INetworkManager network, ISessionManager sessionManager, IHttpClient httpClient, IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IImageProcessor imageProcessor)
|
public DlnaEntryPoint(IServerConfigurationManager config, ILogManager logManager, IServerApplicationHost appHost, INetworkManager network, ISessionManager sessionManager, IHttpClient httpClient, IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IImageProcessor imageProcessor, IUserDataManager userDataManager)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_appHost = appHost;
|
_appHost = appHost;
|
||||||
|
@ -53,6 +54,7 @@ namespace MediaBrowser.Dlna.Main
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_dlnaManager = dlnaManager;
|
_dlnaManager = dlnaManager;
|
||||||
_imageProcessor = imageProcessor;
|
_imageProcessor = imageProcessor;
|
||||||
|
_userDataManager = userDataManager;
|
||||||
_logger = logManager.GetLogger("Dlna");
|
_logger = logManager.GetLogger("Dlna");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +220,8 @@ namespace MediaBrowser.Dlna.Main
|
||||||
_imageProcessor,
|
_imageProcessor,
|
||||||
_deviceDiscovery,
|
_deviceDiscovery,
|
||||||
_httpClient,
|
_httpClient,
|
||||||
_config);
|
_config,
|
||||||
|
_userDataManager);
|
||||||
|
|
||||||
_manager.Start();
|
_manager.Start();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
private readonly IDlnaManager _dlnaManager;
|
private readonly IDlnaManager _dlnaManager;
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IImageProcessor _imageProcessor;
|
private readonly IImageProcessor _imageProcessor;
|
||||||
|
private readonly IUserDataManager _userDataManager;
|
||||||
|
|
||||||
private readonly DeviceDiscovery _deviceDiscovery;
|
private readonly DeviceDiscovery _deviceDiscovery;
|
||||||
private readonly string _serverAddress;
|
private readonly string _serverAddress;
|
||||||
|
@ -51,7 +52,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
private Timer _updateTimer;
|
private Timer _updateTimer;
|
||||||
|
|
||||||
public PlayToController(SessionInfo session, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, DeviceDiscovery deviceDiscovery)
|
public PlayToController(SessionInfo session, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, DeviceDiscovery deviceDiscovery, IUserDataManager userDataManager)
|
||||||
{
|
{
|
||||||
_session = session;
|
_session = session;
|
||||||
_itemRepository = itemRepository;
|
_itemRepository = itemRepository;
|
||||||
|
@ -62,6 +63,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
_imageProcessor = imageProcessor;
|
_imageProcessor = imageProcessor;
|
||||||
_serverAddress = serverAddress;
|
_serverAddress = serverAddress;
|
||||||
_deviceDiscovery = deviceDiscovery;
|
_deviceDiscovery = deviceDiscovery;
|
||||||
|
_userDataManager = userDataManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +476,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
playlistItem.StreamUrl = playlistItem.StreamInfo.ToUrl(serverAddress);
|
playlistItem.StreamUrl = playlistItem.StreamInfo.ToUrl(serverAddress);
|
||||||
|
|
||||||
var itemXml = new DidlBuilder(profile, user, _imageProcessor, serverAddress).GetItemDidl(item, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
|
var itemXml = new DidlBuilder(profile, user, _imageProcessor, serverAddress, _userDataManager).GetItemDidl(item, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
|
||||||
|
|
||||||
playlistItem.Didl = itemXml;
|
playlistItem.Didl = itemXml;
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,11 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
private readonly IImageProcessor _imageProcessor;
|
private readonly IImageProcessor _imageProcessor;
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
|
private readonly IUserDataManager _userDataManager;
|
||||||
|
|
||||||
private readonly DeviceDiscovery _deviceDiscovery;
|
private readonly DeviceDiscovery _deviceDiscovery;
|
||||||
|
|
||||||
public PlayToManager(ILogger logger, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, DeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config)
|
public PlayToManager(ILogger logger, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, DeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_sessionManager = sessionManager;
|
_sessionManager = sessionManager;
|
||||||
|
@ -45,6 +46,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
_deviceDiscovery = deviceDiscovery;
|
_deviceDiscovery = deviceDiscovery;
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
_userDataManager = userDataManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
|
@ -103,7 +105,8 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
_userManager,
|
_userManager,
|
||||||
_imageProcessor,
|
_imageProcessor,
|
||||||
serverAddress,
|
serverAddress,
|
||||||
_deviceDiscovery);
|
_deviceDiscovery,
|
||||||
|
_userDataManager);
|
||||||
|
|
||||||
controller.Init(device);
|
controller.Init(device);
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int SendCount { get; private set; }
|
public int SendCount { get; private set; }
|
||||||
|
|
||||||
|
public bool HandleBindError { get; set; }
|
||||||
|
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public Datagram(IPEndPoint toEndPoint, IPEndPoint fromEndPoint, ILogger logger, string message, int totalSendCount)
|
public Datagram(IPEndPoint toEndPoint, IPEndPoint fromEndPoint, ILogger logger, string message, int totalSendCount)
|
||||||
|
@ -42,7 +44,17 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
|
|
||||||
if (FromEndPoint != null)
|
if (FromEndPoint != null)
|
||||||
{
|
{
|
||||||
client.Bind(FromEndPoint);
|
try
|
||||||
|
{
|
||||||
|
client.Bind(FromEndPoint);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
if (!HandleBindError)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client.BeginSendTo(msg, 0, msg.Length, SocketFlags.None, ToEndPoint, result =>
|
client.BeginSendTo(msg, 0, msg.Length, SocketFlags.None, ToEndPoint, result =>
|
||||||
|
|
|
@ -65,7 +65,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
string mx = null;
|
string mx = null;
|
||||||
args.Headers.TryGetValue("mx", out mx);
|
args.Headers.TryGetValue("mx", out mx);
|
||||||
int delaySeconds;
|
int delaySeconds;
|
||||||
if (!string.IsNullOrWhiteSpace(mx) &&
|
if (!string.IsNullOrWhiteSpace(mx) &&
|
||||||
int.TryParse(mx, NumberStyles.Any, CultureInfo.InvariantCulture, out delaySeconds)
|
int.TryParse(mx, NumberStyles.Any, CultureInfo.InvariantCulture, out delaySeconds)
|
||||||
&& delaySeconds > 0)
|
&& delaySeconds > 0)
|
||||||
{
|
{
|
||||||
|
@ -124,18 +124,23 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
IPEndPoint localAddress,
|
IPEndPoint localAddress,
|
||||||
int sendCount = 1)
|
int sendCount = 1)
|
||||||
{
|
{
|
||||||
SendDatagram(header, values, _ssdpEndp, localAddress, sendCount);
|
SendDatagram(header, values, _ssdpEndp, localAddress, false, sendCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendDatagram(string header,
|
public void SendDatagram(string header,
|
||||||
Dictionary<string, string> values,
|
Dictionary<string, string> values,
|
||||||
IPEndPoint endpoint,
|
IPEndPoint endpoint,
|
||||||
IPEndPoint localAddress,
|
IPEndPoint localAddress,
|
||||||
|
bool handleBindError,
|
||||||
int sendCount = 1)
|
int sendCount = 1)
|
||||||
{
|
{
|
||||||
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
|
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
|
||||||
|
|
||||||
var dgram = new Datagram(endpoint, localAddress, _logger, msg, sendCount);
|
var dgram = new Datagram(endpoint, localAddress, _logger, msg, sendCount)
|
||||||
|
{
|
||||||
|
HandleBindError = handleBindError
|
||||||
|
};
|
||||||
|
|
||||||
if (_messageQueue.Count == 0)
|
if (_messageQueue.Count == 0)
|
||||||
{
|
{
|
||||||
dgram.Send();
|
dgram.Send();
|
||||||
|
@ -170,10 +175,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
values["ST"] = d.Type;
|
values["ST"] = d.Type;
|
||||||
values["USN"] = d.USN;
|
values["USN"] = d.USN;
|
||||||
|
|
||||||
// Commenting this out because binding to the local ipendpoint often throws an error
|
SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0), true);
|
||||||
//SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0));
|
|
||||||
|
|
||||||
SendDatagram(header, values, endpoint, null);
|
|
||||||
|
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||||
{
|
{
|
||||||
|
|
|
@ -91,7 +91,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
<Target Name="BeforeBuild">
|
<Target Name="BeforeBuild">
|
||||||
|
|
|
@ -26,7 +26,28 @@
|
||||||
public const string Playlists = "playlists";
|
public const string Playlists = "playlists";
|
||||||
public const string Folders = "folders";
|
public const string Folders = "folders";
|
||||||
|
|
||||||
|
public const string LiveTvNowPlaying = "LiveTvNowPlaying";
|
||||||
public const string LiveTvChannels = "LiveTvChannels";
|
public const string LiveTvChannels = "LiveTvChannels";
|
||||||
public const string LiveTvRecordingGroups = "LiveTvRecordingGroups";
|
public const string LiveTvRecordingGroups = "LiveTvRecordingGroups";
|
||||||
|
|
||||||
|
public const string TvSeries = "TvSeries";
|
||||||
|
public const string TvGenres = "TvGenres";
|
||||||
|
public const string TvLatest = "TvLatest";
|
||||||
|
public const string TvNextUp = "TvNextUp";
|
||||||
|
public const string TvResume = "TvResume";
|
||||||
|
public const string TvFavorites = "TvFavorites";
|
||||||
|
|
||||||
|
public const string MovieLatest = "MovieLatest";
|
||||||
|
public const string MovieResume = "MovieResume";
|
||||||
|
public const string MovieMovies = "MovieMovies";
|
||||||
|
public const string MovieCollections = "MovieCollections";
|
||||||
|
public const string MovieFavorites = "MovieFavorites";
|
||||||
|
public const string MovieGenres = "MovieGenres";
|
||||||
|
|
||||||
|
public const string LatestGames = "LatestGames";
|
||||||
|
public const string RecentlyPlayedGames = "RecentlyPlayedGames";
|
||||||
|
public const string GameSystems = "GameSystems";
|
||||||
|
public const string GameGenres = "GameGenres";
|
||||||
|
public const string GameFavorites = "GameFavorites";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -372,7 +372,7 @@
|
||||||
xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\net45\" /y /d /r /i
|
xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\net45\" /y /d /r /i
|
||||||
)</PostBuildEvent>
|
)</PostBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
|
||||||
<Import Project="Fody.targets" />
|
<Import Project="Fody.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
|
|
@ -211,7 +211,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
<Target Name="BeforeBuild">
|
<Target Name="BeforeBuild">
|
||||||
|
|
|
@ -198,7 +198,7 @@ namespace MediaBrowser.Server.Implementations.Connect
|
||||||
|
|
||||||
private string GetConnectUrl(string handler)
|
private string GetConnectUrl(string handler)
|
||||||
{
|
{
|
||||||
return "http://mb3admin.com/admin/connect/" + handler;
|
return "http://mediabrowser.tv:8095/" + handler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,7 +196,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed.HasValue;
|
var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed > 0;
|
||||||
|
|
||||||
using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
|
using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
|
||||||
{
|
{
|
||||||
|
@ -308,7 +308,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
/// <param name="options">The options.</param>
|
/// <param name="options">The options.</param>
|
||||||
private void DrawIndicator(Graphics graphics, int imageWidth, int imageHeight, ImageProcessingOptions options)
|
private void DrawIndicator(Graphics graphics, int imageWidth, int imageHeight, ImageProcessingOptions options)
|
||||||
{
|
{
|
||||||
if (!options.AddPlayedIndicator && !options.UnplayedCount.HasValue && !options.PercentPlayed.HasValue)
|
if (!options.AddPlayedIndicator && !options.UnplayedCount.HasValue && options.PercentPlayed.Equals(0))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -328,11 +328,11 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
new UnplayedCountIndicator().DrawUnplayedCountIndicator(graphics, currentImageSize, options.UnplayedCount.Value);
|
new UnplayedCountIndicator().DrawUnplayedCountIndicator(graphics, currentImageSize, options.UnplayedCount.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.PercentPlayed.HasValue)
|
if (options.PercentPlayed >= 0)
|
||||||
{
|
{
|
||||||
var currentImageSize = new Size(imageWidth, imageHeight);
|
var currentImageSize = new Size(imageWidth, imageHeight);
|
||||||
|
|
||||||
new PercentPlayedDrawer().Process(graphics, currentImageSize, options.PercentPlayed.Value);
|
new PercentPlayedDrawer().Process(graphics, currentImageSize, options.PercentPlayed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -437,7 +437,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the cache file path based on a set of parameters
|
/// Gets the cache file path based on a set of parameters
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, ImageOutputFormat format, bool addPlayedIndicator, double? percentPlayed, int? unwatchedCount, string backgroundColor)
|
private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, ImageOutputFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, string backgroundColor)
|
||||||
{
|
{
|
||||||
var filename = originalPath;
|
var filename = originalPath;
|
||||||
|
|
||||||
|
@ -462,9 +462,9 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
hasIndicator = true;
|
hasIndicator = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (percentPlayed.HasValue)
|
if (percentPlayed > 0)
|
||||||
{
|
{
|
||||||
filename += "p=" + percentPlayed.Value;
|
filename += "p=" + percentPlayed;
|
||||||
hasIndicator = true;
|
hasIndicator = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -726,7 +726,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<QueryResult<ProgramInfoDto>> GetRecommendedPrograms(RecommendedProgramQuery query, CancellationToken cancellationToken)
|
public async Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
IEnumerable<LiveTvProgram> programs = _programs.Values;
|
IEnumerable<LiveTvProgram> programs = _programs.Values;
|
||||||
|
|
||||||
|
@ -771,7 +771,24 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
|
|
||||||
await RefreshIfNeeded(programList, cancellationToken).ConfigureAwait(false);
|
await RefreshIfNeeded(programList, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var returnArray = programList
|
var returnArray = programList.ToArray();
|
||||||
|
|
||||||
|
var result = new QueryResult<LiveTvProgram>
|
||||||
|
{
|
||||||
|
Items = returnArray,
|
||||||
|
TotalRecordCount = returnArray.Length
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<QueryResult<ProgramInfoDto>> GetRecommendedPrograms(RecommendedProgramQuery query, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var internalResult = await GetRecommendedProgramsInternal(query, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var user = _userManager.GetUserById(new Guid(query.UserId));
|
||||||
|
|
||||||
|
var returnArray = internalResult.Items
|
||||||
.Select(i =>
|
.Select(i =>
|
||||||
{
|
{
|
||||||
var channel = GetChannel(i);
|
var channel = GetChannel(i);
|
||||||
|
@ -785,7 +802,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
var result = new QueryResult<ProgramInfoDto>
|
var result = new QueryResult<ProgramInfoDto>
|
||||||
{
|
{
|
||||||
Items = returnArray,
|
Items = returnArray,
|
||||||
TotalRecordCount = returnArray.Length
|
TotalRecordCount = internalResult.TotalRecordCount
|
||||||
};
|
};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -841,6 +841,24 @@
|
||||||
"ViewTypeBoxSets": "Collections",
|
"ViewTypeBoxSets": "Collections",
|
||||||
"ViewTypeChannels": "Channels",
|
"ViewTypeChannels": "Channels",
|
||||||
"ViewTypeLiveTV": "Live TV",
|
"ViewTypeLiveTV": "Live TV",
|
||||||
|
"ViewTypeLiveTvNowPlaying": "Now Airing",
|
||||||
|
"ViewTypeLatestGames": "Latest Games",
|
||||||
|
"ViewTypeRecentlyPlayedGames": "Recently Played",
|
||||||
|
"ViewTypeGameFavorites": "Favorites",
|
||||||
|
"ViewTypeGameSystems": "Game Systems",
|
||||||
|
"ViewTypeGameGenres": "Genres",
|
||||||
|
"ViewTypeTvResume": "Resume",
|
||||||
|
"ViewTypeTvNextUp": "Next Up",
|
||||||
|
"ViewTypeTvLatest": "Latest",
|
||||||
|
"ViewTypeTvSeries": "Series",
|
||||||
|
"ViewTypeTvGenres": "Genres",
|
||||||
|
"ViewTypeTvFavorites": "Favorites",
|
||||||
|
"ViewTypeMovieResume": "Resume",
|
||||||
|
"ViewTypeMovieLatest": "Latest",
|
||||||
|
"ViewTypeMovieMovies": "Movies",
|
||||||
|
"ViewTypeMovieCollections": "Collections",
|
||||||
|
"ViewTypeMovieFavorites": "Favorites",
|
||||||
|
"ViewTypeMovieGenres": "Genres",
|
||||||
"HeaderOtherDisplaySettings": "Display Settings",
|
"HeaderOtherDisplaySettings": "Display Settings",
|
||||||
"HeaderMyViews": "My Views",
|
"HeaderMyViews": "My Views",
|
||||||
"LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:",
|
"LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:",
|
||||||
|
|
|
@ -293,6 +293,7 @@
|
||||||
<Compile Include="Sync\SyncManager.cs" />
|
<Compile Include="Sync\SyncManager.cs" />
|
||||||
<Compile Include="Sync\SyncRepository.cs" />
|
<Compile Include="Sync\SyncRepository.cs" />
|
||||||
<Compile Include="Themes\AppThemeManager.cs" />
|
<Compile Include="Themes\AppThemeManager.cs" />
|
||||||
|
<Compile Include="TV\TVSeriesManager.cs" />
|
||||||
<Compile Include="Udp\UdpMessageReceivedEventArgs.cs" />
|
<Compile Include="Udp\UdpMessageReceivedEventArgs.cs" />
|
||||||
<Compile Include="Udp\UdpServer.cs" />
|
<Compile Include="Udp\UdpServer.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -500,7 +501,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
<Target Name="BeforeBuild">
|
<Target Name="BeforeBuild">
|
||||||
|
@ -508,4 +509,4 @@
|
||||||
<Target Name="AfterBuild">
|
<Target Name="AfterBuild">
|
||||||
</Target>
|
</Target>
|
||||||
-->
|
-->
|
||||||
</Project>
|
</Project>
|
202
MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs
Normal file
202
MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.TV;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.TV
|
||||||
|
{
|
||||||
|
public class TVSeriesManager : ITVSeriesManager
|
||||||
|
{
|
||||||
|
private readonly IUserManager _userManager;
|
||||||
|
private readonly IUserDataManager _userDataManager;
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
|
public TVSeriesManager(IUserManager userManager, IUserDataManager userDataManager, ILibraryManager libraryManager)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_userDataManager = userDataManager;
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryResult<BaseItem> GetNextUp(NextUpQuery request)
|
||||||
|
{
|
||||||
|
var user = _userManager.GetUserById(new Guid(request.UserId));
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
var parentIds = string.IsNullOrEmpty(request.ParentId)
|
||||||
|
? new string[] { }
|
||||||
|
: new[] { request.ParentId };
|
||||||
|
|
||||||
|
var items = GetAllLibraryItems(user, parentIds)
|
||||||
|
.OfType<Series>();
|
||||||
|
|
||||||
|
// Avoid implicitly captured closure
|
||||||
|
var episodes = GetNextUpEpisodes(request, user, items);
|
||||||
|
|
||||||
|
return GetResult(episodes, null, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryResult<BaseItem> GetNextUp(NextUpQuery request, IEnumerable<Folder> parentsFolders)
|
||||||
|
{
|
||||||
|
var user = _userManager.GetUserById(new Guid(request.UserId));
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
var items = parentsFolders.SelectMany(i => i.GetRecursiveChildren(user))
|
||||||
|
.OfType<Series>();
|
||||||
|
|
||||||
|
// Avoid implicitly captured closure
|
||||||
|
var episodes = GetNextUpEpisodes(request, user, items);
|
||||||
|
|
||||||
|
return GetResult(episodes, null, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<BaseItem> GetAllLibraryItems(User user, string[] parentIds)
|
||||||
|
{
|
||||||
|
if (parentIds.Length > 0)
|
||||||
|
{
|
||||||
|
return parentIds.SelectMany(i =>
|
||||||
|
{
|
||||||
|
var folder = (Folder)_libraryManager.GetItemById(new Guid(i));
|
||||||
|
|
||||||
|
return folder.GetRecursiveChildren(user);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return user.RootFolder.GetRecursiveChildren(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Episode> GetNextUpEpisodes(NextUpQuery request, User user, IEnumerable<Series> series)
|
||||||
|
{
|
||||||
|
// Avoid implicitly captured closure
|
||||||
|
var currentUser = user;
|
||||||
|
|
||||||
|
return FilterSeries(request, series)
|
||||||
|
.AsParallel()
|
||||||
|
.Select(i => GetNextUp(i, currentUser))
|
||||||
|
.Where(i => i.Item1 != null)
|
||||||
|
.OrderByDescending(i =>
|
||||||
|
{
|
||||||
|
var episode = i.Item1;
|
||||||
|
|
||||||
|
var seriesUserData = _userDataManager.GetUserData(user.Id, episode.Series.GetUserDataKey());
|
||||||
|
|
||||||
|
if (seriesUserData.IsFavorite)
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seriesUserData.Likes.HasValue)
|
||||||
|
{
|
||||||
|
return seriesUserData.Likes.Value ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
})
|
||||||
|
.ThenByDescending(i => i.Item2)
|
||||||
|
.ThenByDescending(i => i.Item1.PremiereDate ?? DateTime.MinValue)
|
||||||
|
.Select(i => i.Item1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the next up.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="series">The series.</param>
|
||||||
|
/// <param name="user">The user.</param>
|
||||||
|
/// <returns>Task{Episode}.</returns>
|
||||||
|
private Tuple<Episode, DateTime> GetNextUp(Series series, User user)
|
||||||
|
{
|
||||||
|
// Get them in display order, then reverse
|
||||||
|
var allEpisodes = series.GetSeasons(user, true, true)
|
||||||
|
.SelectMany(i => i.GetEpisodes(user, true, true))
|
||||||
|
.Reverse()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
Episode lastWatched = null;
|
||||||
|
var lastWatchedDate = DateTime.MinValue;
|
||||||
|
Episode nextUp = null;
|
||||||
|
|
||||||
|
// Go back starting with the most recent episodes
|
||||||
|
foreach (var episode in allEpisodes)
|
||||||
|
{
|
||||||
|
var userData = _userDataManager.GetUserData(user.Id, episode.GetUserDataKey());
|
||||||
|
|
||||||
|
if (userData.Played)
|
||||||
|
{
|
||||||
|
if (lastWatched != null || nextUp == null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastWatched = episode;
|
||||||
|
lastWatchedDate = userData.LastPlayedDate ?? DateTime.MinValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (episode.LocationType != LocationType.Virtual)
|
||||||
|
{
|
||||||
|
nextUp = episode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastWatched != null)
|
||||||
|
{
|
||||||
|
return new Tuple<Episode, DateTime>(nextUp, lastWatchedDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tuple<Episode, DateTime>(null, lastWatchedDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<Series> FilterSeries(NextUpQuery request, IEnumerable<Series> items)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(request.SeriesId))
|
||||||
|
{
|
||||||
|
var id = new Guid(request.SeriesId);
|
||||||
|
|
||||||
|
items = items.Where(i => i.Id == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult<BaseItem> GetResult(IEnumerable<BaseItem> items, int? totalRecordLimit, NextUpQuery query)
|
||||||
|
{
|
||||||
|
var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
|
||||||
|
var totalCount = itemsArray.Length;
|
||||||
|
|
||||||
|
if (query.Limit.HasValue)
|
||||||
|
{
|
||||||
|
itemsArray = itemsArray.Skip(query.StartIndex ?? 0).Take(query.Limit.Value).ToArray();
|
||||||
|
}
|
||||||
|
else if (query.StartIndex.HasValue)
|
||||||
|
{
|
||||||
|
itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new QueryResult<BaseItem>
|
||||||
|
{
|
||||||
|
TotalRecordCount = totalCount,
|
||||||
|
Items = itemsArray
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ using MediaBrowser.Controller.Sorting;
|
||||||
using MediaBrowser.Controller.Subtitles;
|
using MediaBrowser.Controller.Subtitles;
|
||||||
using MediaBrowser.Controller.Sync;
|
using MediaBrowser.Controller.Sync;
|
||||||
using MediaBrowser.Controller.Themes;
|
using MediaBrowser.Controller.Themes;
|
||||||
|
using MediaBrowser.Controller.TV;
|
||||||
using MediaBrowser.Dlna;
|
using MediaBrowser.Dlna;
|
||||||
using MediaBrowser.Dlna.ConnectionManager;
|
using MediaBrowser.Dlna.ConnectionManager;
|
||||||
using MediaBrowser.Dlna.ContentDirectory;
|
using MediaBrowser.Dlna.ContentDirectory;
|
||||||
|
@ -79,6 +80,7 @@ using MediaBrowser.Server.Implementations.ServerManager;
|
||||||
using MediaBrowser.Server.Implementations.Session;
|
using MediaBrowser.Server.Implementations.Session;
|
||||||
using MediaBrowser.Server.Implementations.Sync;
|
using MediaBrowser.Server.Implementations.Sync;
|
||||||
using MediaBrowser.Server.Implementations.Themes;
|
using MediaBrowser.Server.Implementations.Themes;
|
||||||
|
using MediaBrowser.Server.Implementations.TV;
|
||||||
using MediaBrowser.ServerApplication.FFMpeg;
|
using MediaBrowser.ServerApplication.FFMpeg;
|
||||||
using MediaBrowser.ServerApplication.IO;
|
using MediaBrowser.ServerApplication.IO;
|
||||||
using MediaBrowser.ServerApplication.Native;
|
using MediaBrowser.ServerApplication.Native;
|
||||||
|
@ -213,10 +215,11 @@ namespace MediaBrowser.ServerApplication
|
||||||
private ISubtitleManager SubtitleManager { get; set; }
|
private ISubtitleManager SubtitleManager { get; set; }
|
||||||
private IChapterManager ChapterManager { get; set; }
|
private IChapterManager ChapterManager { get; set; }
|
||||||
|
|
||||||
private IUserViewManager UserViewManager { get; set; }
|
internal IUserViewManager UserViewManager { get; set; }
|
||||||
|
|
||||||
private IAuthenticationRepository AuthenticationRepository { get; set; }
|
private IAuthenticationRepository AuthenticationRepository { get; set; }
|
||||||
private ISyncRepository SyncRepository { get; set; }
|
private ISyncRepository SyncRepository { get; set; }
|
||||||
|
private ITVSeriesManager TVSeriesManager { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ApplicationHost" /> class.
|
/// Initializes a new instance of the <see cref="ApplicationHost" /> class.
|
||||||
|
@ -466,6 +469,9 @@ namespace MediaBrowser.ServerApplication
|
||||||
ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, Logger, ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager);
|
ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, Logger, ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager);
|
||||||
RegisterSingleInstance(ChannelManager);
|
RegisterSingleInstance(ChannelManager);
|
||||||
|
|
||||||
|
TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager);
|
||||||
|
RegisterSingleInstance(TVSeriesManager);
|
||||||
|
|
||||||
var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger);
|
var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger);
|
||||||
RegisterSingleInstance<IAppThemeManager>(appThemeManager);
|
RegisterSingleInstance<IAppThemeManager>(appThemeManager);
|
||||||
|
|
||||||
|
@ -487,7 +493,7 @@ namespace MediaBrowser.ServerApplication
|
||||||
UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, FileSystemManager, UserManager, ChannelManager, LiveTvManager, ApplicationPaths, playlistManager);
|
UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, FileSystemManager, UserManager, ChannelManager, LiveTvManager, ApplicationPaths, playlistManager);
|
||||||
RegisterSingleInstance(UserViewManager);
|
RegisterSingleInstance(UserViewManager);
|
||||||
|
|
||||||
var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, UserViewManager, ChannelManager);
|
var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient);
|
||||||
RegisterSingleInstance<IContentDirectory>(contentDirectory);
|
RegisterSingleInstance<IContentDirectory>(contentDirectory);
|
||||||
|
|
||||||
NotificationManager = new NotificationManager(LogManager, UserManager, ServerConfigurationManager);
|
NotificationManager = new NotificationManager(LogManager, UserManager, ServerConfigurationManager);
|
||||||
|
@ -682,9 +688,10 @@ namespace MediaBrowser.ServerApplication
|
||||||
Folder.UserManager = UserManager;
|
Folder.UserManager = UserManager;
|
||||||
BaseItem.FileSystem = FileSystemManager;
|
BaseItem.FileSystem = FileSystemManager;
|
||||||
BaseItem.UserDataManager = UserDataManager;
|
BaseItem.UserDataManager = UserDataManager;
|
||||||
ChannelVideoItem.ChannelManager = ChannelManager;
|
BaseItem.ChannelManager = ChannelManager;
|
||||||
BaseItem.LiveTvManager = LiveTvManager;
|
BaseItem.LiveTvManager = LiveTvManager;
|
||||||
UserView.UserViewManager = UserViewManager;
|
Folder.UserViewManager = UserViewManager;
|
||||||
|
UserView.TVSeriesManager = TVSeriesManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
using MediaBrowser.Controller.Entities;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Persistence;
|
||||||
|
using MediaBrowser.Model.Library;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using System;
|
using System;
|
||||||
|
@ -16,17 +19,17 @@ namespace MediaBrowser.ServerApplication
|
||||||
{
|
{
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly IItemRepository _itemRepository;
|
private readonly IUserViewManager _userViewManager;
|
||||||
|
|
||||||
private User _currentUser;
|
private User _currentUser;
|
||||||
|
|
||||||
public LibraryViewer(IJsonSerializer jsonSerializer, IUserManager userManager, ILibraryManager libraryManager, IItemRepository itemRepo)
|
public LibraryViewer(IJsonSerializer jsonSerializer, IUserManager userManager, ILibraryManager libraryManager, IUserViewManager userViewManager)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_jsonSerializer = jsonSerializer;
|
_jsonSerializer = jsonSerializer;
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_itemRepository = itemRepo;
|
_userViewManager = userViewManager;
|
||||||
|
|
||||||
foreach (var user in userManager.Users)
|
foreach (var user in userManager.Users)
|
||||||
selectUser.Items.Add(user);
|
selectUser.Items.Add(user);
|
||||||
|
@ -72,23 +75,50 @@ namespace MediaBrowser.ServerApplication
|
||||||
LoadTree();
|
LoadTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IEnumerable<BaseItem> GetItems(Folder parent, User user)
|
||||||
|
{
|
||||||
|
if (parent == null)
|
||||||
|
{
|
||||||
|
var task = _userViewManager.GetUserViews(new UserViewQuery
|
||||||
|
{
|
||||||
|
UserId = user.Id.ToString("N")
|
||||||
|
|
||||||
|
}, CancellationToken.None);
|
||||||
|
|
||||||
|
task.RunSynchronously();
|
||||||
|
|
||||||
|
return task.Result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var task = parent.GetUserItems(new UserItemsQuery
|
||||||
|
{
|
||||||
|
User = user,
|
||||||
|
SortBy = new[] { ItemSortBy.SortName }
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
task.RunSynchronously();
|
||||||
|
|
||||||
|
return task.Result.Items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void LoadTree()
|
private void LoadTree()
|
||||||
{
|
{
|
||||||
treeView1.Nodes.Clear();
|
treeView1.Nodes.Clear();
|
||||||
|
|
||||||
var isPhysical = _currentUser.Name == "Physical";
|
var isPhysical = _currentUser.Name == "Physical";
|
||||||
IEnumerable<BaseItem> children = isPhysical ? new[] { _libraryManager.RootFolder } : _libraryManager.RootFolder.GetChildren(_currentUser, true);
|
IEnumerable<BaseItem> children = isPhysical ? new[] { _libraryManager.RootFolder } : GetItems(null, _currentUser);
|
||||||
children = OrderByName(children, _currentUser);
|
|
||||||
|
|
||||||
foreach (Folder folder in children)
|
foreach (var folder in children.OfType<Folder>())
|
||||||
{
|
{
|
||||||
|
|
||||||
var currentFolder = folder;
|
var currentFolder = folder;
|
||||||
|
|
||||||
var node = new TreeNode { Tag = currentFolder };
|
var node = new TreeNode { Tag = currentFolder };
|
||||||
|
|
||||||
var subChildren = isPhysical ? currentFolder.Children : currentFolder.GetChildren(_currentUser, true);
|
var subChildren = isPhysical ? currentFolder.Children.OrderBy(i => i.SortName) : GetItems(currentFolder, _currentUser);
|
||||||
subChildren = OrderByName(subChildren, _currentUser);
|
|
||||||
AddChildren(node, subChildren, _currentUser, isPhysical);
|
AddChildren(node, subChildren, _currentUser, isPhysical);
|
||||||
node.Text = currentFolder.Name + " (" +
|
node.Text = currentFolder.Name + " (" +
|
||||||
node.Nodes.Count + ")";
|
node.Nodes.Count + ")";
|
||||||
|
@ -111,9 +141,9 @@ namespace MediaBrowser.ServerApplication
|
||||||
var subFolder = item as Folder;
|
var subFolder = item as Folder;
|
||||||
if (subFolder != null)
|
if (subFolder != null)
|
||||||
{
|
{
|
||||||
var subChildren = isPhysical ? subFolder.Children : subFolder.GetChildren(_currentUser, true);
|
var subChildren = isPhysical ? subFolder.Children.OrderBy(i => i.SortName) : GetItems(subFolder, _currentUser);
|
||||||
|
|
||||||
AddChildren(node, OrderBy(subChildren, user, ItemSortBy.SortName), user, isPhysical);
|
AddChildren(node, subChildren, user, isPhysical);
|
||||||
node.Text = item.Name + " (" + node.Nodes.Count + ")";
|
node.Text = item.Name + " (" + node.Nodes.Count + ")";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -124,28 +154,6 @@ namespace MediaBrowser.ServerApplication
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Orders the name of the by.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="items">The items.</param>
|
|
||||||
/// <param name="user">The user.</param>
|
|
||||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
|
||||||
private IEnumerable<BaseItem> OrderByName(IEnumerable<BaseItem> items, User user)
|
|
||||||
{
|
|
||||||
return OrderBy(items, user, ItemSortBy.SortName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Orders the name of the by.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="items">The items.</param>
|
|
||||||
/// <param name="user">The user.</param>
|
|
||||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
|
||||||
private IEnumerable<BaseItem> OrderBy(IEnumerable<BaseItem> items, User user, string order)
|
|
||||||
{
|
|
||||||
return _libraryManager.Sort(items, user, new[] { order }, SortOrder.Ascending);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The INDEN t_ STRING
|
/// The INDEN t_ STRING
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -249,7 +249,7 @@ namespace MediaBrowser.ServerApplication
|
||||||
{
|
{
|
||||||
//Application.EnableVisualStyles();
|
//Application.EnableVisualStyles();
|
||||||
//Application.SetCompatibleTextRenderingDefault(false);
|
//Application.SetCompatibleTextRenderingDefault(false);
|
||||||
_serverNotifyIcon = new ServerNotifyIcon(_appHost.LogManager, _appHost, _appHost.ServerConfigurationManager, _appHost.UserManager, _appHost.LibraryManager, _appHost.JsonSerializer, _appHost.ItemRepository, _appHost.LocalizationManager);
|
_serverNotifyIcon = new ServerNotifyIcon(_appHost.LogManager, _appHost, _appHost.ServerConfigurationManager, _appHost.UserManager, _appHost.LibraryManager, _appHost.JsonSerializer, _appHost.LocalizationManager, _appHost.UserViewManager);
|
||||||
Application.Run();
|
Application.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace MediaBrowser.ServerApplication
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
private readonly IItemRepository _itemRepository;
|
private readonly IUserViewManager _userViewManager;
|
||||||
private readonly ILocalizationManager _localization;
|
private readonly ILocalizationManager _localization;
|
||||||
private LogForm _logForm;
|
private LogForm _logForm;
|
||||||
|
|
||||||
|
@ -61,11 +61,11 @@ namespace MediaBrowser.ServerApplication
|
||||||
IServerConfigurationManager configurationManager,
|
IServerConfigurationManager configurationManager,
|
||||||
IUserManager userManager, ILibraryManager libraryManager,
|
IUserManager userManager, ILibraryManager libraryManager,
|
||||||
IJsonSerializer jsonSerializer,
|
IJsonSerializer jsonSerializer,
|
||||||
IItemRepository itemRepo, ILocalizationManager localization)
|
ILocalizationManager localization, IUserViewManager userViewManager)
|
||||||
{
|
{
|
||||||
_logger = logManager.GetLogger("MainWindow");
|
_logger = logManager.GetLogger("MainWindow");
|
||||||
_itemRepository = itemRepo;
|
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
|
_userViewManager = userViewManager;
|
||||||
_appHost = appHost;
|
_appHost = appHost;
|
||||||
_logManager = logManager;
|
_logManager = logManager;
|
||||||
_configurationManager = configurationManager;
|
_configurationManager = configurationManager;
|
||||||
|
@ -318,7 +318,7 @@ namespace MediaBrowser.ServerApplication
|
||||||
|
|
||||||
void cmdLibraryExplorer_Click(object sender, EventArgs e)
|
void cmdLibraryExplorer_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
new LibraryViewer(_jsonSerializer, _userManager, _libraryManager, _itemRepository).Show();
|
new LibraryViewer(_jsonSerializer, _userManager, _libraryManager, _userViewManager).Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmdRestart_Click(object sender, EventArgs e)
|
void cmdRestart_Click(object sender, EventArgs e)
|
||||||
|
|
|
@ -2136,7 +2136,7 @@
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
</PostBuildEvent>
|
</PostBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
<Target Name="BeforeBuild">
|
<Target Name="BeforeBuild">
|
||||||
|
|
Loading…
Reference in New Issue
Block a user