mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-06 11:34:57 +02:00
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
This commit is contained in:
commit
6819be8160
199 changed files with 5525 additions and 2201 deletions
|
@ -92,7 +92,7 @@ namespace MediaBrowser.Api
|
|||
private readonly char[] _dashReplaceChars = new[] { '?', '/' };
|
||||
private const char SlugChar = '-';
|
||||
|
||||
protected Artist GetArtist(string name, ILibraryManager libraryManager)
|
||||
protected MusicArtist GetArtist(string name, ILibraryManager libraryManager)
|
||||
{
|
||||
return libraryManager.GetArtist(DeSlugArtistName(name, libraryManager));
|
||||
}
|
||||
|
@ -147,21 +147,7 @@ namespace MediaBrowser.Api
|
|||
return name;
|
||||
}
|
||||
|
||||
return libraryManager.RootFolder.GetRecursiveChildren()
|
||||
.OfType<Audio>()
|
||||
.SelectMany(i =>
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(i.AlbumArtist))
|
||||
{
|
||||
list.Add(i.AlbumArtist);
|
||||
}
|
||||
list.AddRange(i.Artists);
|
||||
|
||||
return list;
|
||||
})
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
return libraryManager.GetAllArtists()
|
||||
.FirstOrDefault(i =>
|
||||
{
|
||||
i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
|
||||
|
|
|
@ -194,20 +194,7 @@ namespace MediaBrowser.Api.DefaultTheme
|
|||
.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
|
||||
.ToList();
|
||||
|
||||
var artists = allItems.OfType<Audio>()
|
||||
.SelectMany(i =>
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(i.AlbumArtist))
|
||||
{
|
||||
list.Add(i.AlbumArtist);
|
||||
}
|
||||
list.AddRange(i.Artists);
|
||||
|
||||
return list;
|
||||
})
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
var artists = _libraryManager.GetAllArtists(allItems)
|
||||
.Randomize()
|
||||
.Select(i =>
|
||||
{
|
||||
|
@ -650,7 +637,7 @@ namespace MediaBrowser.Api.DefaultTheme
|
|||
public static IEnumerable<T> Randomize<T>(this IEnumerable<T> sequence, string type = "none")
|
||||
where T : BaseItem
|
||||
{
|
||||
var hour = DateTime.Now.Hour + 2;
|
||||
var hour = DateTime.Now.Hour + DateTime.Now.Day + 2;
|
||||
|
||||
var typeCode = type.GetHashCode();
|
||||
|
||||
|
|
52
MediaBrowser.Api/IHasItemFields.cs
Normal file
52
MediaBrowser.Api/IHasItemFields.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
using MediaBrowser.Model.Querying;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Api
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface IHasItemFields
|
||||
/// </summary>
|
||||
public interface IHasItemFields
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the fields.
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
string Fields { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class ItemFieldsExtensions.
|
||||
/// </summary>
|
||||
public static class ItemFieldsExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the item fields.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>IEnumerable{ItemFields}.</returns>
|
||||
public static IEnumerable<ItemFields> GetItemFields(this IHasItemFields request)
|
||||
{
|
||||
var val = request.Fields;
|
||||
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
return new ItemFields[] { };
|
||||
}
|
||||
|
||||
return val.Split(',').Select(v =>
|
||||
{
|
||||
ItemFields value;
|
||||
|
||||
if (Enum.TryParse(v, true, out value))
|
||||
{
|
||||
return (ItemFields?)value;
|
||||
}
|
||||
return null;
|
||||
|
||||
}).Where(i => i.HasValue).Select(i => i.Value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ using MediaBrowser.Controller.Drawing;
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Drawing;
|
||||
|
@ -37,6 +38,18 @@ namespace MediaBrowser.Api.Images
|
|||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Channels/{Id}/Images", "GET")]
|
||||
[Api(Description = "Gets information about an item's images")]
|
||||
public class GetChannelImageInfos : IReturn<List<ImageInfo>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Artists/{Name}/Images", "GET")]
|
||||
[Route("/Genres/{Name}/Images", "GET")]
|
||||
[Route("/GameGenres/{Name}/Images", "GET")]
|
||||
|
@ -67,6 +80,19 @@ namespace MediaBrowser.Api.Images
|
|||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}", "GET")]
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}/{Index}", "GET")]
|
||||
[Api(Description = "Gets an item image")]
|
||||
public class GetChannelImage : ImageRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Channel Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class UpdateItemImageIndex
|
||||
/// </summary>
|
||||
|
@ -243,6 +269,19 @@ namespace MediaBrowser.Api.Images
|
|||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}", "DELETE")]
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}/{Index}", "DELETE")]
|
||||
[Api(Description = "Deletes an item image")]
|
||||
public class DeleteChannelImage : DeleteImageRequest, IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Channel Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class PostUserImage
|
||||
/// </summary>
|
||||
|
@ -318,6 +357,25 @@ namespace MediaBrowser.Api.Images
|
|||
public Stream RequestStream { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}", "POST")]
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}/{Index}", "POST")]
|
||||
[Api(Description = "Posts an item image")]
|
||||
public class PostChannelImage : DeleteImageRequest, IRequiresRequestStream, IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The raw Http Request Input Stream
|
||||
/// </summary>
|
||||
/// <value>The request stream.</value>
|
||||
public Stream RequestStream { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class ImageService
|
||||
/// </summary>
|
||||
|
@ -341,10 +399,12 @@ namespace MediaBrowser.Api.Images
|
|||
private readonly IDtoService _dtoService;
|
||||
private readonly IImageProcessor _imageProcessor;
|
||||
|
||||
private readonly ILiveTvManager _liveTv;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ImageService" /> class.
|
||||
/// </summary>
|
||||
public ImageService(IUserManager userManager, ILibraryManager libraryManager, IApplicationPaths appPaths, IProviderManager providerManager, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor)
|
||||
public ImageService(IUserManager userManager, ILibraryManager libraryManager, IApplicationPaths appPaths, IProviderManager providerManager, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor, ILiveTvManager liveTv)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_libraryManager = libraryManager;
|
||||
|
@ -353,6 +413,7 @@ namespace MediaBrowser.Api.Images
|
|||
_itemRepo = itemRepo;
|
||||
_dtoService = dtoService;
|
||||
_imageProcessor = imageProcessor;
|
||||
_liveTv = liveTv;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -369,6 +430,15 @@ namespace MediaBrowser.Api.Images
|
|||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public object Get(GetChannelImageInfos request)
|
||||
{
|
||||
var item = _liveTv.GetChannel(request.Id);
|
||||
|
||||
var result = GetItemImageInfos(item);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public object Get(GetItemByNameImageInfos request)
|
||||
{
|
||||
var result = GetItemByNameImageInfos(request);
|
||||
|
@ -484,7 +554,7 @@ namespace MediaBrowser.Api.Images
|
|||
Height = Convert.ToInt32(size.Height)
|
||||
};
|
||||
}
|
||||
catch (IOException ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error getting image information for {0}", ex, path);
|
||||
|
||||
|
@ -492,6 +562,13 @@ namespace MediaBrowser.Api.Images
|
|||
}
|
||||
}
|
||||
|
||||
public object Get(GetChannelImage request)
|
||||
{
|
||||
var item = _liveTv.GetChannel(request.Id);
|
||||
|
||||
return GetImage(request, item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
|
@ -577,6 +654,20 @@ namespace MediaBrowser.Api.Images
|
|||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
public void Post(PostChannelImage request)
|
||||
{
|
||||
var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
|
||||
var id = pathInfo.GetArgumentValue<string>(2);
|
||||
|
||||
request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue<string>(4), true);
|
||||
|
||||
var item = _liveTv.GetChannel(id);
|
||||
|
||||
var task = PostImage(item, request.RequestStream, request.Type, RequestContext.ContentType);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the specified request.
|
||||
/// </summary>
|
||||
|
@ -603,6 +694,15 @@ namespace MediaBrowser.Api.Images
|
|||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
public void Delete(DeleteChannelImage request)
|
||||
{
|
||||
var item = _liveTv.GetChannel(request.Id);
|
||||
|
||||
var task = item.DeleteImage(request.Type, request.Index);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the specified request.
|
||||
/// </summary>
|
||||
|
|
|
@ -264,16 +264,14 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
var item = _dtoService.GetItemByDtoId(request.Id);
|
||||
|
||||
var folder = item as Folder;
|
||||
|
||||
try
|
||||
{
|
||||
await item.RefreshMetadata(CancellationToken.None, forceRefresh: request.Forced).ConfigureAwait(false);
|
||||
|
||||
if (folder != null)
|
||||
if (item.IsFolder)
|
||||
{
|
||||
// Collection folders don't validate their children so we'll have to simulate that here
|
||||
var collectionFolder = folder as CollectionFolder;
|
||||
var collectionFolder = item as CollectionFolder;
|
||||
|
||||
if (collectionFolder != null)
|
||||
{
|
||||
|
@ -281,6 +279,8 @@ namespace MediaBrowser.Api
|
|||
}
|
||||
else
|
||||
{
|
||||
var folder = (Folder)item;
|
||||
|
||||
await folder.ValidateChildren(new Progress<double>(), CancellationToken.None, request.Recursive, request.Forced).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
@ -303,10 +303,10 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
await child.RefreshMetadata(CancellationToken.None, forceRefresh: request.Forced).ConfigureAwait(false);
|
||||
|
||||
var folder = child as Folder;
|
||||
|
||||
if (folder != null)
|
||||
if (child.IsFolder)
|
||||
{
|
||||
var folder = (Folder)child;
|
||||
|
||||
await folder.ValidateChildren(new Progress<double>(), CancellationToken.None, request.Recursive, request.Forced).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities;
|
|||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using ServiceStack.ServiceHost;
|
||||
|
@ -13,6 +14,14 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Api
|
||||
{
|
||||
[Route("/LiveTv/Channels/{ChannelId}", "POST")]
|
||||
[Api(("Updates an item"))]
|
||||
public class UpdateChannel : BaseItemDto, IReturnVoid
|
||||
{
|
||||
[ApiMember(Name = "ChannelId", Description = "The id of the channel", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string ChannelId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Items/{ItemId}", "POST")]
|
||||
[Api(("Updates an item"))]
|
||||
public class UpdateItem : BaseItemDto, IReturnVoid
|
||||
|
@ -73,11 +82,13 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly ILiveTvManager _liveTv;
|
||||
|
||||
public ItemUpdateService(ILibraryManager libraryManager, IDtoService dtoService)
|
||||
public ItemUpdateService(ILibraryManager libraryManager, IDtoService dtoService, ILiveTvManager liveTv)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_dtoService = dtoService;
|
||||
_liveTv = liveTv;
|
||||
}
|
||||
|
||||
public void Post(UpdateItem request)
|
||||
|
@ -87,13 +98,34 @@ namespace MediaBrowser.Api
|
|||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
private Task UpdateItem(UpdateItem request)
|
||||
public void Post(UpdateChannel request)
|
||||
{
|
||||
var task = UpdateItem(request);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
private async Task UpdateItem(UpdateItem request)
|
||||
{
|
||||
var item = _dtoService.GetItemByDtoId(request.ItemId);
|
||||
|
||||
var newEnableInternetProviders = request.EnableInternetProviders ?? true;
|
||||
var dontFetchMetaChanged = item.DontFetchMeta != !newEnableInternetProviders;
|
||||
|
||||
UpdateItem(request, item);
|
||||
|
||||
return _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None);
|
||||
await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
if (dontFetchMetaChanged && item.IsFolder)
|
||||
{
|
||||
var folder = (Folder)item;
|
||||
|
||||
foreach (var child in folder.RecursiveChildren.ToList())
|
||||
{
|
||||
child.DontFetchMeta = !newEnableInternetProviders;
|
||||
await _libraryManager.UpdateItem(child, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Post(UpdatePerson request)
|
||||
|
@ -112,6 +144,15 @@ namespace MediaBrowser.Api
|
|||
await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task UpdateItem(UpdateChannel request)
|
||||
{
|
||||
var item = _liveTv.GetChannel(request.Id);
|
||||
|
||||
UpdateItem(request, item);
|
||||
|
||||
await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public void Post(UpdateArtist request)
|
||||
{
|
||||
var task = UpdateItem(request);
|
||||
|
@ -126,15 +167,6 @@ namespace MediaBrowser.Api
|
|||
UpdateItem(request, item);
|
||||
|
||||
await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
var musicArtist = Artist.FindMusicArtist(item, _libraryManager);
|
||||
|
||||
if (musicArtist != null)
|
||||
{
|
||||
UpdateItem(request, musicArtist);
|
||||
|
||||
await _libraryManager.UpdateItem(musicArtist, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void Post(UpdateStudio request)
|
||||
|
@ -216,8 +248,12 @@ namespace MediaBrowser.Api
|
|||
item.ForcedSortName = request.SortName;
|
||||
}
|
||||
|
||||
item.Budget = request.Budget;
|
||||
item.Revenue = request.Revenue;
|
||||
var hasBudget = item as IHasBudget;
|
||||
if (hasBudget != null)
|
||||
{
|
||||
hasBudget.Budget = request.Budget;
|
||||
hasBudget.Revenue = request.Revenue;
|
||||
}
|
||||
|
||||
var hasCriticRating = item as IHasCriticRating;
|
||||
if (hasCriticRating != null)
|
||||
|
@ -235,8 +271,16 @@ namespace MediaBrowser.Api
|
|||
item.Overview = request.Overview;
|
||||
item.Genres = request.Genres;
|
||||
item.Tags = request.Tags;
|
||||
item.Studios = request.Studios.Select(x => x.Name).ToList();
|
||||
item.People = request.People.Select(x => new PersonInfo { Name = x.Name, Role = x.Role, Type = x.Type }).ToList();
|
||||
|
||||
if (request.Studios != null)
|
||||
{
|
||||
item.Studios = request.Studios.Select(x => x.Name).ToList();
|
||||
}
|
||||
|
||||
if (request.People != null)
|
||||
{
|
||||
item.People = request.People.Select(x => new PersonInfo { Name = x.Name, Role = x.Role, Type = x.Type }).ToList();
|
||||
}
|
||||
|
||||
if (request.DateCreated.HasValue)
|
||||
{
|
||||
|
@ -247,11 +291,16 @@ namespace MediaBrowser.Api
|
|||
item.PremiereDate = request.PremiereDate.HasValue ? request.PremiereDate.Value.ToUniversalTime() : (DateTime?)null;
|
||||
item.ProductionYear = request.ProductionYear;
|
||||
item.ProductionLocations = request.ProductionLocations;
|
||||
item.AspectRatio = request.AspectRatio;
|
||||
item.Language = request.Language;
|
||||
item.OfficialRating = request.OfficialRating;
|
||||
item.CustomRating = request.CustomRating;
|
||||
|
||||
var hasAspectRatio = item as IHasAspectRatio;
|
||||
if (hasAspectRatio != null)
|
||||
{
|
||||
hasAspectRatio.AspectRatio = request.AspectRatio;
|
||||
}
|
||||
|
||||
item.DontFetchMeta = !(request.EnableInternetProviders ?? true);
|
||||
if (request.EnableInternetProviders ?? true)
|
||||
{
|
||||
|
|
|
@ -286,7 +286,12 @@ namespace MediaBrowser.Api.Library
|
|||
}
|
||||
finally
|
||||
{
|
||||
_directoryWatchers.Start();
|
||||
// No need to start if scanning the library because it will handle it
|
||||
if (!request.RefreshLibrary)
|
||||
{
|
||||
_directoryWatchers.Start();
|
||||
}
|
||||
|
||||
_directoryWatchers.RemoveTempIgnore(virtualFolderPath);
|
||||
}
|
||||
|
||||
|
@ -353,7 +358,12 @@ namespace MediaBrowser.Api.Library
|
|||
}
|
||||
finally
|
||||
{
|
||||
_directoryWatchers.Start();
|
||||
// No need to start if scanning the library because it will handle it
|
||||
if (!request.RefreshLibrary)
|
||||
{
|
||||
_directoryWatchers.Start();
|
||||
}
|
||||
|
||||
_directoryWatchers.RemoveTempIgnore(currentPath);
|
||||
_directoryWatchers.RemoveTempIgnore(newPath);
|
||||
}
|
||||
|
@ -404,7 +414,12 @@ namespace MediaBrowser.Api.Library
|
|||
}
|
||||
finally
|
||||
{
|
||||
_directoryWatchers.Start();
|
||||
// No need to start if scanning the library because it will handle it
|
||||
if (!request.RefreshLibrary)
|
||||
{
|
||||
_directoryWatchers.Start();
|
||||
}
|
||||
|
||||
_directoryWatchers.RemoveTempIgnore(path);
|
||||
}
|
||||
|
||||
|
@ -442,7 +457,11 @@ namespace MediaBrowser.Api.Library
|
|||
}
|
||||
finally
|
||||
{
|
||||
_directoryWatchers.Start();
|
||||
// No need to start if scanning the library because it will handle it
|
||||
if (!request.RefreshLibrary)
|
||||
{
|
||||
_directoryWatchers.Start();
|
||||
}
|
||||
}
|
||||
|
||||
if (request.RefreshLibrary)
|
||||
|
@ -479,7 +498,11 @@ namespace MediaBrowser.Api.Library
|
|||
}
|
||||
finally
|
||||
{
|
||||
_directoryWatchers.Start();
|
||||
// No need to start if scanning the library because it will handle it
|
||||
if (!request.RefreshLibrary)
|
||||
{
|
||||
_directoryWatchers.Start();
|
||||
}
|
||||
}
|
||||
|
||||
if (request.RefreshLibrary)
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace MediaBrowser.Api
|
|||
/// </summary>
|
||||
[Route("/Items/{Id}/CriticReviews", "GET")]
|
||||
[Api(Description = "Gets critic reviews for an item")]
|
||||
public class GetCriticReviews : IReturn<ItemReviewsResult>
|
||||
public class GetCriticReviews : IReturn<QueryResult<ItemReview>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
|
@ -367,7 +367,7 @@ namespace MediaBrowser.Api
|
|||
BoxSetCount = boxsets.Count,
|
||||
BookCount = books.Count,
|
||||
|
||||
UniqueTypes = items.Select(i => i.GetType().Name).Distinct().ToList()
|
||||
UniqueTypes = items.Select(i => i.GetClientTypeName()).Distinct().ToList()
|
||||
};
|
||||
|
||||
var people = items.SelectMany(i => i.People)
|
||||
|
@ -390,19 +390,7 @@ namespace MediaBrowser.Api
|
|||
people = request.UserId.HasValue ? FilterItems(people, request, request.UserId.Value).ToList() : people;
|
||||
counts.PersonCount = people.Count;
|
||||
|
||||
var artists = items.OfType<Audio>().SelectMany(i =>
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(i.AlbumArtist))
|
||||
{
|
||||
list.Add(i.AlbumArtist);
|
||||
}
|
||||
list.AddRange(i.Artists);
|
||||
|
||||
return list;
|
||||
})
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
var artists = _libraryManager.GetAllArtists(items)
|
||||
.Select(i =>
|
||||
{
|
||||
try
|
||||
|
@ -477,13 +465,16 @@ namespace MediaBrowser.Api
|
|||
|
||||
if (item.LocationType == LocationType.FileSystem)
|
||||
{
|
||||
if (Directory.Exists(item.Path))
|
||||
foreach (var path in item.GetDeletePaths().ToList())
|
||||
{
|
||||
Directory.Delete(item.Path, true);
|
||||
}
|
||||
else if (File.Exists(item.Path))
|
||||
{
|
||||
File.Delete(item.Path);
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
Directory.Delete(path, true);
|
||||
}
|
||||
else if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
if (parent != null)
|
||||
|
@ -521,16 +512,16 @@ namespace MediaBrowser.Api
|
|||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>Task{ItemReviewsResult}.</returns>
|
||||
private ItemReviewsResult GetCriticReviews(GetCriticReviews request)
|
||||
private QueryResult<ItemReview> GetCriticReviews(GetCriticReviews request)
|
||||
{
|
||||
var reviews = _itemRepo.GetCriticReviews(new Guid(request.Id));
|
||||
|
||||
var reviewsArray = reviews.ToArray();
|
||||
|
||||
var result = new ItemReviewsResult
|
||||
{
|
||||
TotalRecordCount = reviewsArray.Length
|
||||
};
|
||||
var result = new QueryResult<ItemReview>
|
||||
{
|
||||
TotalRecordCount = reviewsArray.Length
|
||||
};
|
||||
|
||||
if (request.StartIndex.HasValue)
|
||||
{
|
||||
|
@ -541,7 +532,7 @@ namespace MediaBrowser.Api
|
|||
reviewsArray = reviewsArray.Take(request.Limit.Value).ToArray();
|
||||
}
|
||||
|
||||
result.ItemReviews = reviewsArray;
|
||||
result.Items = reviewsArray;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -681,6 +672,11 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
var album = originalItem as MusicAlbum;
|
||||
|
||||
if (album == null)
|
||||
{
|
||||
album = originalItem.Parents.OfType<MusicAlbum>().FirstOrDefault();
|
||||
}
|
||||
|
||||
if (album != null)
|
||||
{
|
||||
var linkedItemWithThemes = album.SoundtrackIds
|
||||
|
@ -744,17 +740,12 @@ namespace MediaBrowser.Api
|
|||
: (Folder)_libraryManager.RootFolder)
|
||||
: _dtoService.GetItemByDtoId(id, userId);
|
||||
|
||||
while (GetSoundtrackSongIds(item).Count == 0 && inheritFromParent && item.Parent != null)
|
||||
{
|
||||
item = item.Parent;
|
||||
}
|
||||
|
||||
// Get everything
|
||||
var fields = Enum.GetNames(typeof(ItemFields))
|
||||
.Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
|
||||
.ToList();
|
||||
|
||||
var dtos = GetSoundtrackSongIds(item)
|
||||
var dtos = GetSoundtrackSongIds(item, inheritFromParent)
|
||||
.Select(_libraryManager.GetItemById)
|
||||
.OfType<MusicAlbum>()
|
||||
.SelectMany(i => i.RecursiveChildren)
|
||||
|
@ -772,7 +763,7 @@ namespace MediaBrowser.Api
|
|||
};
|
||||
}
|
||||
|
||||
private List<Guid> GetSoundtrackSongIds(BaseItem item)
|
||||
private IEnumerable<Guid> GetSoundtrackSongIds(BaseItem item, bool inherit)
|
||||
{
|
||||
var hasSoundtracks = item as IHasSoundtracks;
|
||||
|
||||
|
@ -781,7 +772,14 @@ namespace MediaBrowser.Api
|
|||
return hasSoundtracks.SoundtrackIds;
|
||||
}
|
||||
|
||||
return new List<Guid>();
|
||||
if (!inherit)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
hasSoundtracks = item.Parents.OfType<IHasSoundtracks>().FirstOrDefault();
|
||||
|
||||
return hasSoundtracks != null ? hasSoundtracks.SoundtrackIds : new List<Guid>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using ServiceStack.ServiceHost;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
@ -18,31 +20,101 @@ namespace MediaBrowser.Api.LiveTv
|
|||
|
||||
[Route("/LiveTv/Channels", "GET")]
|
||||
[Api(Description = "Gets available live tv channels.")]
|
||||
public class GetChannels : IReturn<List<ChannelInfoDto>>
|
||||
public class GetChannels : IReturn<QueryResult<ChannelInfoDto>>
|
||||
{
|
||||
[ApiMember(Name = "ServiceName", Description = "Optional filter by service.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
[ApiMember(Name = "Type", Description = "Optional filter by channel type.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public ChannelType? Type { get; set; }
|
||||
|
||||
[ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Channels/{Id}", "GET")]
|
||||
[Api(Description = "Gets a live tv channel")]
|
||||
public class GetChannel : IReturn<ChannelInfoDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Channel Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "UserId", Description = "Optional user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Recordings", "GET")]
|
||||
[Api(Description = "Gets available live tv recordings.")]
|
||||
public class GetRecordings : IReturn<List<RecordingInfo>>
|
||||
[Api(Description = "Gets live tv recordings")]
|
||||
public class GetRecordings : IReturn<QueryResult<RecordingInfoDto>>
|
||||
{
|
||||
[ApiMember(Name = "ServiceName", Description = "Optional filter by service.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
[ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ChannelId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Guide", "GET")]
|
||||
[Api(Description = "Gets available live tv epgs..")]
|
||||
public class GetGuide : IReturn<List<ChannelGuide>>
|
||||
[Route("/LiveTv/Recordings/{Id}", "GET")]
|
||||
[Api(Description = "Gets a live tv recording")]
|
||||
public class GetRecording : IReturn<RecordingInfoDto>
|
||||
{
|
||||
[ApiMember(Name = "ServiceName", Description = "Live tv service name", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
[ApiMember(Name = "Id", Description = "Recording Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Timers/{Id}", "GET")]
|
||||
[Api(Description = "Gets a live tv timer")]
|
||||
public class GetTimer : IReturn<TimerInfoDto>
|
||||
{
|
||||
[ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Timers", "GET")]
|
||||
[Api(Description = "Gets live tv timers")]
|
||||
public class GetTimers : IReturn<QueryResult<TimerInfoDto>>
|
||||
{
|
||||
[ApiMember(Name = "ServiceName", Description = "Optional filter by service.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
[ApiMember(Name = "ChannelIds", Description = "The channels to return guide information for.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ChannelIds { get; set; }
|
||||
[ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ChannelId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Programs", "GET")]
|
||||
[Api(Description = "Gets available live tv epgs..")]
|
||||
public class GetPrograms : IReturn<QueryResult<ProgramInfoDto>>
|
||||
{
|
||||
[ApiMember(Name = "ServiceName", Description = "Live tv service name", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
[ApiMember(Name = "ChannelIds", Description = "The channels to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ChannelIds { get; set; }
|
||||
|
||||
[ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Recordings/{Id}", "DELETE")]
|
||||
[Api(Description = "Deletes a live tv recording")]
|
||||
public class DeleteRecording : IReturnVoid
|
||||
{
|
||||
[ApiMember(Name = "Id", Description = "Recording Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Timers/{Id}", "DELETE")]
|
||||
[Api(Description = "Cancels a live tv timer")]
|
||||
public class CancelTimer : IReturnVoid
|
||||
{
|
||||
[ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
public class LiveTvService : BaseApiService
|
||||
{
|
||||
private readonly ILiveTvManager _liveTvManager;
|
||||
|
@ -58,7 +130,7 @@ namespace MediaBrowser.Api.LiveTv
|
|||
|
||||
if (!string.IsNullOrEmpty(serviceName))
|
||||
{
|
||||
services = services.Where(i => string.Equals(i.Name, serviceName, System.StringComparison.OrdinalIgnoreCase));
|
||||
services = services.Where(i => string.Equals(i.Name, serviceName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
return services;
|
||||
|
@ -83,62 +155,87 @@ namespace MediaBrowser.Api.LiveTv
|
|||
|
||||
public object Get(GetChannels request)
|
||||
{
|
||||
var result = GetChannelsAsync(request).Result;
|
||||
|
||||
return ToOptimizedResult(result.ToList());
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<ChannelInfoDto>> GetChannelsAsync(GetChannels request)
|
||||
{
|
||||
var services = GetServices(request.ServiceName);
|
||||
|
||||
var tasks = services.Select(i => i.GetChannelsAsync(CancellationToken.None));
|
||||
|
||||
var channelLists = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
// Aggregate all channels from all services
|
||||
return channelLists.SelectMany(i => i)
|
||||
.Select(_liveTvManager.GetChannelInfoDto);
|
||||
}
|
||||
|
||||
public object Get(GetRecordings request)
|
||||
{
|
||||
var result = GetRecordingsAsync(request).Result;
|
||||
|
||||
return ToOptimizedResult(result.ToList());
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<RecordingInfo>> GetRecordingsAsync(GetRecordings request)
|
||||
{
|
||||
var services = GetServices(request.ServiceName);
|
||||
|
||||
var query = new RecordingQuery
|
||||
var result = _liveTvManager.GetChannels(new ChannelQuery
|
||||
{
|
||||
ChannelType = request.Type,
|
||||
ServiceName = request.ServiceName,
|
||||
UserId = request.UserId
|
||||
|
||||
};
|
||||
|
||||
var tasks = services.Select(i => i.GetRecordingsAsync(query, CancellationToken.None));
|
||||
|
||||
var recordings = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
return recordings.SelectMany(i => i);
|
||||
}
|
||||
|
||||
public object Get(GetGuide request)
|
||||
{
|
||||
var result = GetGuideAsync(request).Result;
|
||||
});
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<ChannelGuide>> GetGuideAsync(GetGuide request)
|
||||
public object Get(GetChannel request)
|
||||
{
|
||||
var service = GetServices(request.ServiceName)
|
||||
.First();
|
||||
var result = _liveTvManager.GetChannelInfoDto(request.Id, request.UserId);
|
||||
|
||||
var channels = request.ChannelIds.Split(',');
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
return await service.GetChannelGuidesAsync(channels, CancellationToken.None).ConfigureAwait(false);
|
||||
public object Get(GetPrograms request)
|
||||
{
|
||||
var result = _liveTvManager.GetPrograms(new ProgramQuery
|
||||
{
|
||||
ServiceName = request.ServiceName,
|
||||
ChannelIdList = (request.ChannelIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray(),
|
||||
UserId = request.UserId
|
||||
|
||||
}, CancellationToken.None).Result;
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public object Get(GetRecordings request)
|
||||
{
|
||||
var result = _liveTvManager.GetRecordings(new RecordingQuery
|
||||
{
|
||||
ChannelId = request.ChannelId,
|
||||
ServiceName = request.ServiceName
|
||||
|
||||
}, CancellationToken.None).Result;
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public object Get(GetRecording request)
|
||||
{
|
||||
var result = _liveTvManager.GetRecording(request.Id, CancellationToken.None).Result;
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public object Get(GetTimer request)
|
||||
{
|
||||
var result = _liveTvManager.GetTimer(request.Id, CancellationToken.None).Result;
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public object Get(GetTimers request)
|
||||
{
|
||||
var result = _liveTvManager.GetTimers(new TimerQuery
|
||||
{
|
||||
ChannelId = request.ChannelId,
|
||||
ServiceName = request.ServiceName
|
||||
|
||||
}, CancellationToken.None).Result;
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public void Delete(DeleteRecording request)
|
||||
{
|
||||
var task = _liveTvManager.DeleteRecording(request.Id);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
public void Delete(CancelTimer request)
|
||||
{
|
||||
var task = _liveTvManager.CancelTimer(request.Id);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,6 +38,18 @@
|
|||
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="ServiceStack.Common, Version=3.9.70.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\ServiceStack.Common.3.9.70\lib\net35\ServiceStack.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Interfaces, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\ServiceStack.Common.3.9.70\lib\net35\ServiceStack.Interfaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Text, Version=3.9.70.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\ServiceStack.Text.3.9.70\lib\net35\ServiceStack.Text.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
|
@ -47,15 +59,6 @@
|
|||
<Reference Include="MoreLinq">
|
||||
<HintPath>..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Common">
|
||||
<HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Interfaces">
|
||||
<HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Interfaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Text">
|
||||
<HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -70,6 +73,7 @@
|
|||
<Compile Include="EnvironmentService.cs" />
|
||||
<Compile Include="AuthorizationRequestFilterAttribute.cs" />
|
||||
<Compile Include="GamesService.cs" />
|
||||
<Compile Include="IHasItemFields.cs" />
|
||||
<Compile Include="Images\ImageByNameService.cs" />
|
||||
<Compile Include="Images\ImageRequest.cs" />
|
||||
<Compile Include="Images\ImageService.cs" />
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Globalization;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.MediaInfo;
|
||||
using MediaBrowser.Controller;
|
||||
|
@ -11,15 +10,15 @@ using MediaBrowser.Controller.MediaInfo;
|
|||
using MediaBrowser.Model.Drawing;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
namespace MediaBrowser.Api.Playback
|
||||
{
|
||||
|
@ -696,7 +695,7 @@ namespace MediaBrowser.Api.Playback
|
|||
// This is arbitrary, but add a little buffer time when internet streaming
|
||||
if (state.Item.LocationType == LocationType.Remote)
|
||||
{
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
await Task.Delay(4000).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
}
|
||||
|
||||
var volParam = string.Empty;
|
||||
var AudioSampleRate = string.Empty;
|
||||
var audioSampleRate = string.Empty;
|
||||
|
||||
// Boost volume to 200% when downsampling from 6ch to 2ch
|
||||
if (channels.HasValue && channels.Value <= 2 && state.AudioStream.Channels.HasValue && state.AudioStream.Channels.Value > 5)
|
||||
|
@ -98,10 +98,10 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
if (state.Request.AudioSampleRate.HasValue)
|
||||
{
|
||||
AudioSampleRate= state.Request.AudioSampleRate.Value + ":";
|
||||
audioSampleRate= state.Request.AudioSampleRate.Value + ":";
|
||||
}
|
||||
|
||||
args += string.Format(" -af \"adelay=1,aresample={0}async=1000{1}\"",AudioSampleRate, volParam);
|
||||
args += string.Format(" -af \"adelay=1,aresample={0}async=1000{1}\"",audioSampleRate, volParam);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
@ -127,6 +127,10 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
const string keyFrameArg = " -force_key_frames expr:if(isnan(prev_forced_t),gte(t,.1),gte(t,prev_forced_t+5))";
|
||||
|
||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsExternal &&
|
||||
(state.SubtitleStream.Codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
state.SubtitleStream.Codec.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1);
|
||||
|
||||
var args = "-codec:v:0 " + codec + " -preset superfast" + keyFrameArg;
|
||||
|
||||
var bitrate = GetVideoBitrateParam(state);
|
||||
|
@ -137,9 +141,12 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
}
|
||||
|
||||
// Add resolution params, if specified
|
||||
if (state.VideoRequest.Width.HasValue || state.VideoRequest.Height.HasValue || state.VideoRequest.MaxHeight.HasValue || state.VideoRequest.MaxWidth.HasValue)
|
||||
if (!hasGraphicalSubs)
|
||||
{
|
||||
args += GetOutputSizeParam(state, codec, performSubtitleConversion);
|
||||
if (state.VideoRequest.Width.HasValue || state.VideoRequest.Height.HasValue || state.VideoRequest.MaxHeight.HasValue || state.VideoRequest.MaxWidth.HasValue)
|
||||
{
|
||||
args += GetOutputSizeParam(state, codec, performSubtitleConversion);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.VideoRequest.Framerate.HasValue)
|
||||
|
@ -158,14 +165,11 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
args += " -level " + state.VideoRequest.Level;
|
||||
}
|
||||
|
||||
if (state.SubtitleStream != null)
|
||||
|
||||
// This is for internal graphical subs
|
||||
if (hasGraphicalSubs)
|
||||
{
|
||||
// This is for internal graphical subs
|
||||
if (!state.SubtitleStream.IsExternal && (state.SubtitleStream.Codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 || state.SubtitleStream.Codec.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1))
|
||||
{
|
||||
args += GetInternalGraphicalSubtitleParam(state, codec);
|
||||
}
|
||||
args += GetInternalGraphicalSubtitleParam(state, codec);
|
||||
}
|
||||
|
||||
return args;
|
||||
|
|
|
@ -127,44 +127,44 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
|
||||
const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000";
|
||||
|
||||
if (string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=MP3";
|
||||
}
|
||||
else if (string.Equals(extension, ".aac", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=AAC_ISO";
|
||||
}
|
||||
else if (string.Equals(extension, ".wma", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=WMABASE";
|
||||
}
|
||||
else if (string.Equals(extension, ".avi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=AVI";
|
||||
}
|
||||
else if (string.Equals(extension, ".mp4", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=MPEG4_P2_SP_AAC";
|
||||
}
|
||||
else if (string.Equals(extension, ".mpeg", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
|
||||
}
|
||||
else if (string.Equals(extension, ".wmv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
|
||||
}
|
||||
else if (string.Equals(extension, ".asf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// ??
|
||||
contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
|
||||
}
|
||||
else if (string.Equals(extension, ".mkv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// ??
|
||||
contentFeatures = "";
|
||||
}
|
||||
//if (string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// contentFeatures = "DLNA.ORG_PN=MP3";
|
||||
//}
|
||||
//else if (string.Equals(extension, ".aac", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// contentFeatures = "DLNA.ORG_PN=AAC_ISO";
|
||||
//}
|
||||
//else if (string.Equals(extension, ".wma", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// contentFeatures = "DLNA.ORG_PN=WMABASE";
|
||||
//}
|
||||
//else if (string.Equals(extension, ".avi", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// contentFeatures = "DLNA.ORG_PN=AVI";
|
||||
//}
|
||||
//else if (string.Equals(extension, ".mp4", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// contentFeatures = "DLNA.ORG_PN=MPEG4_P2_SP_AAC";
|
||||
//}
|
||||
//else if (string.Equals(extension, ".mpeg", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
|
||||
//}
|
||||
//else if (string.Equals(extension, ".wmv", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
|
||||
//}
|
||||
//else if (string.Equals(extension, ".asf", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// // ??
|
||||
// contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
|
||||
//}
|
||||
//else if (string.Equals(extension, ".mkv", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// // ??
|
||||
// contentFeatures = "";
|
||||
//}
|
||||
|
||||
if (!string.IsNullOrEmpty(contentFeatures))
|
||||
{
|
||||
|
@ -206,10 +206,10 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
var outputPath = GetOutputFilePath(state);
|
||||
var outputPathExists = File.Exists(outputPath);
|
||||
|
||||
//var isStatic = request.Static ||
|
||||
// (outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive));
|
||||
var isStatic = request.Static ||
|
||||
(outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive));
|
||||
|
||||
//AddDlnaHeaders(state, responseHeaders, isStatic);
|
||||
AddDlnaHeaders(state, responseHeaders, isStatic);
|
||||
|
||||
if (request.Static)
|
||||
{
|
||||
|
@ -307,7 +307,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
}
|
||||
}
|
||||
|
||||
return new ImageService(UserManager, LibraryManager, ApplicationPaths, null, ItemRepository, DtoService, ImageProcessor)
|
||||
return new ImageService(UserManager, LibraryManager, ApplicationPaths, null, ItemRepository, DtoService, ImageProcessor, null)
|
||||
{
|
||||
Logger = Logger,
|
||||
RequestContext = RequestContext,
|
||||
|
|
|
@ -143,12 +143,19 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
|
||||
args += keyFrameArg;
|
||||
|
||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsExternal &&
|
||||
(state.SubtitleStream.Codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
state.SubtitleStream.Codec.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1);
|
||||
|
||||
var request = state.VideoRequest;
|
||||
|
||||
// Add resolution params, if specified
|
||||
if (request.Width.HasValue || request.Height.HasValue || request.MaxHeight.HasValue || request.MaxWidth.HasValue)
|
||||
if (!hasGraphicalSubs)
|
||||
{
|
||||
args += GetOutputSizeParam(state, codec, performSubtitleConversion);
|
||||
if (request.Width.HasValue || request.Height.HasValue || request.MaxHeight.HasValue || request.MaxWidth.HasValue)
|
||||
{
|
||||
args += GetOutputSizeParam(state, codec, performSubtitleConversion);
|
||||
}
|
||||
}
|
||||
|
||||
if (request.Framerate.HasValue)
|
||||
|
@ -175,13 +182,10 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
args += " -level " + state.VideoRequest.Level;
|
||||
}
|
||||
|
||||
if (state.SubtitleStream != null)
|
||||
// This is for internal graphical subs
|
||||
if (hasGraphicalSubs)
|
||||
{
|
||||
// This is for internal graphical subs
|
||||
if (!state.SubtitleStream.IsExternal && (state.SubtitleStream.Codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 || state.SubtitleStream.Codec.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1))
|
||||
{
|
||||
args += GetInternalGraphicalSubtitleParam(state, codec);
|
||||
}
|
||||
args += GetInternalGraphicalSubtitleParam(state, codec);
|
||||
}
|
||||
|
||||
return args;
|
||||
|
|
|
@ -31,7 +31,8 @@ namespace MediaBrowser.Api.ScheduledTasks
|
|||
[Api(Description = "Gets scheduled tasks")]
|
||||
public class GetScheduledTasks : IReturn<List<TaskInfo>>
|
||||
{
|
||||
|
||||
[ApiMember(Name = "IsHidden", Description = "Optional filter tasks that are hidden, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsHidden { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -112,10 +113,33 @@ namespace MediaBrowser.Api.ScheduledTasks
|
|||
/// <returns>IEnumerable{TaskInfo}.</returns>
|
||||
public object Get(GetScheduledTasks request)
|
||||
{
|
||||
var result = TaskManager.ScheduledTasks.OrderBy(i => i.Name)
|
||||
.Select(ScheduledTaskHelpers.GetTaskInfo).ToList();
|
||||
IEnumerable<IScheduledTaskWorker> result = TaskManager.ScheduledTasks
|
||||
.OrderBy(i => i.Name);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
if (request.IsHidden.HasValue)
|
||||
{
|
||||
var val = request.IsHidden.Value;
|
||||
|
||||
result = result.Where(i =>
|
||||
{
|
||||
var isHidden = false;
|
||||
|
||||
var configurableTask = i.ScheduledTask as IConfigurableScheduledTask;
|
||||
|
||||
if (configurableTask != null)
|
||||
{
|
||||
isHidden = configurableTask.IsHidden;
|
||||
}
|
||||
|
||||
return isHidden == val;
|
||||
});
|
||||
}
|
||||
|
||||
var infos = result
|
||||
.Select(ScheduledTaskHelpers.GetTaskInfo)
|
||||
.ToList();
|
||||
|
||||
return ToOptimizedResult(infos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -46,8 +46,10 @@ namespace MediaBrowser.Api.ScheduledTasks
|
|||
/// <returns>Task{IEnumerable{TaskInfo}}.</returns>
|
||||
protected override Task<IEnumerable<TaskInfo>> GetDataToSend(object state)
|
||||
{
|
||||
return Task.FromResult(TaskManager.ScheduledTasks.OrderBy(i => i.Name)
|
||||
.Select(ScheduledTaskHelpers.GetTaskInfo));
|
||||
return Task.FromResult(TaskManager.ScheduledTasks
|
||||
.OrderBy(i => i.Name)
|
||||
.Select(ScheduledTaskHelpers.GetTaskInfo)
|
||||
.Where(i => !i.IsHidden));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ namespace MediaBrowser.Api
|
|||
IndexNumber = item.IndexNumber,
|
||||
ParentIndexNumber = item.ParentIndexNumber,
|
||||
ItemId = _dtoService.GetDtoId(item),
|
||||
Type = item.GetType().Name,
|
||||
Type = item.GetClientTypeName(),
|
||||
MediaType = item.MediaType,
|
||||
MatchedTerm = hintInfo.MatchedTerm,
|
||||
DisplayMediaType = item.DisplayMediaType,
|
||||
|
@ -187,9 +187,7 @@ namespace MediaBrowser.Api
|
|||
|
||||
result.SongCount = songs.Count;
|
||||
|
||||
result.Artists = songs
|
||||
.SelectMany(i => i.Artists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
result.Artists = _libraryManager.GetAllArtists(songs)
|
||||
.ToArray();
|
||||
|
||||
result.AlbumArtist = songs.Select(i => i.AlbumArtist).FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace MediaBrowser.Api
|
|||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
public class BaseGetSimilarItems : IReturn<ItemsResult>
|
||||
public class BaseGetSimilarItems : IReturn<ItemsResult>, IHasItemFields
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
|
@ -47,32 +47,6 @@ namespace MediaBrowser.Api
|
|||
/// <value>The fields.</value>
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, OverviewHtml, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item fields.
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{ItemFields}.</returns>
|
||||
public IEnumerable<ItemFields> GetItemFields()
|
||||
{
|
||||
var val = Fields;
|
||||
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
return new ItemFields[] { };
|
||||
}
|
||||
|
||||
return val.Split(',').Select(v =>
|
||||
{
|
||||
ItemFields value;
|
||||
|
||||
if (Enum.TryParse(v, true, out value))
|
||||
{
|
||||
return (ItemFields?)value;
|
||||
}
|
||||
return null;
|
||||
|
||||
}).Where(i => i.HasValue).Select(i => i.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Api.UserLibrary;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
@ -17,7 +18,7 @@ namespace MediaBrowser.Api
|
|||
/// </summary>
|
||||
[Route("/Shows/NextUp", "GET")]
|
||||
[Api(("Gets a list of currently installed plugins"))]
|
||||
public class GetNextUpEpisodes : IReturn<ItemsResult>
|
||||
public class GetNextUpEpisodes : IReturn<ItemsResult>, IHasItemFields
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
|
@ -49,32 +50,6 @@ namespace MediaBrowser.Api
|
|||
|
||||
[ApiMember(Name = "SeriesId", Description = "Optional. Filter by series id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string SeriesId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item fields.
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{ItemFields}.</returns>
|
||||
public IEnumerable<ItemFields> GetItemFields()
|
||||
{
|
||||
var val = Fields;
|
||||
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
return new ItemFields[] { };
|
||||
}
|
||||
|
||||
return val.Split(',').Select(v =>
|
||||
{
|
||||
ItemFields value;
|
||||
|
||||
if (Enum.TryParse(v, true, out value))
|
||||
{
|
||||
return (ItemFields?)value;
|
||||
}
|
||||
return null;
|
||||
|
||||
}).Where(i => i.HasValue).Select(i => i.Value);
|
||||
}
|
||||
}
|
||||
|
||||
[Route("/Shows/{Id}/Similar", "GET")]
|
||||
|
@ -83,6 +58,77 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
}
|
||||
|
||||
[Route("/Shows/{Id}/Episodes", "GET")]
|
||||
[Api(Description = "Gets episodes for a tv season")]
|
||||
public class GetEpisodes : IReturn<ItemsResult>, IHasItemFields
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, OverviewHtml, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { get; set; }
|
||||
|
||||
[ApiMember(Name = "Id", Description = "The series id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "Season", Description = "Optional filter by season number.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public int? Season { get; set; }
|
||||
|
||||
[ApiMember(Name = "SeasonId", Description = "Optional. Filter by season id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string SeasonId { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsMissing { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsVirtualUnaired", Description = "Optional filter by items that are virtual unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsVirtualUnaired { get; set; }
|
||||
|
||||
[ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string AdjacentTo { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Shows/{Id}/Seasons", "GET")]
|
||||
[Api(Description = "Gets seasons for a tv series")]
|
||||
public class GetSeasons : IReturn<ItemsResult>, IHasItemFields
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, OverviewHtml, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { get; set; }
|
||||
|
||||
[ApiMember(Name = "Id", Description = "The series id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsSpecialSeason", Description = "Optional. Filter by special season.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsSpecialSeason { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsMissing { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsVirtualUnaired", Description = "Optional filter by items that are virtual unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsVirtualUnaired { get; set; }
|
||||
|
||||
[ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string AdjacentTo { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class TvShowsService
|
||||
/// </summary>
|
||||
|
@ -311,5 +357,196 @@ namespace MediaBrowser.Api
|
|||
|
||||
return items;
|
||||
}
|
||||
|
||||
public object Get(GetSeasons request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var series = _libraryManager.GetItemById(request.Id) as Series;
|
||||
|
||||
var fields = request.GetItemFields().ToList();
|
||||
|
||||
var seasons = series.GetChildren(user, true)
|
||||
.OfType<Season>();
|
||||
|
||||
var sortOrder = ItemSortBy.SortName;
|
||||
|
||||
if (request.IsSpecialSeason.HasValue)
|
||||
{
|
||||
var val = request.IsSpecialSeason.Value;
|
||||
|
||||
seasons = seasons.Where(i => i.IsSpecialSeason == val);
|
||||
}
|
||||
|
||||
var config = user.Configuration;
|
||||
|
||||
if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes)
|
||||
{
|
||||
seasons = seasons.Where(i => !i.IsMissingOrVirtualUnaired);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!config.DisplayMissingEpisodes)
|
||||
{
|
||||
seasons = seasons.Where(i => !i.IsMissingSeason);
|
||||
}
|
||||
if (!config.DisplayUnairedEpisodes)
|
||||
{
|
||||
seasons = seasons.Where(i => !i.IsVirtualUnaired);
|
||||
}
|
||||
}
|
||||
|
||||
seasons = FilterVirtualSeasons(request, seasons);
|
||||
|
||||
seasons = _libraryManager.Sort(seasons, user, new[] { sortOrder }, SortOrder.Ascending)
|
||||
.Cast<Season>();
|
||||
|
||||
// This must be the last filter
|
||||
if (!string.IsNullOrEmpty(request.AdjacentTo))
|
||||
{
|
||||
seasons = ItemsService.FilterForAdjacency(seasons, request.AdjacentTo)
|
||||
.Cast<Season>();
|
||||
}
|
||||
|
||||
var returnItems = seasons.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
|
||||
.ToArray();
|
||||
|
||||
return new ItemsResult
|
||||
{
|
||||
TotalRecordCount = returnItems.Length,
|
||||
Items = returnItems
|
||||
};
|
||||
}
|
||||
|
||||
private IEnumerable<Season> FilterVirtualSeasons(GetSeasons request, IEnumerable<Season> items)
|
||||
{
|
||||
if (request.IsMissing.HasValue && request.IsVirtualUnaired.HasValue)
|
||||
{
|
||||
var isMissing = request.IsMissing.Value;
|
||||
var isVirtualUnaired = request.IsVirtualUnaired.Value;
|
||||
|
||||
if (!isMissing && !isVirtualUnaired)
|
||||
{
|
||||
return items.Where(i => !i.IsMissingOrVirtualUnaired);
|
||||
}
|
||||
}
|
||||
|
||||
if (request.IsMissing.HasValue)
|
||||
{
|
||||
var val = request.IsMissing.Value;
|
||||
items = items.Where(i => i.IsMissingSeason == val);
|
||||
}
|
||||
|
||||
if (request.IsVirtualUnaired.HasValue)
|
||||
{
|
||||
var val = request.IsVirtualUnaired.Value;
|
||||
items = items.Where(i => i.IsVirtualUnaired == val);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
public object Get(GetEpisodes request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var series = _libraryManager.GetItemById(request.Id) as Series;
|
||||
|
||||
var fields = request.GetItemFields().ToList();
|
||||
|
||||
var episodes = series.GetRecursiveChildren(user)
|
||||
.OfType<Episode>();
|
||||
|
||||
var sortOrder = ItemSortBy.SortName;
|
||||
|
||||
if (!string.IsNullOrEmpty(request.SeasonId))
|
||||
{
|
||||
var season = _libraryManager.GetItemById(new Guid(request.SeasonId)) as Season;
|
||||
|
||||
if (season.IndexNumber.HasValue)
|
||||
{
|
||||
episodes = FilterEpisodesBySeason(episodes, season.IndexNumber.Value, true);
|
||||
|
||||
sortOrder = ItemSortBy.AiredEpisodeOrder;
|
||||
}
|
||||
else
|
||||
{
|
||||
episodes = season.RecursiveChildren.OfType<Episode>();
|
||||
|
||||
sortOrder = ItemSortBy.SortName;
|
||||
}
|
||||
}
|
||||
|
||||
else if (request.Season.HasValue)
|
||||
{
|
||||
episodes = FilterEpisodesBySeason(episodes, request.Season.Value, true);
|
||||
|
||||
sortOrder = ItemSortBy.AiredEpisodeOrder;
|
||||
}
|
||||
|
||||
var config = user.Configuration;
|
||||
|
||||
if (!config.DisplayMissingEpisodes)
|
||||
{
|
||||
episodes = episodes.Where(i => !i.IsMissingEpisode);
|
||||
}
|
||||
if (!config.DisplayUnairedEpisodes)
|
||||
{
|
||||
episodes = episodes.Where(i => !i.IsVirtualUnaired);
|
||||
}
|
||||
|
||||
if (request.IsMissing.HasValue)
|
||||
{
|
||||
var val = request.IsMissing.Value;
|
||||
episodes = episodes.Where(i => i.IsMissingEpisode == val);
|
||||
}
|
||||
|
||||
if (request.IsVirtualUnaired.HasValue)
|
||||
{
|
||||
var val = request.IsVirtualUnaired.Value;
|
||||
episodes = episodes.Where(i => i.IsVirtualUnaired == val);
|
||||
}
|
||||
|
||||
episodes = _libraryManager.Sort(episodes, user, new[] { sortOrder }, SortOrder.Ascending)
|
||||
.Cast<Episode>();
|
||||
|
||||
// This must be the last filter
|
||||
if (!string.IsNullOrEmpty(request.AdjacentTo))
|
||||
{
|
||||
episodes = ItemsService.FilterForAdjacency(episodes, request.AdjacentTo)
|
||||
.Cast<Episode>();
|
||||
}
|
||||
|
||||
var returnItems = episodes.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
|
||||
.ToArray();
|
||||
|
||||
return new ItemsResult
|
||||
{
|
||||
TotalRecordCount = returnItems.Length,
|
||||
Items = returnItems
|
||||
};
|
||||
}
|
||||
|
||||
internal static IEnumerable<Episode> FilterEpisodesBySeason(IEnumerable<Episode> episodes, int seasonNumber, bool includeSpecials)
|
||||
{
|
||||
if (!includeSpecials || seasonNumber < 1)
|
||||
{
|
||||
return episodes.Where(i => (i.PhysicalSeasonNumber ?? -1) == seasonNumber);
|
||||
}
|
||||
|
||||
return episodes.Where(i =>
|
||||
{
|
||||
var episode = i;
|
||||
|
||||
if (episode != null)
|
||||
{
|
||||
var currentSeasonNumber = episode.AiredSeasonNumber;
|
||||
|
||||
return currentSeasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <summary>
|
||||
/// Class ArtistsService
|
||||
/// </summary>
|
||||
public class ArtistsService : BaseItemsByNameService<Artist>
|
||||
public class ArtistsService : BaseItemsByNameService<MusicArtist>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArtistsService" /> class.
|
||||
|
@ -109,24 +109,9 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <param name="request">The request.</param>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
|
||||
protected override IEnumerable<Artist> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
protected override IEnumerable<MusicArtist> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
{
|
||||
var itemsList = items.OfType<Audio>().ToList();
|
||||
|
||||
return itemsList
|
||||
.SelectMany(i =>
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(i.AlbumArtist))
|
||||
{
|
||||
list.Add(i.AlbumArtist);
|
||||
}
|
||||
list.AddRange(i.Artists);
|
||||
|
||||
return list;
|
||||
})
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
return LibraryManager.GetAllArtists(items)
|
||||
.Select(name => LibraryManager.GetArtist(name));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ using System;
|
|||
|
||||
namespace MediaBrowser.Api.UserLibrary
|
||||
{
|
||||
public abstract class BaseItemsRequest
|
||||
public abstract class BaseItemsRequest : IHasItemFields
|
||||
{
|
||||
/// <summary>
|
||||
/// Skips over a given number of items within the results. Use for paging.
|
||||
|
@ -109,32 +109,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return val.Split(',').Select(v => (ItemFilter)Enum.Parse(typeof(ItemFilter), v, true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item fields.
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{ItemFields}.</returns>
|
||||
public IEnumerable<ItemFields> GetItemFields()
|
||||
{
|
||||
var val = Fields;
|
||||
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
return new ItemFields[] { };
|
||||
}
|
||||
|
||||
return val.Split(',').Select(v =>
|
||||
{
|
||||
ItemFields value;
|
||||
|
||||
if (Enum.TryParse(v, true, out value))
|
||||
{
|
||||
return (ItemFields?)value;
|
||||
}
|
||||
return null;
|
||||
|
||||
}).Where(i => i.HasValue).Select(i => i.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image types.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
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.Localization;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using ServiceStack.ServiceHost;
|
||||
|
@ -205,6 +208,27 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
[ApiMember(Name = "AiredDuringSeason", Description = "Gets all episodes that aired during a season, including specials.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? AiredDuringSeason { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinPremiereDate", Description = "Optional. The minimum premiere date. Format = yyyyMMddHHmmss", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string MinPremiereDate { get; set; }
|
||||
|
||||
[ApiMember(Name = "MaxPremiereDate", Description = "Optional. The maximum premiere date. Format = yyyyMMddHHmmss", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string MaxPremiereDate { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasOverview", Description = "Optional filter by items that have an overview or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasOverview { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasImdbId", Description = "Optional filter by items that have an imdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasImdbId { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasTmdbId", Description = "Optional filter by items that have a tmdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasTmdbId { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasTvdbId", Description = "Optional filter by items that have a tvdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasTvdbId { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsYearMismatched", Description = "Optional filter by items that are potentially misidentified.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsYearMismatched { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -286,6 +310,12 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
items = ApplySortOrder(request, items, user, _libraryManager);
|
||||
|
||||
// This must be the last filter
|
||||
if (!string.IsNullOrEmpty(request.AdjacentTo))
|
||||
{
|
||||
items = FilterForAdjacency(items, request.AdjacentTo);
|
||||
}
|
||||
|
||||
var itemsArray = items.ToList();
|
||||
|
||||
var pagedItems = ApplyPaging(request, itemsArray);
|
||||
|
@ -642,30 +672,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.AdjacentTo))
|
||||
{
|
||||
var item = _dtoService.GetItemByDtoId(request.AdjacentTo);
|
||||
|
||||
var allSiblings = item.Parent.GetChildren(user, true).OrderBy(i => i.SortName).ToList();
|
||||
|
||||
var index = allSiblings.IndexOf(item);
|
||||
|
||||
var previousId = Guid.Empty;
|
||||
var nextId = Guid.Empty;
|
||||
|
||||
if (index > 0)
|
||||
{
|
||||
previousId = allSiblings[index - 1].Id;
|
||||
}
|
||||
|
||||
if (index < allSiblings.Count - 1)
|
||||
{
|
||||
nextId = allSiblings[index + 1].Id;
|
||||
}
|
||||
|
||||
items = items.Where(i => i.Id == previousId || i.Id == nextId);
|
||||
}
|
||||
|
||||
// Min index number
|
||||
if (request.MinIndexNumber.HasValue)
|
||||
{
|
||||
|
@ -861,7 +867,19 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
if (request.HasTrailer.HasValue)
|
||||
{
|
||||
items = items.Where(i => request.HasTrailer.Value ? i.LocalTrailerIds.Count > 0 : i.LocalTrailerIds.Count == 0);
|
||||
var val = request.HasTrailer.Value;
|
||||
items = items.Where(i =>
|
||||
{
|
||||
var trailerCount = 0;
|
||||
|
||||
var hasTrailers = i as IHasTrailers;
|
||||
if (hasTrailers != null)
|
||||
{
|
||||
trailerCount = hasTrailers.LocalTrailerIds.Count;
|
||||
}
|
||||
|
||||
return val ? trailerCount > 0 : trailerCount == 0;
|
||||
});
|
||||
}
|
||||
|
||||
if (request.HasThemeSong.HasValue)
|
||||
|
@ -1005,26 +1023,134 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
if (request.AiredDuringSeason.HasValue)
|
||||
{
|
||||
var val = request.AiredDuringSeason.Value;
|
||||
items = TvShowsService.FilterEpisodesBySeason(items.OfType<Episode>(), request.AiredDuringSeason.Value, true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.MinPremiereDate))
|
||||
{
|
||||
var date = DateTime.ParseExact(request.MinPremiereDate, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
|
||||
|
||||
items = items.Where(i => i.PremiereDate.HasValue && i.PremiereDate.Value >= date);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.MaxPremiereDate))
|
||||
{
|
||||
var date = DateTime.ParseExact(request.MaxPremiereDate, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
|
||||
|
||||
items = items.Where(i => i.PremiereDate.HasValue && i.PremiereDate.Value <= date);
|
||||
}
|
||||
|
||||
if (request.HasOverview.HasValue)
|
||||
{
|
||||
var filterValue = request.HasOverview.Value;
|
||||
|
||||
items = items.Where(i =>
|
||||
{
|
||||
var episode = i as Episode;
|
||||
var hasValue = !string.IsNullOrEmpty(i.Overview);
|
||||
|
||||
if (episode != null)
|
||||
{
|
||||
var seasonNumber = episode.AirsAfterSeasonNumber ?? episode.AirsBeforeEpisodeNumber ?? episode.ParentIndexNumber;
|
||||
|
||||
return episode.PremiereDate.HasValue && seasonNumber.HasValue && seasonNumber.Value == val;
|
||||
}
|
||||
|
||||
return false;
|
||||
return hasValue == filterValue;
|
||||
});
|
||||
}
|
||||
|
||||
if (request.HasImdbId.HasValue)
|
||||
{
|
||||
var filterValue = request.HasImdbId.Value;
|
||||
|
||||
items = items.Where(i =>
|
||||
{
|
||||
var hasValue = !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Imdb));
|
||||
|
||||
return hasValue == filterValue;
|
||||
});
|
||||
}
|
||||
|
||||
if (request.HasTmdbId.HasValue)
|
||||
{
|
||||
var filterValue = request.HasTmdbId.Value;
|
||||
|
||||
items = items.Where(i =>
|
||||
{
|
||||
var hasValue = !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tmdb));
|
||||
|
||||
return hasValue == filterValue;
|
||||
});
|
||||
}
|
||||
|
||||
if (request.HasTvdbId.HasValue)
|
||||
{
|
||||
var filterValue = request.HasTvdbId.Value;
|
||||
|
||||
items = items.Where(i =>
|
||||
{
|
||||
var hasValue = !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb));
|
||||
|
||||
return hasValue == filterValue;
|
||||
});
|
||||
}
|
||||
|
||||
if (request.IsYearMismatched.HasValue)
|
||||
{
|
||||
var filterValue = request.IsYearMismatched.Value;
|
||||
|
||||
items = items.Where(i => IsYearMismatched(i) == filterValue);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private bool IsYearMismatched(BaseItem item)
|
||||
{
|
||||
if (item.ProductionYear.HasValue)
|
||||
{
|
||||
var path = item.Path;
|
||||
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
int? yearInName;
|
||||
string name;
|
||||
NameParser.ParseName(Path.GetFileName(path), out name, out yearInName);
|
||||
|
||||
// Go up a level if we didn't get a year
|
||||
if (!yearInName.HasValue)
|
||||
{
|
||||
NameParser.ParseName(Path.GetFileName(Path.GetDirectoryName(path)), out name, out yearInName);
|
||||
}
|
||||
|
||||
if (yearInName.HasValue)
|
||||
{
|
||||
return yearInName.Value != item.ProductionYear.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static IEnumerable<BaseItem> FilterForAdjacency(IEnumerable<BaseItem> items, string adjacentToId)
|
||||
{
|
||||
var list = items.ToList();
|
||||
|
||||
var adjacentToIdGuid = new Guid(adjacentToId);
|
||||
var adjacentToItem = list.FirstOrDefault(i => i.Id == adjacentToIdGuid);
|
||||
|
||||
var index = list.IndexOf(adjacentToItem);
|
||||
|
||||
var previousId = Guid.Empty;
|
||||
var nextId = Guid.Empty;
|
||||
|
||||
if (index > 0)
|
||||
{
|
||||
previousId = list[index - 1].Id;
|
||||
}
|
||||
|
||||
if (index < list.Count - 1)
|
||||
{
|
||||
nextId = list[index + 1].Id;
|
||||
}
|
||||
|
||||
return list.Where(i => i.Id == previousId || i.Id == nextId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified item has image.
|
||||
/// </summary>
|
||||
|
|
|
@ -155,7 +155,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <returns>IEnumerable{PersonInfo}.</returns>
|
||||
private IEnumerable<PersonInfo> GetAllPeople(IEnumerable<BaseItem> itemsList, string[] personTypes)
|
||||
{
|
||||
var people = itemsList.SelectMany(i => i.People.OrderBy(p => p.Type));
|
||||
var people = itemsList.SelectMany(i => i.People.OrderBy(p => p.SortOrder ?? int.MaxValue).ThenBy(p => p.Type));
|
||||
|
||||
return personTypes.Length == 0 ?
|
||||
|
||||
|
|
|
@ -489,7 +489,15 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
// Get everything
|
||||
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
|
||||
|
||||
var dtos = item.LocalTrailerIds
|
||||
var trailerIds = new List<Guid>();
|
||||
|
||||
var hasTrailers = item as IHasTrailers;
|
||||
if (hasTrailers != null)
|
||||
{
|
||||
trailerIds = hasTrailers.LocalTrailerIds;
|
||||
}
|
||||
|
||||
var dtos = trailerIds
|
||||
.Select(_libraryManager.GetItemById)
|
||||
.OrderBy(i => i.SortName)
|
||||
.Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="morelinq" version="1.0.16006" targetFramework="net45" />
|
||||
<package id="ServiceStack.Common" version="3.9.62" targetFramework="net45" />
|
||||
<package id="ServiceStack.Text" version="3.9.62" targetFramework="net45" />
|
||||
<package id="ServiceStack.Common" version="3.9.70" targetFramework="net45" />
|
||||
<package id="ServiceStack.Text" version="3.9.70" targetFramework="net45" />
|
||||
</packages>
|
|
@ -22,7 +22,6 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -34,7 +33,7 @@ namespace MediaBrowser.Common.Implementations
|
|||
/// </summary>
|
||||
/// <typeparam name="TApplicationPathsType">The type of the T application paths type.</typeparam>
|
||||
public abstract class BaseApplicationHost<TApplicationPathsType> : IApplicationHost
|
||||
where TApplicationPathsType : class, IApplicationPaths, new()
|
||||
where TApplicationPathsType : class, IApplicationPaths
|
||||
{
|
||||
/// <summary>
|
||||
/// Occurs when [has pending restart changed].
|
||||
|
@ -84,7 +83,7 @@ namespace MediaBrowser.Common.Implementations
|
|||
/// <summary>
|
||||
/// The json serializer
|
||||
/// </summary>
|
||||
public readonly IJsonSerializer JsonSerializer = new JsonSerializer();
|
||||
public IJsonSerializer JsonSerializer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The _XML serializer
|
||||
|
@ -154,7 +153,7 @@ namespace MediaBrowser.Common.Implementations
|
|||
protected IInstallationManager InstallationManager { get; private set; }
|
||||
|
||||
protected IFileSystem FileSystemManager { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the zip client.
|
||||
/// </summary>
|
||||
|
@ -182,6 +181,8 @@ namespace MediaBrowser.Common.Implementations
|
|||
/// <returns>Task.</returns>
|
||||
public virtual async Task Init()
|
||||
{
|
||||
JsonSerializer = CreateJsonSerializer();
|
||||
|
||||
IsFirstRun = !ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted;
|
||||
|
||||
Logger = LogManager.GetLogger("App");
|
||||
|
@ -213,19 +214,24 @@ namespace MediaBrowser.Common.Implementations
|
|||
|
||||
}
|
||||
|
||||
protected virtual IJsonSerializer CreateJsonSerializer()
|
||||
{
|
||||
return new JsonSerializer();
|
||||
}
|
||||
|
||||
private void SetHttpLimit()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Increase the max http request limit
|
||||
ServicePointManager.DefaultConnectionLimit = Math.Max(48, ServicePointManager.DefaultConnectionLimit);
|
||||
ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error setting http limit", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Installs the iso mounters.
|
||||
/// </summary>
|
||||
|
@ -353,7 +359,7 @@ namespace MediaBrowser.Common.Implementations
|
|||
FileSystemManager = CreateFileSystemManager();
|
||||
RegisterSingleInstance(FileSystemManager);
|
||||
|
||||
HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, CreateHttpClient, FileSystemManager);
|
||||
HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, FileSystemManager);
|
||||
RegisterSingleInstance(HttpClient);
|
||||
|
||||
NetworkManager = CreateNetworkManager();
|
||||
|
@ -378,8 +384,6 @@ namespace MediaBrowser.Common.Implementations
|
|||
return new CommonFileSystem(Logger, true);
|
||||
}
|
||||
|
||||
protected abstract HttpClient CreateHttpClient(bool enableHttpCompression);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of types within an assembly
|
||||
/// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference
|
||||
|
|
|
@ -20,21 +20,23 @@ namespace MediaBrowser.Common.Implementations
|
|||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseApplicationPaths" /> class.
|
||||
/// </summary>
|
||||
/// <param name="useDebugPath">if set to <c>true</c> [use debug paths].</param>
|
||||
protected BaseApplicationPaths(bool useDebugPath)
|
||||
protected BaseApplicationPaths(bool useDebugPath, string applicationPath)
|
||||
{
|
||||
_useDebugPath = useDebugPath;
|
||||
ApplicationPath = applicationPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseApplicationPaths"/> class.
|
||||
/// </summary>
|
||||
/// <param name="programDataPath">The program data path.</param>
|
||||
protected BaseApplicationPaths(string programDataPath)
|
||||
protected BaseApplicationPaths(string programDataPath, string applicationPath)
|
||||
{
|
||||
_programDataPath = programDataPath;
|
||||
ApplicationPath = applicationPath;
|
||||
}
|
||||
|
||||
public string ApplicationPath { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The _program data path
|
||||
/// </summary>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace MediaBrowser.Common.Implementations.HttpClientManager
|
||||
{
|
||||
|
@ -8,11 +7,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
/// </summary>
|
||||
public class HttpClientInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the HTTP client.
|
||||
/// </summary>
|
||||
/// <value>The HTTP client.</value>
|
||||
public HttpClient HttpClient { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the last timeout.
|
||||
/// </summary>
|
||||
|
|
|
@ -9,7 +9,10 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Cache;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -21,6 +24,11 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
/// </summary>
|
||||
public class HttpClientManager : IHttpClient
|
||||
{
|
||||
/// <summary>
|
||||
/// When one request to a host times out, we'll ban all other requests for this period of time, to prevent scans from stalling
|
||||
/// </summary>
|
||||
private const int TimeoutSeconds = 30;
|
||||
|
||||
/// <summary>
|
||||
/// The _logger
|
||||
/// </summary>
|
||||
|
@ -31,23 +39,18 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
/// </summary>
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
|
||||
public delegate HttpClient GetHttpClientHandler(bool enableHttpCompression);
|
||||
|
||||
private readonly GetHttpClientHandler _getHttpClientHandler;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpClientManager"/> class.
|
||||
/// Initializes a new instance of the <see cref="HttpClientManager" /> class.
|
||||
/// </summary>
|
||||
/// <param name="appPaths">The app paths.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="getHttpClientHandler">The get HTTP client handler.</param>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// appPaths
|
||||
/// <param name="fileSystem">The file system.</param>
|
||||
/// <exception cref="System.ArgumentNullException">appPaths
|
||||
/// or
|
||||
/// logger
|
||||
/// </exception>
|
||||
public HttpClientManager(IApplicationPaths appPaths, ILogger logger, GetHttpClientHandler getHttpClientHandler, IFileSystem fileSystem)
|
||||
/// logger</exception>
|
||||
public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem)
|
||||
{
|
||||
if (appPaths == null)
|
||||
{
|
||||
|
@ -59,7 +62,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
}
|
||||
|
||||
_logger = logger;
|
||||
_getHttpClientHandler = getHttpClientHandler;
|
||||
_fileSystem = fileSystem;
|
||||
_appPaths = appPaths;
|
||||
}
|
||||
|
@ -91,17 +93,82 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
|
||||
if (!_httpClients.TryGetValue(key, out client))
|
||||
{
|
||||
client = new HttpClientInfo
|
||||
{
|
||||
client = new HttpClientInfo();
|
||||
|
||||
HttpClient = _getHttpClientHandler(enableHttpCompression)
|
||||
};
|
||||
_httpClients.TryAdd(key, client);
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
private WebRequest GetMonoRequest(HttpRequestOptions options, string method, bool enableHttpCompression)
|
||||
{
|
||||
var request = WebRequest.Create(options.Url);
|
||||
|
||||
if (!string.IsNullOrEmpty(options.AcceptHeader))
|
||||
{
|
||||
request.Headers.Add("Accept", options.AcceptHeader);
|
||||
}
|
||||
|
||||
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.Revalidate);
|
||||
request.ConnectionGroupName = GetHostFromUrl(options.Url);
|
||||
request.Method = method;
|
||||
request.Timeout = 20000;
|
||||
|
||||
if (!string.IsNullOrEmpty(options.UserAgent))
|
||||
{
|
||||
request.Headers.Add("User-Agent", options.UserAgent);
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
private PropertyInfo _httpBehaviorPropertyInfo;
|
||||
private WebRequest GetRequest(HttpRequestOptions options, string method, bool enableHttpCompression)
|
||||
{
|
||||
#if __MonoCS__
|
||||
return GetMonoRequest(options, method, enableHttpCompression);
|
||||
#endif
|
||||
|
||||
var request = HttpWebRequest.CreateHttp(options.Url);
|
||||
|
||||
if (!string.IsNullOrEmpty(options.AcceptHeader))
|
||||
{
|
||||
request.Accept = options.AcceptHeader;
|
||||
}
|
||||
|
||||
request.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None;
|
||||
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.Revalidate);
|
||||
request.ConnectionGroupName = GetHostFromUrl(options.Url);
|
||||
request.KeepAlive = true;
|
||||
request.Method = method;
|
||||
request.Pipelined = true;
|
||||
request.Timeout = 20000;
|
||||
|
||||
if (!string.IsNullOrEmpty(options.UserAgent))
|
||||
{
|
||||
request.UserAgent = options.UserAgent;
|
||||
}
|
||||
|
||||
// This is a hack to prevent KeepAlive from getting disabled internally by the HttpWebRequest
|
||||
// May need to remove this for mono
|
||||
var sp = request.ServicePoint;
|
||||
if (_httpBehaviorPropertyInfo == null)
|
||||
{
|
||||
_httpBehaviorPropertyInfo = sp.GetType().GetProperty("HttpBehaviour", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
}
|
||||
_httpBehaviorPropertyInfo.SetValue(sp, (byte)0, null);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the response internal.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>Task{HttpResponseInfo}.</returns>
|
||||
/// <exception cref="HttpException">
|
||||
/// </exception>
|
||||
public async Task<HttpResponseInfo> GetResponse(HttpRequestOptions options)
|
||||
{
|
||||
ValidateParams(options.Url, options.CancellationToken);
|
||||
|
@ -110,80 +177,97 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
|
||||
var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression);
|
||||
|
||||
if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < 30)
|
||||
if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < TimeoutSeconds)
|
||||
{
|
||||
throw new HttpException(string.Format("Cancelling connection to {0} due to a previous timeout.", options.Url)) { IsTimedOut = true };
|
||||
}
|
||||
|
||||
using (var message = GetHttpRequestMessage(options))
|
||||
var httpWebRequest = GetRequest(options, "GET", options.EnableHttpCompression);
|
||||
|
||||
if (options.ResourcePool != null)
|
||||
{
|
||||
await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < TimeoutSeconds)
|
||||
{
|
||||
if (options.ResourcePool != null)
|
||||
{
|
||||
await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false);
|
||||
options.ResourcePool.Release();
|
||||
}
|
||||
|
||||
if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < 30)
|
||||
throw new HttpException(string.Format("Connection to {0} timed out", options.Url)) { IsTimedOut = true };
|
||||
}
|
||||
|
||||
_logger.Info("HttpClientManager.GET url: {0}", options.Url);
|
||||
|
||||
try
|
||||
{
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using (var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false))
|
||||
{
|
||||
if (options.ResourcePool != null)
|
||||
{
|
||||
options.ResourcePool.Release();
|
||||
}
|
||||
var httpResponse = (HttpWebResponse)response;
|
||||
|
||||
throw new HttpException(string.Format("Connection to {0} timed out", options.Url)) { IsTimedOut = true };
|
||||
}
|
||||
|
||||
_logger.Info("HttpClientManager.Get url: {0}", options.Url);
|
||||
|
||||
try
|
||||
{
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var response = await client.HttpClient.SendAsync(message, HttpCompletionOption.ResponseContentRead, options.CancellationToken).ConfigureAwait(false);
|
||||
|
||||
EnsureSuccessStatusCode(response);
|
||||
EnsureSuccessStatusCode(httpResponse);
|
||||
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
return new HttpResponseInfo
|
||||
using (var stream = httpResponse.GetResponseStream())
|
||||
{
|
||||
Content = await response.Content.ReadAsStreamAsync().ConfigureAwait(false),
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
StatusCode = response.StatusCode,
|
||||
await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
|
||||
|
||||
ContentType = response.Content.Headers.ContentType.MediaType
|
||||
};
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
var exception = GetCancellationException(options.Url, options.CancellationToken, ex);
|
||||
memoryStream.Position = 0;
|
||||
|
||||
var httpException = exception as HttpException;
|
||||
return new HttpResponseInfo
|
||||
{
|
||||
Content = memoryStream,
|
||||
|
||||
if (httpException != null && httpException.IsTimedOut)
|
||||
{
|
||||
client.LastTimeout = DateTime.UtcNow;
|
||||
StatusCode = httpResponse.StatusCode,
|
||||
|
||||
ContentType = httpResponse.ContentType
|
||||
};
|
||||
}
|
||||
|
||||
throw exception;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting response from " + options.Url, ex);
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
var exception = GetCancellationException(options.Url, options.CancellationToken, ex);
|
||||
|
||||
throw new HttpException(ex.Message, ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting response from " + options.Url, ex);
|
||||
var httpException = exception as HttpException;
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
if (httpException != null && httpException.IsTimedOut)
|
||||
{
|
||||
if (options.ResourcePool != null)
|
||||
{
|
||||
options.ResourcePool.Release();
|
||||
}
|
||||
client.LastTimeout = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
throw exception;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting response from " + options.Url, ex);
|
||||
|
||||
throw new HttpException(ex.Message, ex);
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting response from " + options.Url, ex);
|
||||
|
||||
throw new HttpException(ex.Message, ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting response from " + options.Url, ex);
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (options.ResourcePool != null)
|
||||
{
|
||||
options.ResourcePool.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -197,81 +281,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
/// <exception cref="MediaBrowser.Model.Net.HttpException"></exception>
|
||||
public async Task<Stream> Get(HttpRequestOptions options)
|
||||
{
|
||||
ValidateParams(options.Url, options.CancellationToken);
|
||||
var response = await GetResponse(options).ConfigureAwait(false);
|
||||
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression);
|
||||
|
||||
if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < 30)
|
||||
{
|
||||
throw new HttpException(string.Format("Cancelling connection to {0} due to a previous timeout.", options.Url)) { IsTimedOut = true };
|
||||
}
|
||||
|
||||
using (var message = GetHttpRequestMessage(options))
|
||||
{
|
||||
if (options.ResourcePool != null)
|
||||
{
|
||||
await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < 30)
|
||||
{
|
||||
if (options.ResourcePool != null)
|
||||
{
|
||||
options.ResourcePool.Release();
|
||||
}
|
||||
|
||||
throw new HttpException(string.Format("Connection to {0} timed out", options.Url)) { IsTimedOut = true };
|
||||
}
|
||||
|
||||
_logger.Info("HttpClientManager.Get url: {0}", options.Url);
|
||||
|
||||
try
|
||||
{
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var response = await client.HttpClient.SendAsync(message, HttpCompletionOption.ResponseContentRead, options.CancellationToken).ConfigureAwait(false);
|
||||
|
||||
EnsureSuccessStatusCode(response);
|
||||
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
return await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
var exception = GetCancellationException(options.Url, options.CancellationToken, ex);
|
||||
|
||||
var httpException = exception as HttpException;
|
||||
|
||||
if (httpException != null && httpException.IsTimedOut)
|
||||
{
|
||||
client.LastTimeout = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
throw exception;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting response from " + options.Url, ex);
|
||||
|
||||
throw new HttpException(ex.Message, ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting response from " + options.Url, ex);
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (options.ResourcePool != null)
|
||||
{
|
||||
options.ResourcePool.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
return response.Content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -302,6 +314,96 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
return Get(url, null, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a POST request
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="postData">Params to add to the POST data.</param>
|
||||
/// <returns>stream on success, null on failure</returns>
|
||||
/// <exception cref="HttpException">
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">postData</exception>
|
||||
/// <exception cref="MediaBrowser.Model.Net.HttpException"></exception>
|
||||
public async Task<Stream> Post(HttpRequestOptions options, Dictionary<string, string> postData)
|
||||
{
|
||||
ValidateParams(options.Url, options.CancellationToken);
|
||||
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var httpWebRequest = GetRequest(options, "POST", options.EnableHttpCompression);
|
||||
|
||||
var strings = postData.Keys.Select(key => string.Format("{0}={1}", key, postData[key]));
|
||||
var postContent = string.Join("&", strings.ToArray());
|
||||
var bytes = Encoding.UTF8.GetBytes(postContent);
|
||||
|
||||
httpWebRequest.ContentType = "application/x-www-form-urlencoded";
|
||||
httpWebRequest.ContentLength = bytes.Length;
|
||||
httpWebRequest.GetRequestStream().Write(bytes, 0, bytes.Length);
|
||||
|
||||
if (options.ResourcePool != null)
|
||||
{
|
||||
await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
_logger.Info("HttpClientManager.POST url: {0}", options.Url);
|
||||
|
||||
try
|
||||
{
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using (var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false))
|
||||
{
|
||||
var httpResponse = (HttpWebResponse)response;
|
||||
|
||||
EnsureSuccessStatusCode(httpResponse);
|
||||
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using (var stream = httpResponse.GetResponseStream())
|
||||
{
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
|
||||
|
||||
memoryStream.Position = 0;
|
||||
|
||||
return memoryStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
var exception = GetCancellationException(options.Url, options.CancellationToken, ex);
|
||||
|
||||
throw exception;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting response from " + options.Url, ex);
|
||||
|
||||
throw new HttpException(ex.Message, ex);
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting response from " + options.Url, ex);
|
||||
|
||||
throw new HttpException(ex.Message, ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting response from " + options.Url, ex);
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (options.ResourcePool != null)
|
||||
{
|
||||
options.ResourcePool.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a POST request
|
||||
/// </summary>
|
||||
|
@ -310,57 +412,15 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
/// <param name="resourcePool">The resource pool.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>stream on success, null on failure</returns>
|
||||
/// <exception cref="System.ArgumentNullException">postData</exception>
|
||||
/// <exception cref="MediaBrowser.Model.Net.HttpException"></exception>
|
||||
public async Task<Stream> Post(string url, Dictionary<string, string> postData, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
|
||||
public Task<Stream> Post(string url, Dictionary<string, string> postData, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
|
||||
{
|
||||
ValidateParams(url, cancellationToken);
|
||||
|
||||
if (postData == null)
|
||||
return Post(new HttpRequestOptions
|
||||
{
|
||||
throw new ArgumentNullException("postData");
|
||||
}
|
||||
Url = url,
|
||||
ResourcePool = resourcePool,
|
||||
CancellationToken = cancellationToken
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var strings = postData.Keys.Select(key => string.Format("{0}={1}", key, postData[key]));
|
||||
var postContent = string.Join("&", strings.ToArray());
|
||||
var content = new StringContent(postContent, Encoding.UTF8, "application/x-www-form-urlencoded");
|
||||
|
||||
if (resourcePool != null)
|
||||
{
|
||||
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
_logger.Info("HttpClientManager.Post url: {0}", url);
|
||||
|
||||
try
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var msg = await GetHttpClient(GetHostFromUrl(url), true).HttpClient.PostAsync(url, content, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
EnsureSuccessStatusCode(msg);
|
||||
|
||||
return await msg.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
throw GetCancellationException(url, cancellationToken, ex);
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting response from " + url, ex);
|
||||
|
||||
throw new HttpException(ex.Message, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (resourcePool != null)
|
||||
{
|
||||
resourcePool.Release();
|
||||
}
|
||||
}
|
||||
}, postData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -391,6 +451,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var httpWebRequest = GetRequest(options, "GET", options.EnableHttpCompression);
|
||||
|
||||
if (options.ResourcePool != null)
|
||||
{
|
||||
await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false);
|
||||
|
@ -398,57 +460,68 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
|
||||
options.Progress.Report(0);
|
||||
|
||||
_logger.Info("HttpClientManager.GetTempFile url: {0}, temp file: {1}", options.Url, tempFile);
|
||||
_logger.Info("HttpClientManager.GetTempFileResponse url: {0}", options.Url);
|
||||
|
||||
try
|
||||
{
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using (var message = GetHttpRequestMessage(options))
|
||||
using (var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false))
|
||||
{
|
||||
using (var response = await GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression).HttpClient.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, options.CancellationToken).ConfigureAwait(false))
|
||||
var httpResponse = (HttpWebResponse)response;
|
||||
|
||||
EnsureSuccessStatusCode(httpResponse);
|
||||
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var contentLength = GetContentLength(httpResponse);
|
||||
|
||||
if (!contentLength.HasValue)
|
||||
{
|
||||
EnsureSuccessStatusCode(response);
|
||||
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var contentLength = GetContentLength(response);
|
||||
|
||||
if (!contentLength.HasValue)
|
||||
// We're not able to track progress
|
||||
using (var stream = httpResponse.GetResponseStream())
|
||||
{
|
||||
// We're not able to track progress
|
||||
using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
||||
using (var fs = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, true))
|
||||
{
|
||||
using (var fs = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, true))
|
||||
{
|
||||
await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), options.Progress.Report, contentLength.Value))
|
||||
{
|
||||
using (var fs = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, true))
|
||||
{
|
||||
await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
options.Progress.Report(100);
|
||||
|
||||
return new HttpResponseInfo
|
||||
{
|
||||
TempFilePath = tempFile,
|
||||
|
||||
StatusCode = response.StatusCode,
|
||||
|
||||
ContentType = response.Content.Headers.ContentType.MediaType
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var stream = ProgressStream.CreateReadProgressStream(httpResponse.GetResponseStream(), options.Progress.Report, contentLength.Value))
|
||||
{
|
||||
using (var fs = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, true))
|
||||
{
|
||||
await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
options.Progress.Report(100);
|
||||
|
||||
return new HttpResponseInfo
|
||||
{
|
||||
TempFilePath = tempFile,
|
||||
|
||||
StatusCode = httpResponse.StatusCode,
|
||||
|
||||
ContentType = httpResponse.ContentType
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
throw GetTempFileException(ex, options, tempFile);
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
throw GetTempFileException(ex, options, tempFile);
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
throw GetTempFileException(ex, options, tempFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw GetTempFileException(ex, options, tempFile);
|
||||
|
@ -462,63 +535,16 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the message.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>HttpResponseMessage.</returns>
|
||||
private HttpRequestMessage GetHttpRequestMessage(HttpRequestOptions options)
|
||||
private long? GetContentLength(HttpWebResponse response)
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, options.Url);
|
||||
var length = response.ContentLength;
|
||||
|
||||
foreach (var pair in options.RequestHeaders.ToList())
|
||||
{
|
||||
if (!message.Headers.TryAddWithoutValidation(pair.Key, pair.Value))
|
||||
{
|
||||
_logger.Error("Unable to add request header {0} with value {1}", pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the content.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>System.Nullable{System.Int64}.</returns>
|
||||
private long? GetContentLength(HttpResponseMessage response)
|
||||
{
|
||||
IEnumerable<string> lengthValues = null;
|
||||
|
||||
// Seeing some InvalidOperationException here under mono
|
||||
try
|
||||
{
|
||||
response.Headers.TryGetValues("content-length", out lengthValues);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
_logger.ErrorException("Error accessing response.Headers.TryGetValues Content-Length", ex);
|
||||
}
|
||||
|
||||
if (lengthValues == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
response.Content.Headers.TryGetValues("content-length", out lengthValues);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
_logger.ErrorException("Error accessing response.Content.Headers.TryGetValues Content-Length", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (lengthValues == null)
|
||||
if (length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return long.Parse(string.Join(string.Empty, lengthValues.ToArray()), UsCulture);
|
||||
return length;
|
||||
}
|
||||
|
||||
protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||
|
@ -545,16 +571,23 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
|
||||
_logger.ErrorException("Error getting response from " + options.Url, ex);
|
||||
|
||||
var httpRequestException = ex as HttpRequestException;
|
||||
|
||||
// Cleanup
|
||||
DeleteTempFile(tempFile);
|
||||
|
||||
var httpRequestException = ex as HttpRequestException;
|
||||
|
||||
if (httpRequestException != null)
|
||||
{
|
||||
return new HttpException(ex.Message, ex);
|
||||
}
|
||||
|
||||
var webException = ex as WebException;
|
||||
|
||||
if (webException != null)
|
||||
{
|
||||
return new HttpException(ex.Message, ex);
|
||||
}
|
||||
|
||||
return ex;
|
||||
}
|
||||
|
||||
|
@ -613,11 +646,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
{
|
||||
if (dispose)
|
||||
{
|
||||
foreach (var client in _httpClients.Values.ToList())
|
||||
{
|
||||
client.HttpClient.Dispose();
|
||||
}
|
||||
|
||||
_httpClients.Clear();
|
||||
}
|
||||
}
|
||||
|
@ -645,16 +673,14 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
return exception;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures the success status code.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <exception cref="MediaBrowser.Model.Net.HttpException"></exception>
|
||||
private void EnsureSuccessStatusCode(HttpResponseMessage response)
|
||||
private void EnsureSuccessStatusCode(HttpWebResponse response)
|
||||
{
|
||||
if (!response.IsSuccessStatusCode)
|
||||
var statusCode = response.StatusCode;
|
||||
var isSuccessful = statusCode >= HttpStatusCode.OK && statusCode <= (HttpStatusCode)299;
|
||||
|
||||
if (!isSuccessful)
|
||||
{
|
||||
throw new HttpException(response.ReasonPhrase) { StatusCode = response.StatusCode };
|
||||
throw new HttpException(response.StatusDescription) { StatusCode = response.StatusCode };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\NLog.2.1.0\lib\net45\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Text, Version=3.9.70.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\ServiceStack.Text.3.9.70\lib\net35\ServiceStack.Text.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SharpCompress">
|
||||
<HintPath>..\packages\sharpcompress.0.10.1.3\lib\net40\SharpCompress.dll</HintPath>
|
||||
</Reference>
|
||||
|
@ -55,9 +59,6 @@
|
|||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="ServiceStack.Text">
|
||||
<HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SharedVersion.cs">
|
||||
|
|
|
@ -29,7 +29,6 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
|
|||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DeleteCacheFileTask" /> class.
|
||||
/// </summary>
|
||||
/// <param name="appPaths">The app paths.</param>
|
||||
public DeleteCacheFileTask(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem)
|
||||
{
|
||||
ApplicationPaths = appPaths;
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace MediaBrowser.Common.Implementations.Serialization
|
|||
|
||||
using (Stream stream = File.OpenRead(file))
|
||||
{
|
||||
return ServiceStack.Text.JsonSerializer.DeserializeFromStream(type, stream);
|
||||
return DeserializeFromStream(stream, type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ namespace MediaBrowser.Common.Implementations.Serialization
|
|||
|
||||
using (Stream stream = File.OpenRead(file))
|
||||
{
|
||||
return ServiceStack.Text.JsonSerializer.DeserializeFromStream<T>(stream);
|
||||
return DeserializeFromStream<T>(stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,6 +169,8 @@ namespace MediaBrowser.Common.Implementations.Serialization
|
|||
ServiceStack.Text.JsConfig.DateHandler = ServiceStack.Text.JsonDateHandler.ISO8601;
|
||||
ServiceStack.Text.JsConfig.ExcludeTypeInfo = true;
|
||||
ServiceStack.Text.JsConfig.IncludeNullValues = false;
|
||||
ServiceStack.Text.JsConfig.AlwaysUseUtc = true;
|
||||
ServiceStack.Text.JsConfig.AssumeUtc = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -168,7 +168,7 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
{
|
||||
// Let dev users get results more often for testing purposes
|
||||
var cacheLength = _config.CommonConfiguration.SystemUpdateLevel == PackageVersionClass.Dev
|
||||
? TimeSpan.FromMinutes(15)
|
||||
? TimeSpan.FromMinutes(5)
|
||||
: TimeSpan.FromHours(12);
|
||||
|
||||
if ((DateTime.UtcNow - _lastPackageListResult.Item2) < cacheLength)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="NLog" version="2.1.0" targetFramework="net45" />
|
||||
<package id="ServiceStack.Text" version="3.9.62" targetFramework="net45" />
|
||||
<package id="ServiceStack.Text" version="3.9.70" targetFramework="net45" />
|
||||
<package id="sharpcompress" version="0.10.1.3" targetFramework="net45" />
|
||||
<package id="SimpleInjector" version="2.3.6" targetFramework="net45" />
|
||||
</packages>
|
|
@ -6,6 +6,12 @@ namespace MediaBrowser.Common.Configuration
|
|||
/// </summary>
|
||||
public interface IApplicationPaths
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the application path.
|
||||
/// </summary>
|
||||
/// <value>The application path.</value>
|
||||
string ApplicationPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the program data folder
|
||||
/// </summary>
|
||||
|
|
|
@ -35,18 +35,21 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="ServiceStack.Common, Version=3.9.70.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\ServiceStack.Common.3.9.70\lib\net35\ServiceStack.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Interfaces, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\ServiceStack.Common.3.9.70\lib\net35\ServiceStack.Interfaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Text, Version=3.9.70.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\ServiceStack.Text.3.9.70\lib\net35\ServiceStack.Text.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="ServiceStack.Common">
|
||||
<HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Interfaces">
|
||||
<HintPath>..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Interfaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Text">
|
||||
<HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SharedVersion.cs">
|
||||
|
|
|
@ -73,6 +73,11 @@ namespace MediaBrowser.Common.Net
|
|||
/// <exception cref="MediaBrowser.Model.Net.HttpException"></exception>
|
||||
Task<string> GetTempFile(HttpRequestOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the temporary file response.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>Task{HttpResponseInfo}.</returns>
|
||||
Task<HttpResponseInfo> GetTempFileResponse(HttpRequestOptions options);
|
||||
}
|
||||
}
|
|
@ -42,4 +42,9 @@ namespace MediaBrowser.Common.ScheduledTasks
|
|||
/// <returns>IEnumerable{BaseTaskTrigger}.</returns>
|
||||
IEnumerable<ITaskTrigger> GetDefaultTriggers();
|
||||
}
|
||||
|
||||
public interface IConfigurableScheduledTask
|
||||
{
|
||||
bool IsHidden { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,15 @@ namespace MediaBrowser.Common.ScheduledTasks
|
|||
/// <returns>TaskInfo.</returns>
|
||||
public static TaskInfo GetTaskInfo(IScheduledTaskWorker task)
|
||||
{
|
||||
var isHidden = false;
|
||||
|
||||
var configurableTask = task.ScheduledTask as IConfigurableScheduledTask;
|
||||
|
||||
if (configurableTask != null)
|
||||
{
|
||||
isHidden = configurableTask.IsHidden;
|
||||
}
|
||||
|
||||
return new TaskInfo
|
||||
{
|
||||
Name = task.Name,
|
||||
|
@ -25,7 +34,8 @@ namespace MediaBrowser.Common.ScheduledTasks
|
|||
LastExecutionResult = task.LastExecutionResult,
|
||||
Triggers = task.Triggers.Select(GetTriggerInfo).ToList(),
|
||||
Description = task.Description,
|
||||
Category = task.Category
|
||||
Category = task.Category,
|
||||
IsHidden = isHidden
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="ServiceStack.Common" version="3.9.62" targetFramework="net45" />
|
||||
<package id="ServiceStack.Text" version="3.9.62" targetFramework="net45" />
|
||||
<package id="ServiceStack.Common" version="3.9.70" targetFramework="net45" />
|
||||
<package id="ServiceStack.Text" version="3.9.70" targetFramework="net45" />
|
||||
</packages>
|
|
@ -1,86 +0,0 @@
|
|||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
/// <summary>
|
||||
/// Class Artist
|
||||
/// </summary>
|
||||
public class Artist : BaseItem, IItemByName, IHasMusicGenres
|
||||
{
|
||||
public Artist()
|
||||
{
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
}
|
||||
|
||||
public string LastFmImageUrl { get; set; }
|
||||
public string LastFmImageSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
{
|
||||
return GetUserDataKey(this);
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Finds the music artist.
|
||||
/// </summary>
|
||||
/// <param name="artist">The artist.</param>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
/// <returns>MusicArtist.</returns>
|
||||
public static MusicArtist FindMusicArtist(Artist artist, ILibraryManager libraryManager)
|
||||
{
|
||||
return FindMusicArtist(artist, libraryManager.RootFolder.RecursiveChildren.OfType<MusicArtist>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the music artist.
|
||||
/// </summary>
|
||||
/// <param name="artist">The artist.</param>
|
||||
/// <param name="allMusicArtists">All music artists.</param>
|
||||
/// <returns>MusicArtist.</returns>
|
||||
public static MusicArtist FindMusicArtist(Artist artist, IEnumerable<MusicArtist> allMusicArtists)
|
||||
{
|
||||
var musicBrainzId = artist.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
|
||||
return allMusicArtists.FirstOrDefault(i =>
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(musicBrainzId) && string.Equals(musicBrainzId, i.GetProviderId(MetadataProviders.Musicbrainz), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return string.Compare(i.Name, artist.Name, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols) == 0;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
public static string GetUserDataKey(BaseItem item)
|
||||
{
|
||||
var id = item.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
|
||||
if (!string.IsNullOrEmpty(id))
|
||||
{
|
||||
return "Artist-Musicbrainz-" + id;
|
||||
}
|
||||
|
||||
return "Artist-" + item.Name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,65 @@
|
|||
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
/// <summary>
|
||||
/// Class MusicArtist
|
||||
/// </summary>
|
||||
public class MusicArtist : Folder
|
||||
public class MusicArtist : Folder, IItemByName, IHasMusicGenres, IHasDualAccess
|
||||
{
|
||||
[IgnoreDataMember]
|
||||
public List<ItemByNameCounts> UserItemCountList { get; set; }
|
||||
|
||||
public bool IsAccessedByName { get; set; }
|
||||
|
||||
public override bool IsFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return !IsAccessedByName;
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<BaseItem> ActualChildren
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsAccessedByName)
|
||||
{
|
||||
return new List<BaseItem>();
|
||||
}
|
||||
|
||||
return base.ActualChildren;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool? recursive = null, bool forceRefreshMetadata = false)
|
||||
{
|
||||
if (IsAccessedByName)
|
||||
{
|
||||
// Should never get in here anyway
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
return base.ValidateChildrenInternal(progress, cancellationToken, recursive, forceRefreshMetadata);
|
||||
}
|
||||
|
||||
public override string GetClientTypeName()
|
||||
{
|
||||
if (IsAccessedByName)
|
||||
{
|
||||
//return "Artist";
|
||||
}
|
||||
|
||||
return base.GetClientTypeName();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the last fm image URL.
|
||||
/// </summary>
|
||||
|
@ -13,13 +67,35 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
public string LastFmImageUrl { get; set; }
|
||||
public string LastFmImageSize { get; set; }
|
||||
|
||||
public MusicArtist()
|
||||
{
|
||||
UserItemCountList = new List<ItemByNameCounts>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
{
|
||||
return Artist.GetUserDataKey(this);
|
||||
return GetUserDataKey(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
public static string GetUserDataKey(BaseItem item)
|
||||
{
|
||||
var id = item.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
|
||||
if (!string.IsNullOrEmpty(id))
|
||||
{
|
||||
return "Artist-Musicbrainz-" + id;
|
||||
}
|
||||
|
||||
return "Artist-" + item.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
{
|
||||
public MusicGenre()
|
||||
{
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
UserItemCountList = new List<ItemByNameCounts>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -25,6 +25,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
public List<ItemByNameCounts> UserItemCountList { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Localization;
|
||||
|
@ -38,10 +37,8 @@ namespace MediaBrowser.Controller.Entities
|
|||
Tags = new List<string>();
|
||||
ThemeSongIds = new List<Guid>();
|
||||
ThemeVideoIds = new List<Guid>();
|
||||
LocalTrailerIds = new List<Guid>();
|
||||
LockedFields = new List<MetadataFields>();
|
||||
Taglines = new List<string>();
|
||||
RemoteTrailers = new List<MediaUrl>();
|
||||
ImageSources = new List<ImageSourceInfo>();
|
||||
}
|
||||
|
||||
|
@ -87,30 +84,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <value>The id.</value>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the budget.
|
||||
/// </summary>
|
||||
/// <value>The budget.</value>
|
||||
public double? Budget { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the taglines.
|
||||
/// </summary>
|
||||
/// <value>The taglines.</value>
|
||||
public List<string> Taglines { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the revenue.
|
||||
/// </summary>
|
||||
/// <value>The revenue.</value>
|
||||
public double? Revenue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the trailer URL.
|
||||
/// </summary>
|
||||
/// <value>The trailer URL.</value>
|
||||
public List<MediaUrl> RemoteTrailers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Return the id that should be used to key display prefs for this item.
|
||||
/// Default is based on the type for everything except actual generic folders.
|
||||
|
@ -139,6 +118,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Gets or sets the type of the location.
|
||||
/// </summary>
|
||||
/// <value>The type of the location.</value>
|
||||
[IgnoreDataMember]
|
||||
public virtual LocationType LocationType
|
||||
{
|
||||
get
|
||||
|
@ -483,6 +463,22 @@ namespace MediaBrowser.Controller.Entities
|
|||
[IgnoreDataMember]
|
||||
public Folder Parent { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<Folder> Parents
|
||||
{
|
||||
get
|
||||
{
|
||||
var parent = Parent;
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
yield return parent;
|
||||
|
||||
parent = parent.Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When the item first debuted. For movies this could be premiere date, episodes would be first aired
|
||||
/// </summary>
|
||||
|
@ -630,11 +626,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <value>The original run time ticks.</value>
|
||||
public long? OriginalRunTimeTicks { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the aspect ratio.
|
||||
/// </summary>
|
||||
/// <value>The aspect ratio.</value>
|
||||
public string AspectRatio { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the production year.
|
||||
/// </summary>
|
||||
/// <value>The production year.</value>
|
||||
|
@ -655,7 +646,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
public List<Guid> ThemeSongIds { get; set; }
|
||||
public List<Guid> ThemeVideoIds { get; set; }
|
||||
public List<Guid> LocalTrailerIds { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public virtual string OfficialRatingForComparison
|
||||
|
@ -898,7 +888,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
themeVideosChanged = await RefreshThemeVideos(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
|
||||
|
||||
localTrailersChanged = await RefreshLocalTrailers(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
|
||||
var hasTrailers = this as IHasTrailers;
|
||||
if (hasTrailers != null)
|
||||
{
|
||||
localTrailersChanged = await RefreshLocalTrailers(hasTrailers, cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
@ -918,18 +912,18 @@ namespace MediaBrowser.Controller.Entities
|
|||
return changed;
|
||||
}
|
||||
|
||||
private async Task<bool> RefreshLocalTrailers(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true)
|
||||
private async Task<bool> RefreshLocalTrailers(IHasTrailers item, CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true)
|
||||
{
|
||||
var newItems = LoadLocalTrailers().ToList();
|
||||
var newItemIds = newItems.Select(i => i.Id).ToList();
|
||||
|
||||
var itemsChanged = !LocalTrailerIds.SequenceEqual(newItemIds);
|
||||
var itemsChanged = !item.LocalTrailerIds.SequenceEqual(newItemIds);
|
||||
|
||||
var tasks = newItems.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders, resetResolveArgs: false));
|
||||
|
||||
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
LocalTrailerIds = newItemIds;
|
||||
item.LocalTrailerIds = newItemIds;
|
||||
|
||||
return itemsChanged || results.Contains(true);
|
||||
}
|
||||
|
@ -1134,6 +1128,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
return changed;
|
||||
}
|
||||
|
||||
public virtual string GetClientTypeName()
|
||||
{
|
||||
return GetType().Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the item is considered new based on user settings
|
||||
/// </summary>
|
||||
|
@ -1187,6 +1186,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
if (existing != null)
|
||||
{
|
||||
existing.Type = PersonType.GuestStar;
|
||||
existing.SortOrder = person.SortOrder ?? existing.SortOrder;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1203,23 +1203,35 @@ namespace MediaBrowser.Controller.Entities
|
|||
else
|
||||
{
|
||||
// Was there, if no role and we have one - fill it in
|
||||
if (string.IsNullOrWhiteSpace(existing.Role) && !string.IsNullOrWhiteSpace(person.Role)) existing.Role = person.Role;
|
||||
if (string.IsNullOrWhiteSpace(existing.Role) && !string.IsNullOrWhiteSpace(person.Role))
|
||||
{
|
||||
existing.Role = person.Role;
|
||||
}
|
||||
|
||||
existing.SortOrder = person.SortOrder ?? existing.SortOrder;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var existing = People.FirstOrDefault(p =>
|
||||
string.Equals(p.Name, person.Name, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(p.Type, person.Type, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
// Check for dupes based on the combination of Name and Type
|
||||
if (!People.Any(p => string.Equals(p.Name, person.Name, StringComparison.OrdinalIgnoreCase) && string.Equals(p.Type, person.Type, StringComparison.OrdinalIgnoreCase)))
|
||||
if (existing == null)
|
||||
{
|
||||
People.Add(person);
|
||||
}
|
||||
else
|
||||
{
|
||||
existing.SortOrder = person.SortOrder ?? existing.SortOrder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the tagline.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="tagline">The tagline.</param>
|
||||
/// <exception cref="System.ArgumentNullException">tagline</exception>
|
||||
public void AddTagline(string tagline)
|
||||
|
@ -1737,5 +1749,14 @@ namespace MediaBrowser.Controller.Entities
|
|||
// See if we can avoid a file system lookup by looking for the file in ResolveArgs
|
||||
return metaFileEntry == null ? FileSystem.GetLastWriteTimeUtc(imagePath) : FileSystem.GetLastWriteTimeUtc(metaFileEntry);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file system path to delete when the item is to be deleted
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual IEnumerable<string> GetDeletePaths()
|
||||
{
|
||||
return new[] { Path };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <param name="url">The URL.</param>
|
||||
/// <param name="isDirectLink">if set to <c>true</c> [is direct link].</param>
|
||||
/// <exception cref="System.ArgumentNullException">url</exception>
|
||||
public static void AddTrailerUrl(this BaseItem item, string url, bool isDirectLink)
|
||||
public static void AddTrailerUrl(this IHasTrailers item, string url, bool isDirectLink)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
|
|
|
@ -90,7 +90,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
item.Id = item.Path.GetMBId(item.GetType());
|
||||
}
|
||||
|
||||
if (_children.Any(i => i.Id == item.Id))
|
||||
if (ActualChildren.Any(i => i.Id == item.Id))
|
||||
{
|
||||
throw new ArgumentException(string.Format("A child with the Id {0} already exists.", item.Id));
|
||||
}
|
||||
|
@ -108,14 +108,14 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
await LibraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await ItemRepository.SaveChildren(Id, _children.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
|
||||
await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected void AddChildrenInternal(IEnumerable<BaseItem> children)
|
||||
{
|
||||
lock (_childrenSyncLock)
|
||||
{
|
||||
var newChildren = _children.ToList();
|
||||
var newChildren = ActualChildren.ToList();
|
||||
newChildren.AddRange(children);
|
||||
_children = newChildren;
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
lock (_childrenSyncLock)
|
||||
{
|
||||
var newChildren = _children.ToList();
|
||||
var newChildren = ActualChildren.ToList();
|
||||
newChildren.Add(child);
|
||||
_children = newChildren;
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
lock (_childrenSyncLock)
|
||||
{
|
||||
_children = _children.Except(children).ToList();
|
||||
_children = ActualChildren.Except(children).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -519,7 +519,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <summary>
|
||||
/// The children
|
||||
/// </summary>
|
||||
private IReadOnlyList<BaseItem> _children = new List<BaseItem>();
|
||||
private IReadOnlyList<BaseItem> _children;
|
||||
/// <summary>
|
||||
/// The _children sync lock
|
||||
/// </summary>
|
||||
|
@ -532,15 +532,10 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
get
|
||||
{
|
||||
return _children;
|
||||
return _children ?? (_children = LoadChildrenInternal());
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadSavedChildren()
|
||||
{
|
||||
_children = LoadChildrenInternal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// thread-safe access to the actual children of this folder - without regard to user
|
||||
/// </summary>
|
||||
|
@ -758,7 +753,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
AddChildrenInternal(newItems);
|
||||
|
||||
await ItemRepository.SaveChildren(Id, _children.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
|
||||
await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
//force the indexes to rebuild next time
|
||||
if (IndexCache != null)
|
||||
|
@ -1007,8 +1002,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
return result;
|
||||
}
|
||||
|
||||
var initialCount = _children.Count;
|
||||
var list = new List<BaseItem>(initialCount);
|
||||
var list = new List<BaseItem>();
|
||||
|
||||
AddChildrenToList(user, includeLinkedChildren, list, false, null);
|
||||
|
||||
|
@ -1038,16 +1032,13 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
if (recursive)
|
||||
if (recursive && child.IsFolder)
|
||||
{
|
||||
var folder = child as Folder;
|
||||
var folder = (Folder)child;
|
||||
|
||||
if (folder != null)
|
||||
if (folder.AddChildrenToList(user, includeLinkedChildren, list, true, filter))
|
||||
{
|
||||
if (folder.AddChildrenToList(user, includeLinkedChildren, list, true, filter))
|
||||
{
|
||||
hasLinkedChildren = true;
|
||||
}
|
||||
hasLinkedChildren = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1073,7 +1064,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
return hasLinkedChildren;
|
||||
}
|
||||
|
||||
private int _lastRecursiveCount;
|
||||
/// <summary>
|
||||
/// Gets allowed recursive children of an item
|
||||
/// </summary>
|
||||
|
@ -1101,13 +1091,10 @@ namespace MediaBrowser.Controller.Entities
|
|||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
var initialCount = _lastRecursiveCount == 0 ? _children.Count : _lastRecursiveCount;
|
||||
var list = new List<BaseItem>(initialCount);
|
||||
var list = new List<BaseItem>();
|
||||
|
||||
var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, true, filter);
|
||||
|
||||
_lastRecursiveCount = list.Count;
|
||||
|
||||
return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list;
|
||||
}
|
||||
|
||||
|
@ -1127,8 +1114,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
public IList<BaseItem> GetRecursiveChildren(Func<BaseItem, bool> filter)
|
||||
{
|
||||
var initialCount = _lastRecursiveCount == 0 ? _children.Count : _lastRecursiveCount;
|
||||
var list = new List<BaseItem>(initialCount);
|
||||
var list = new List<BaseItem>();
|
||||
|
||||
AddChildrenToList(list, true, filter);
|
||||
|
||||
|
@ -1150,14 +1136,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
list.Add(child);
|
||||
}
|
||||
|
||||
if (recursive)
|
||||
if (recursive && child.IsFolder)
|
||||
{
|
||||
var folder = child as Folder;
|
||||
var folder = (Folder)child;
|
||||
|
||||
if (folder != null)
|
||||
{
|
||||
folder.AddChildrenToList(list, true, filter);
|
||||
}
|
||||
folder.AddChildrenToList(list, true, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,16 +4,26 @@ using System.Collections.Generic;
|
|||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public class Game : BaseItem, IHasSoundtracks
|
||||
public class Game : BaseItem, IHasSoundtracks, IHasTrailers
|
||||
{
|
||||
public List<Guid> SoundtrackIds { get; set; }
|
||||
|
||||
|
||||
public Game()
|
||||
{
|
||||
MultiPartGameFiles = new List<string>();
|
||||
SoundtrackIds = new List<Guid>();
|
||||
RemoteTrailers = new List<MediaUrl>();
|
||||
LocalTrailerIds = new List<Guid>();
|
||||
}
|
||||
|
||||
public List<Guid> LocalTrailerIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the remote trailers.
|
||||
/// </summary>
|
||||
/// <value>The remote trailers.</value>
|
||||
public List<MediaUrl> RemoteTrailers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the media.
|
||||
/// </summary>
|
||||
|
@ -84,5 +94,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
return base.GetUserDataKey();
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDeletePaths()
|
||||
{
|
||||
if (!IsInMixedFolder)
|
||||
{
|
||||
return new[] { System.IO.Path.GetDirectoryName(Path) };
|
||||
}
|
||||
|
||||
return base.GetDeletePaths();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
public GameGenre()
|
||||
{
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
UserItemCountList = new List<ItemByNameCounts>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -22,6 +22,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
public List<ItemByNameCounts> UserItemCountList { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System.Runtime.Serialization;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
public Genre()
|
||||
{
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
UserItemCountList = new List<ItemByNameCounts>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -25,6 +25,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
public List<ItemByNameCounts> UserItemCountList { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
14
MediaBrowser.Controller/Entities/IHasAspectRatio.cs
Normal file
14
MediaBrowser.Controller/Entities/IHasAspectRatio.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface IHasAspectRatio
|
||||
/// </summary>
|
||||
public interface IHasAspectRatio
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the aspect ratio.
|
||||
/// </summary>
|
||||
/// <value>The aspect ratio.</value>
|
||||
string AspectRatio { get; set; }
|
||||
}
|
||||
}
|
18
MediaBrowser.Controller/Entities/IHasBudget.cs
Normal file
18
MediaBrowser.Controller/Entities/IHasBudget.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public interface IHasBudget
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the budget.
|
||||
/// </summary>
|
||||
/// <value>The budget.</value>
|
||||
double? Budget { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the revenue.
|
||||
/// </summary>
|
||||
/// <value>The revenue.</value>
|
||||
double? Revenue { get; set; }
|
||||
}
|
||||
}
|
21
MediaBrowser.Controller/Entities/IHasTrailers.cs
Normal file
21
MediaBrowser.Controller/Entities/IHasTrailers.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public interface IHasTrailers
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the remote trailers.
|
||||
/// </summary>
|
||||
/// <value>The remote trailers.</value>
|
||||
List<MediaUrl> RemoteTrailers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the local trailer ids.
|
||||
/// </summary>
|
||||
/// <value>The local trailer ids.</value>
|
||||
List<Guid> LocalTrailerIds { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -9,26 +10,37 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// </summary>
|
||||
public interface IItemByName
|
||||
{
|
||||
Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
List<ItemByNameCounts> UserItemCountList { get; set; }
|
||||
}
|
||||
|
||||
public static class IItemByNameExtensions
|
||||
public interface IHasDualAccess : IItemByName
|
||||
{
|
||||
public static ItemByNameCounts GetItemByNameCounts(this IItemByName item, User user)
|
||||
bool IsAccessedByName { get; }
|
||||
}
|
||||
|
||||
public static class ItemByNameExtensions
|
||||
{
|
||||
public static ItemByNameCounts GetItemByNameCounts(this IItemByName item, Guid userId)
|
||||
{
|
||||
if (user == null)
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
throw new ArgumentNullException("userId");
|
||||
}
|
||||
|
||||
ItemByNameCounts counts;
|
||||
return item.UserItemCountList.FirstOrDefault(i => i.UserId == userId);
|
||||
}
|
||||
|
||||
if (item.UserItemCounts.TryGetValue(user.Id, out counts))
|
||||
public static void SetItemByNameCounts(this IItemByName item, Guid userId, ItemByNameCounts counts)
|
||||
{
|
||||
var current = item.UserItemCountList.FirstOrDefault(i => i.UserId == userId);
|
||||
|
||||
if (current != null)
|
||||
{
|
||||
return counts;
|
||||
item.UserItemCountList.Remove(current);
|
||||
}
|
||||
|
||||
return null;
|
||||
counts.UserId = userId;
|
||||
item.UserItemCountList.Add(counts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
IndexName = indexName;
|
||||
Parent = parent;
|
||||
LoadSavedChildren();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,10 +1,26 @@
|
|||
|
||||
using System;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Movies
|
||||
{
|
||||
/// <summary>
|
||||
/// Class BoxSet
|
||||
/// </summary>
|
||||
public class BoxSet : Folder
|
||||
public class BoxSet : Folder, IHasTrailers
|
||||
{
|
||||
public BoxSet()
|
||||
{
|
||||
RemoteTrailers = new List<MediaUrl>();
|
||||
LocalTrailerIds = new List<Guid>();
|
||||
}
|
||||
|
||||
public List<Guid> LocalTrailerIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the remote trailers.
|
||||
/// </summary>
|
||||
/// <value>The remote trailers.</value>
|
||||
public List<MediaUrl> RemoteTrailers { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
/// <summary>
|
||||
/// Class Movie
|
||||
/// </summary>
|
||||
public class Movie : Video, IHasCriticRating, IHasSoundtracks
|
||||
public class Movie : Video, IHasCriticRating, IHasSoundtracks, IHasBudget, IHasTrailers
|
||||
{
|
||||
public List<Guid> SpecialFeatureIds { get; set; }
|
||||
|
||||
|
@ -21,8 +21,26 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
{
|
||||
SpecialFeatureIds = new List<Guid>();
|
||||
SoundtrackIds = new List<Guid>();
|
||||
RemoteTrailers = new List<MediaUrl>();
|
||||
LocalTrailerIds = new List<Guid>();
|
||||
}
|
||||
|
||||
public List<Guid> LocalTrailerIds { get; set; }
|
||||
|
||||
public List<MediaUrl> RemoteTrailers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the budget.
|
||||
/// </summary>
|
||||
/// <value>The budget.</value>
|
||||
public double? Budget { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the revenue.
|
||||
/// </summary>
|
||||
/// <value>The revenue.</value>
|
||||
public double? Revenue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the critic rating.
|
||||
/// </summary>
|
||||
|
|
|
@ -4,7 +4,7 @@ using System;
|
|||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public class MusicVideo : Video, IHasArtist, IHasMusicGenres
|
||||
public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasBudget
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the artist.
|
||||
|
@ -18,6 +18,18 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <value>The album.</value>
|
||||
public string Album { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the budget.
|
||||
/// </summary>
|
||||
/// <value>The budget.</value>
|
||||
public double? Budget { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the revenue.
|
||||
/// </summary>
|
||||
/// <value>The revenue.</value>
|
||||
public double? Revenue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified name has artist.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System.Runtime.Serialization;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -12,11 +12,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
public Person()
|
||||
{
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
UserItemCountList = new List<ItemByNameCounts>();
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
public List<ItemByNameCounts> UserItemCountList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
|
@ -49,6 +49,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <value>The type.</value>
|
||||
public string Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sort order - ascending
|
||||
/// </summary>
|
||||
/// <value>The sort order.</value>
|
||||
public int? SortOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String" /> that represents this instance.
|
||||
/// </summary>
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
public Studio()
|
||||
{
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
UserItemCountList = new List<ItemByNameCounts>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -25,6 +25,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
public List<ItemByNameCounts> UserItemCountList { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,33 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
get { return true; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public int? AiredSeasonNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
return AirsAfterSeasonNumber ?? AirsBeforeSeasonNumber ?? PhysicalSeasonNumber;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public int? PhysicalSeasonNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = ParentIndexNumber;
|
||||
|
||||
if (value.HasValue)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
var season = Parent as Season;
|
||||
|
||||
return season != null ? season.IndexNumber : null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We roll up into series
|
||||
/// </summary>
|
||||
|
@ -59,7 +86,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
{
|
||||
get
|
||||
{
|
||||
return Season;
|
||||
return FindParent<Season>();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,20 +178,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
get { return _series ?? (_series = FindParent<Series>()); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _season
|
||||
/// </summary>
|
||||
private Season _season;
|
||||
/// <summary>
|
||||
/// This Episode's Season Instance
|
||||
/// </summary>
|
||||
/// <value>The season.</value>
|
||||
[IgnoreDataMember]
|
||||
public Season Season
|
||||
{
|
||||
get { return _season ?? (_season = FindParent<Season>()); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is the ending episode number for double episodes.
|
||||
/// </summary>
|
||||
|
@ -221,5 +234,46 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
{
|
||||
get { return LocationType == Model.Entities.LocationType.Virtual && IsUnaired; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public Guid? SeasonId
|
||||
{
|
||||
get
|
||||
{
|
||||
// First see if the parent is a Season
|
||||
var season = Parent as Season;
|
||||
|
||||
if (season != null)
|
||||
{
|
||||
return season.Id;
|
||||
}
|
||||
|
||||
var seasonNumber = ParentIndexNumber;
|
||||
|
||||
// Parent is a Series
|
||||
if (seasonNumber.HasValue)
|
||||
{
|
||||
var series = Parent as Series;
|
||||
|
||||
if (series != null)
|
||||
{
|
||||
season = series.Children.OfType<Season>()
|
||||
.FirstOrDefault(i => i.IndexNumber.HasValue && i.IndexNumber.Value == seasonNumber.Value);
|
||||
|
||||
if (season != null)
|
||||
{
|
||||
return season.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDeletePaths()
|
||||
{
|
||||
return new[] { Path };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
using System.Linq;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Localization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.TV
|
||||
|
@ -94,6 +94,22 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
get { return _series ?? (_series = FindParent<Series>()); }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string SeriesPath
|
||||
{
|
||||
get
|
||||
{
|
||||
var series = Series;
|
||||
|
||||
if (series != null)
|
||||
{
|
||||
return series.Path;
|
||||
}
|
||||
|
||||
return System.IO.Path.GetDirectoryName(Path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Our rating comes from our series
|
||||
/// </summary>
|
||||
|
@ -149,16 +165,34 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name;
|
||||
}
|
||||
|
||||
private IEnumerable<Episode> GetEpisodes()
|
||||
{
|
||||
var series = Series;
|
||||
|
||||
if (series != null && series.ContainsEpisodesWithoutSeasonFolders)
|
||||
{
|
||||
var seasonNumber = IndexNumber;
|
||||
|
||||
if (seasonNumber.HasValue)
|
||||
{
|
||||
return series.RecursiveChildren.OfType<Episode>()
|
||||
.Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return Children.OfType<Episode>();
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public bool IsMissingSeason
|
||||
{
|
||||
get { return LocationType == Model.Entities.LocationType.Virtual && Children.OfType<Episode>().All(i => i.IsMissingEpisode); }
|
||||
get { return LocationType == Model.Entities.LocationType.Virtual && GetEpisodes().All(i => i.IsMissingEpisode); }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public bool IsUnaired
|
||||
{
|
||||
get { return Children.OfType<Episode>().All(i => i.IsUnaired); }
|
||||
get { return GetEpisodes().All(i => i.IsUnaired); }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
|
@ -170,7 +204,13 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
[IgnoreDataMember]
|
||||
public bool IsMissingOrVirtualUnaired
|
||||
{
|
||||
get { return LocationType == Model.Entities.LocationType.Virtual && Children.OfType<Episode>().All(i => i.IsVirtualUnaired || i.IsMissingEpisode); }
|
||||
get { return LocationType == Model.Entities.LocationType.Virtual && GetEpisodes().All(i => i.IsVirtualUnaired || i.IsMissingEpisode); }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public bool IsSpecialSeason
|
||||
{
|
||||
get { return (IndexNumber ?? -1) == 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ using MediaBrowser.Model.Entities;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.TV
|
||||
|
@ -11,7 +12,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
/// <summary>
|
||||
/// Class Series
|
||||
/// </summary>
|
||||
public class Series : Folder, IHasSoundtracks
|
||||
public class Series : Folder, IHasSoundtracks, IHasTrailers
|
||||
{
|
||||
public List<Guid> SpecialFeatureIds { get; set; }
|
||||
public List<Guid> SoundtrackIds { get; set; }
|
||||
|
@ -24,8 +25,14 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
|
||||
SpecialFeatureIds = new List<Guid>();
|
||||
SoundtrackIds = new List<Guid>();
|
||||
RemoteTrailers = new List<MediaUrl>();
|
||||
LocalTrailerIds = new List<Guid>();
|
||||
}
|
||||
|
||||
public List<Guid> LocalTrailerIds { get; set; }
|
||||
|
||||
public List<MediaUrl> RemoteTrailers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status.
|
||||
/// </summary>
|
||||
|
@ -94,5 +101,14 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
|
||||
return args;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public bool ContainsEpisodesWithoutSeasonFolders
|
||||
{
|
||||
get
|
||||
{
|
||||
return Children.OfType<Video>().Any();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <summary>
|
||||
/// Class Trailer
|
||||
/// </summary>
|
||||
public class Trailer : Video, IHasCriticRating, IHasSoundtracks
|
||||
public class Trailer : Video, IHasCriticRating, IHasSoundtracks, IHasBudget, IHasTrailers
|
||||
{
|
||||
public List<Guid> SoundtrackIds { get; set; }
|
||||
|
||||
|
@ -17,8 +17,25 @@ namespace MediaBrowser.Controller.Entities
|
|||
RemoteTrailers = new List<MediaUrl>();
|
||||
Taglines = new List<string>();
|
||||
SoundtrackIds = new List<Guid>();
|
||||
LocalTrailerIds = new List<Guid>();
|
||||
}
|
||||
|
||||
public List<Guid> LocalTrailerIds { get; set; }
|
||||
|
||||
public List<MediaUrl> RemoteTrailers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the budget.
|
||||
/// </summary>
|
||||
/// <value>The budget.</value>
|
||||
public double? Budget { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the revenue.
|
||||
/// </summary>
|
||||
/// <value>The revenue.</value>
|
||||
public double? Revenue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the critic rating.
|
||||
/// </summary>
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <summary>
|
||||
/// Class Video
|
||||
/// </summary>
|
||||
public class Video : BaseItem, IHasMediaStreams
|
||||
public class Video : BaseItem, IHasMediaStreams, IHasAspectRatio
|
||||
{
|
||||
public bool IsMultiPart { get; set; }
|
||||
|
||||
|
@ -65,6 +65,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
return GetPlayableStreamFiles(Path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aspect ratio.
|
||||
/// </summary>
|
||||
/// <value>The aspect ratio.</value>
|
||||
public string AspectRatio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should be overridden to return the proper folder where metadata lives
|
||||
/// </summary>
|
||||
|
@ -252,5 +258,17 @@ namespace MediaBrowser.Controller.Entities
|
|||
}).ToList();
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDeletePaths()
|
||||
{
|
||||
if (!IsInMixedFolder)
|
||||
{
|
||||
if (VideoType == VideoType.VideoFile || VideoType == VideoType.Iso)
|
||||
{
|
||||
return new[] { System.IO.Path.GetDirectoryName(Path) };
|
||||
}
|
||||
}
|
||||
|
||||
return base.GetDeletePaths();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,11 +12,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
public Year()
|
||||
{
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
UserItemCountList = new List<ItemByNameCounts>();
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
public List<ItemByNameCounts> UserItemCountList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
|
|
|
@ -60,7 +60,7 @@ namespace MediaBrowser.Controller.Library
|
|||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <returns>Task{Artist}.</returns>
|
||||
Artist GetArtist(string name);
|
||||
MusicArtist GetArtist(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Studio
|
||||
|
@ -302,5 +302,18 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <param name="updateType">Type of the update.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task SaveMetadata(BaseItem item, ItemUpdateType updateType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all artists.
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{System.String}.</returns>
|
||||
IEnumerable<string> GetAllArtists();
|
||||
|
||||
/// <summary>
|
||||
/// Gets all artists.
|
||||
/// </summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable{System.String}.</returns>
|
||||
IEnumerable<string> GetAllArtists(IEnumerable<BaseItem> items);
|
||||
}
|
||||
}
|
|
@ -257,7 +257,7 @@ namespace MediaBrowser.Controller.Library
|
|||
|
||||
if (match != null)
|
||||
{
|
||||
return ParseEpisodeNumber(match.Value);
|
||||
return ParseEpisodeNumber(match.Groups["epnumber"].Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
73
MediaBrowser.Controller/LiveTv/Channel.cs
Normal file
73
MediaBrowser.Controller/LiveTv/Channel.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class Channel : BaseItem, IItemByName
|
||||
{
|
||||
public Channel()
|
||||
{
|
||||
UserItemCountList = new List<ItemByNameCounts>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
{
|
||||
return "Channel-" + Name;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public List<ItemByNameCounts> UserItemCountList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number.
|
||||
/// </summary>
|
||||
/// <value>The number.</value>
|
||||
public string ChannelNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get or sets the Id.
|
||||
/// </summary>
|
||||
/// <value>The id of the channel.</value>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the service.
|
||||
/// </summary>
|
||||
/// <value>The name of the service.</value>
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the channel.
|
||||
/// </summary>
|
||||
/// <value>The type of the channel.</value>
|
||||
public ChannelType ChannelType { get; set; }
|
||||
|
||||
protected override string CreateSortName()
|
||||
{
|
||||
double number = 0;
|
||||
|
||||
if (!string.IsNullOrEmpty(ChannelNumber))
|
||||
{
|
||||
double.TryParse(ChannelNumber, out number);
|
||||
}
|
||||
|
||||
return number.ToString("000-") + (Name ?? string.Empty);
|
||||
}
|
||||
|
||||
public override string MediaType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChannelType == ChannelType.Radio ? Model.Entities.MediaType.Audio : Model.Entities.MediaType.Video;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,12 +25,6 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <value>The id of the channel.</value>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the service.
|
||||
/// </summary>
|
||||
/// <value>The name of the service.</value>
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the channel.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
|
@ -15,6 +17,27 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <value>The services.</value>
|
||||
IReadOnlyList<ILiveTvService> Services { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Schedules the recording.
|
||||
/// </summary>
|
||||
/// <param name="programId">The program identifier.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task ScheduleRecording(string programId);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the recording.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task DeleteRecording(string id);
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the timer.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task CancelTimer(string id);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the parts.
|
||||
/// </summary>
|
||||
|
@ -22,10 +45,65 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
void AddParts(IEnumerable<ILiveTvService> services);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel info dto.
|
||||
/// Gets the channels.
|
||||
/// </summary>
|
||||
/// <param name="info">The info.</param>
|
||||
/// <returns>ChannelInfoDto.</returns>
|
||||
ChannelInfoDto GetChannelInfoDto(ChannelInfo info);
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>IEnumerable{Channel}.</returns>
|
||||
QueryResult<ChannelInfoDto> GetChannels(ChannelQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the recording.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{RecordingInfoDto}.</returns>
|
||||
Task<RecordingInfoDto> GetRecording(string id, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the timer.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{TimerInfoDto}.</returns>
|
||||
Task<TimerInfoDto> GetTimer(string id, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the recordings.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>QueryResult{RecordingInfoDto}.</returns>
|
||||
Task<QueryResult<RecordingInfoDto>> GetRecordings(RecordingQuery query, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the timers.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{QueryResult{TimerInfoDto}}.</returns>
|
||||
Task<QueryResult<TimerInfoDto>> GetTimers(TimerQuery query, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <returns>Channel.</returns>
|
||||
Channel GetChannel(string id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <param name="userId">The user identifier.</param>
|
||||
/// <returns>Channel.</returns>
|
||||
ChannelInfoDto GetChannelInfoDto(string id, string userId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the programs.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>IEnumerable{ProgramInfo}.</returns>
|
||||
Task<QueryResult<ProgramInfoDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using MediaBrowser.Model.LiveTv;
|
||||
using MediaBrowser.Common.Net;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -24,19 +24,88 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
Task<IEnumerable<ChannelInfo>> GetChannelsAsync(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the recordings asynchronous.
|
||||
/// Cancels the timer asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="timerId">The timer identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{IEnumerable{RecordingInfo}}.</returns>
|
||||
Task<IEnumerable<RecordingInfo>> GetRecordingsAsync(RecordingQuery query, CancellationToken cancellationToken);
|
||||
/// <returns>Task.</returns>
|
||||
Task CancelTimerAsync(string timerId, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel guides.
|
||||
/// Deletes the recording asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="channelIdList">The channel identifier list.</param>
|
||||
/// <param name="recordingId">The recording identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{IEnumerable{ChannelGuide}}.</returns>
|
||||
Task<IEnumerable<ChannelGuide>> GetChannelGuidesAsync(IEnumerable<string> channelIdList, CancellationToken cancellationToken);
|
||||
/// <returns>Task.</returns>
|
||||
Task DeleteRecordingAsync(string recordingId, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the timer asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="info">The information.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the series timer asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="info">The information.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task CreateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the series timer asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="info">The information.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel image asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="channelId">The channel identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{Stream}.</returns>
|
||||
Task<ImageResponseInfo> GetChannelImageAsync(string channelId, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the program image asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="programId">The program identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{ImageResponseInfo}.</returns>
|
||||
Task<ImageResponseInfo> GetProgramImageAsync(string programId, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the recordings asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{IEnumerable{RecordingInfo}}.</returns>
|
||||
Task<IEnumerable<RecordingInfo>> GetRecordingsAsync(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the recordings asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{IEnumerable{RecordingInfo}}.</returns>
|
||||
Task<IEnumerable<TimerInfo>> GetTimersAsync(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the series timers asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{IEnumerable{SeriesTimerInfo}}.</returns>
|
||||
Task<IEnumerable<SeriesTimerInfo>> GetSeriesTimersAsync(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the programs asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="channelId">The channel identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{IEnumerable{ProgramInfo}}.</returns>
|
||||
Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
19
MediaBrowser.Controller/LiveTv/ImageResponseInfo.cs
Normal file
19
MediaBrowser.Controller/LiveTv/ImageResponseInfo.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System.IO;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class ImageResponseInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the stream.
|
||||
/// </summary>
|
||||
/// <value>The stream.</value>
|
||||
public Stream Stream { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the MIME.
|
||||
/// </summary>
|
||||
/// <value>The type of the MIME.</value>
|
||||
public string MimeType { get; set; }
|
||||
}
|
||||
}
|
98
MediaBrowser.Controller/LiveTv/ProgramInfo.cs
Normal file
98
MediaBrowser.Controller/LiveTv/ProgramInfo.cs
Normal file
|
@ -0,0 +1,98 @@
|
|||
using MediaBrowser.Model.LiveTv;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class ProgramInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Id of the program.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the channel identifier.
|
||||
/// </summary>
|
||||
/// <value>The channel identifier.</value>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the program
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the official rating.
|
||||
/// </summary>
|
||||
/// <value>The official rating.</value>
|
||||
public string OfficialRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of the progam.
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the program, in UTC.
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end date of the program, in UTC.
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aspect ratio.
|
||||
/// </summary>
|
||||
/// <value>The aspect ratio.</value>
|
||||
public string AspectRatio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Genre of the program.
|
||||
/// </summary>
|
||||
public List<string> Genres { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the quality.
|
||||
/// </summary>
|
||||
/// <value>The quality.</value>
|
||||
public ProgramVideoQuality Quality { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the original air date.
|
||||
/// </summary>
|
||||
/// <value>The original air date.</value>
|
||||
public DateTime? OriginalAirDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the audio.
|
||||
/// </summary>
|
||||
/// <value>The audio.</value>
|
||||
public ProgramAudio Audio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the community rating.
|
||||
/// </summary>
|
||||
/// <value>The community rating.</value>
|
||||
public float? CommunityRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is repeat.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value>
|
||||
public bool IsRepeat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the episode title.
|
||||
/// </summary>
|
||||
/// <value>The episode title.</value>
|
||||
public string EpisodeTitle { get; set; }
|
||||
|
||||
public ProgramInfo()
|
||||
{
|
||||
Genres = new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
102
MediaBrowser.Controller/LiveTv/RecordingInfo.cs
Normal file
102
MediaBrowser.Controller/LiveTv/RecordingInfo.cs
Normal file
|
@ -0,0 +1,102 @@
|
|||
using MediaBrowser.Model.LiveTv;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class RecordingInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Id of the recording.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ChannelId of the recording.
|
||||
/// </summary>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ChannelName of the recording.
|
||||
/// </summary>
|
||||
public string ChannelName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the channel.
|
||||
/// </summary>
|
||||
/// <value>The type of the channel.</value>
|
||||
public ChannelType ChannelType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the recording.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path.
|
||||
/// </summary>
|
||||
/// <value>The path.</value>
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of the recording.
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the program identifier.
|
||||
/// </summary>
|
||||
/// <value>The program identifier.</value>
|
||||
public string ProgramId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status.
|
||||
/// </summary>
|
||||
/// <value>The status.</value>
|
||||
public RecordingStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Genre of the program.
|
||||
/// </summary>
|
||||
public List<string> Genres { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is repeat.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value>
|
||||
public bool IsRepeat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the episode title.
|
||||
/// </summary>
|
||||
/// <value>The episode title.</value>
|
||||
public string EpisodeTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the official rating.
|
||||
/// </summary>
|
||||
/// <value>The official rating.</value>
|
||||
public string OfficialRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the community rating.
|
||||
/// </summary>
|
||||
/// <value>The community rating.</value>
|
||||
public float? CommunityRating { get; set; }
|
||||
|
||||
public RecordingInfo()
|
||||
{
|
||||
Genres = new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
85
MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs
Normal file
85
MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs
Normal file
|
@ -0,0 +1,85 @@
|
|||
using MediaBrowser.Model.LiveTv;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class SeriesTimerInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Id of the recording.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ChannelId of the recording.
|
||||
/// </summary>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ChannelName of the recording.
|
||||
/// </summary>
|
||||
public string ChannelName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the program identifier.
|
||||
/// </summary>
|
||||
/// <value>The program identifier.</value>
|
||||
public string ProgramId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the recording.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of the recording.
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pre padding seconds.
|
||||
/// </summary>
|
||||
/// <value>The pre padding seconds.</value>
|
||||
public int PrePaddingSeconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the post padding seconds.
|
||||
/// </summary>
|
||||
/// <value>The post padding seconds.</value>
|
||||
public int PostPaddingSeconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the recurrence.
|
||||
/// </summary>
|
||||
/// <value>The type of the recurrence.</value>
|
||||
public RecurrenceType RecurrenceType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the days.
|
||||
/// </summary>
|
||||
/// <value>The days.</value>
|
||||
public List<DayOfWeek> Days { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the priority.
|
||||
/// </summary>
|
||||
/// <value>The priority.</value>
|
||||
public int Priority { get; set; }
|
||||
|
||||
public SeriesTimerInfo()
|
||||
{
|
||||
Days = new List<DayOfWeek>();
|
||||
}
|
||||
}
|
||||
}
|
73
MediaBrowser.Controller/LiveTv/TimerInfo.cs
Normal file
73
MediaBrowser.Controller/LiveTv/TimerInfo.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
using MediaBrowser.Model.LiveTv;
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class TimerInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Id of the recording.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the series timer identifier.
|
||||
/// </summary>
|
||||
/// <value>The series timer identifier.</value>
|
||||
public string SeriesTimerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ChannelId of the recording.
|
||||
/// </summary>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ChannelName of the recording.
|
||||
/// </summary>
|
||||
public string ChannelName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the program identifier.
|
||||
/// </summary>
|
||||
/// <value>The program identifier.</value>
|
||||
public string ProgramId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the recording.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of the recording.
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status.
|
||||
/// </summary>
|
||||
/// <value>The status.</value>
|
||||
public RecordingStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pre padding seconds.
|
||||
/// </summary>
|
||||
/// <value>The pre padding seconds.</value>
|
||||
public int PrePaddingSeconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the post padding seconds.
|
||||
/// </summary>
|
||||
/// <value>The post padding seconds.</value>
|
||||
public int PostPaddingSeconds { get; set; }
|
||||
}
|
||||
}
|
|
@ -89,8 +89,11 @@
|
|||
<Compile Include="Entities\GameGenre.cs" />
|
||||
<Compile Include="Entities\GameSystem.cs" />
|
||||
<Compile Include="Entities\IByReferenceItem.cs" />
|
||||
<Compile Include="Entities\IHasAspectRatio.cs" />
|
||||
<Compile Include="Entities\IHasBudget.cs" />
|
||||
<Compile Include="Entities\IHasCriticRating.cs" />
|
||||
<Compile Include="Entities\IHasSoundtracks.cs" />
|
||||
<Compile Include="Entities\IHasTrailers.cs" />
|
||||
<Compile Include="Entities\IItemByName.cs" />
|
||||
<Compile Include="Entities\ILibraryItem.cs" />
|
||||
<Compile Include="Entities\ImageSourceInfo.cs" />
|
||||
|
@ -103,18 +106,24 @@
|
|||
<Compile Include="Library\ItemUpdateType.cs" />
|
||||
<Compile Include="Library\IUserDataManager.cs" />
|
||||
<Compile Include="Library\UserDataSaveEventArgs.cs" />
|
||||
<Compile Include="LiveTv\Channel.cs" />
|
||||
<Compile Include="LiveTv\ChannelInfo.cs" />
|
||||
<Compile Include="LiveTv\ILiveTvManager.cs" />
|
||||
<Compile Include="LiveTv\ILiveTvService.cs" />
|
||||
<Compile Include="LiveTv\ImageResponseInfo.cs" />
|
||||
<Compile Include="LiveTv\ProgramInfo.cs" />
|
||||
<Compile Include="LiveTv\RecordingInfo.cs" />
|
||||
<Compile Include="LiveTv\SeriesTimerInfo.cs" />
|
||||
<Compile Include="LiveTv\TimerInfo.cs" />
|
||||
<Compile Include="Localization\ILocalizationManager.cs" />
|
||||
<Compile Include="Notifications\INotificationsRepository.cs" />
|
||||
<Compile Include="Notifications\NotificationUpdateEventArgs.cs" />
|
||||
<Compile Include="Providers\IDynamicInfoProvider.cs" />
|
||||
<Compile Include="Providers\IImageProvider.cs" />
|
||||
<Compile Include="Providers\NameParser.cs" />
|
||||
<Compile Include="Session\ISessionManager.cs" />
|
||||
<Compile Include="Drawing\ImageExtensions.cs" />
|
||||
<Compile Include="Entities\AggregateFolder.cs" />
|
||||
<Compile Include="Entities\Audio\Artist.cs" />
|
||||
<Compile Include="Entities\Audio\Audio.cs" />
|
||||
<Compile Include="Entities\Audio\MusicAlbum.cs" />
|
||||
<Compile Include="Entities\Audio\MusicArtist.cs" />
|
||||
|
|
|
@ -69,6 +69,12 @@ namespace MediaBrowser.Controller.Providers
|
|||
item.People.Clear();
|
||||
item.Tags.Clear();
|
||||
|
||||
var hasTrailers = item as IHasTrailers;
|
||||
if (hasTrailers != null)
|
||||
{
|
||||
hasTrailers.RemoteTrailers.Clear();
|
||||
}
|
||||
|
||||
//Fetch(item, metadataFile, settings, Encoding.GetEncoding("ISO-8859-1"), cancellationToken);
|
||||
Fetch(item, metadataFile, settings, Encoding.UTF8, cancellationToken);
|
||||
}
|
||||
|
@ -161,10 +167,14 @@ namespace MediaBrowser.Controller.Providers
|
|||
case "Budget":
|
||||
{
|
||||
var text = reader.ReadElementContentAsString();
|
||||
double value;
|
||||
if (double.TryParse(text, NumberStyles.Any, _usCulture, out value))
|
||||
var hasBudget = item as IHasBudget;
|
||||
if (hasBudget != null)
|
||||
{
|
||||
item.Budget = value;
|
||||
double value;
|
||||
if (double.TryParse(text, NumberStyles.Any, _usCulture, out value))
|
||||
{
|
||||
hasBudget.Budget = value;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -173,10 +183,14 @@ namespace MediaBrowser.Controller.Providers
|
|||
case "Revenue":
|
||||
{
|
||||
var text = reader.ReadElementContentAsString();
|
||||
double value;
|
||||
if (double.TryParse(text, NumberStyles.Any, _usCulture, out value))
|
||||
var hasBudget = item as IHasBudget;
|
||||
if (hasBudget != null)
|
||||
{
|
||||
item.Revenue = value;
|
||||
double value;
|
||||
if (double.TryParse(text, NumberStyles.Any, _usCulture, out value))
|
||||
{
|
||||
hasBudget.Revenue = value;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -375,9 +389,10 @@ namespace MediaBrowser.Controller.Providers
|
|||
{
|
||||
var val = reader.ReadElementContentAsString();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(val))
|
||||
var hasAspectRatio = item as IHasAspectRatio;
|
||||
if (!string.IsNullOrWhiteSpace(val) && hasAspectRatio != null)
|
||||
{
|
||||
item.AspectRatio = val;
|
||||
hasAspectRatio.AspectRatio = val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -474,9 +489,26 @@ namespace MediaBrowser.Controller.Providers
|
|||
{
|
||||
var val = reader.ReadElementContentAsString();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(val))
|
||||
var hasTrailers = item as IHasTrailers;
|
||||
if (hasTrailers != null)
|
||||
{
|
||||
item.AddTrailerUrl(val, false);
|
||||
if (!string.IsNullOrWhiteSpace(val))
|
||||
{
|
||||
hasTrailers.AddTrailerUrl(val, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "Trailers":
|
||||
{
|
||||
using (var subtree = reader.ReadSubtree())
|
||||
{
|
||||
var hasTrailers = item as IHasTrailers;
|
||||
if (hasTrailers != null)
|
||||
{
|
||||
FetchDataFromTrailersNode(subtree, hasTrailers);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -921,6 +953,35 @@ namespace MediaBrowser.Controller.Providers
|
|||
}
|
||||
}
|
||||
|
||||
private void FetchDataFromTrailersNode(XmlReader reader, IHasTrailers item)
|
||||
{
|
||||
reader.MoveToContent();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
switch (reader.Name)
|
||||
{
|
||||
case "Trailer":
|
||||
{
|
||||
var val = reader.ReadElementContentAsString();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(val))
|
||||
{
|
||||
item.AddTrailerUrl(val, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
reader.Skip();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task FetchChaptersFromXmlNode(BaseItem item, XmlReader reader, IItemRepository repository, CancellationToken cancellationToken)
|
||||
{
|
||||
var runtime = item.RunTimeTicks ?? 0;
|
||||
|
@ -1071,9 +1132,10 @@ namespace MediaBrowser.Controller.Providers
|
|||
/// <returns>IEnumerable{PersonInfo}.</returns>
|
||||
private IEnumerable<PersonInfo> GetPersonsFromXmlNode(XmlReader reader)
|
||||
{
|
||||
var names = new List<string>();
|
||||
var name = string.Empty;
|
||||
var type = "Actor"; // If type is not specified assume actor
|
||||
var role = string.Empty;
|
||||
int? sortOrder = null;
|
||||
|
||||
reader.MoveToContent();
|
||||
|
||||
|
@ -1084,7 +1146,7 @@ namespace MediaBrowser.Controller.Providers
|
|||
switch (reader.Name)
|
||||
{
|
||||
case "Name":
|
||||
names.AddRange(SplitNames(reader.ReadElementContentAsString()));
|
||||
name = reader.ReadElementContentAsString() ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "Type":
|
||||
|
@ -1108,6 +1170,20 @@ namespace MediaBrowser.Controller.Providers
|
|||
}
|
||||
break;
|
||||
}
|
||||
case "SortOrder":
|
||||
{
|
||||
var val = reader.ReadElementContentAsString();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(val))
|
||||
{
|
||||
int intVal;
|
||||
if (int.TryParse(val, NumberStyles.Integer, _usCulture, out intVal))
|
||||
{
|
||||
sortOrder = intVal;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
reader.Skip();
|
||||
|
@ -1116,7 +1192,15 @@ namespace MediaBrowser.Controller.Providers
|
|||
}
|
||||
}
|
||||
|
||||
return names.Select(n => new PersonInfo { Name = n.Trim(), Role = role, Type = type });
|
||||
var personInfo = new PersonInfo
|
||||
{
|
||||
Name = name.Trim(),
|
||||
Role = role,
|
||||
Type = type,
|
||||
SortOrder = sortOrder
|
||||
};
|
||||
|
||||
return new[] { personInfo };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
39
MediaBrowser.Controller/Providers/NameParser.cs
Normal file
39
MediaBrowser.Controller/Providers/NameParser.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
public static class NameParser
|
||||
{
|
||||
static readonly Regex[] NameMatches = new[] {
|
||||
new Regex(@"(?<name>.*)\((?<year>\d{4})\)"), // matches "My Movie (2001)" and gives us the name and the year
|
||||
new Regex(@"(?<name>.*)(\.(?<year>\d{4})(\.|$)).*$"),
|
||||
new Regex(@"(?<name>.*)") // last resort matches the whole string as the name
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Parses the name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="justName">Name of the just.</param>
|
||||
/// <param name="year">The year.</param>
|
||||
public static void ParseName(string name, out string justName, out int? year)
|
||||
{
|
||||
justName = null;
|
||||
year = null;
|
||||
foreach (var re in NameMatches)
|
||||
{
|
||||
Match m = re.Match(name);
|
||||
if (m.Success)
|
||||
{
|
||||
justName = m.Groups["name"].Value.Trim();
|
||||
string y = m.Groups["year"] != null ? m.Groups["year"].Value : null;
|
||||
int temp;
|
||||
year = Int32.TryParse(y, out temp) ? temp : (int?)null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -224,27 +224,36 @@
|
|||
<Compile Include="..\MediaBrowser.Model\IO\IZipClient.cs">
|
||||
<Link>IO\IZipClient.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ChannelGuide.cs">
|
||||
<Link>LiveTv\ChannelGuide.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ChannelInfoDto.cs">
|
||||
<Link>LiveTv\ChannelInfoDto.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ChannelQuery.cs">
|
||||
<Link>LiveTv\ChannelQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ChannelType.cs">
|
||||
<Link>LiveTv\ChannelType.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\LiveTvServiceInfo.cs">
|
||||
<Link>LiveTv\LiveTvServiceInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ProgramInfo.cs">
|
||||
<Link>LiveTv\ProgramInfo.cs</Link>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ProgramInfoDto.cs">
|
||||
<Link>LiveTv\ProgramInfoDto.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\RecordingInfo.cs">
|
||||
<Link>LiveTv\RecordingInfo.cs</Link>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ProgramQuery.cs">
|
||||
<Link>LiveTv\ProgramQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\RecordingInfoDto.cs">
|
||||
<Link>LiveTv\RecordingInfoDto.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\RecordingQuery.cs">
|
||||
<Link>LiveTv\RecordingQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\RecordingStatus.cs">
|
||||
<Link>LiveTv\RecordingStatus.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\TimerInfoDto.cs">
|
||||
<Link>LiveTv\TimerInfoDto.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Logging\ILogger.cs">
|
||||
<Link>Logging\ILogger.cs</Link>
|
||||
</Compile>
|
||||
|
@ -311,6 +320,9 @@
|
|||
<Compile Include="..\MediaBrowser.Model\Querying\ArtistsQuery.cs">
|
||||
<Link>Querying\ArtistsQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\EpisodeQuery.cs">
|
||||
<Link>Querying\EpisodeQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\ItemCountsQuery.cs">
|
||||
<Link>Querying\ItemCountsQuery.cs</Link>
|
||||
</Compile>
|
||||
|
@ -323,9 +335,6 @@
|
|||
<Compile Include="..\MediaBrowser.Model\Querying\ItemQuery.cs">
|
||||
<Link>Querying\ItemQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\ItemReviewsResult.cs">
|
||||
<Link>Querying\ItemReviewsResult.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\ItemsByNameQuery.cs">
|
||||
<Link>Querying\ItemsByNameQuery.cs</Link>
|
||||
</Compile>
|
||||
|
@ -341,6 +350,9 @@
|
|||
<Compile Include="..\MediaBrowser.Model\Querying\PersonsQuery.cs">
|
||||
<Link>Querying\PersonsQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\QueryResult.cs">
|
||||
<Link>Querying\QueryResult.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\SessionQuery.cs">
|
||||
<Link>Querying\SessionQuery.cs</Link>
|
||||
</Compile>
|
||||
|
|
|
@ -211,27 +211,36 @@
|
|||
<Compile Include="..\MediaBrowser.Model\IO\IZipClient.cs">
|
||||
<Link>IO\IZipClient.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ChannelGuide.cs">
|
||||
<Link>LiveTv\ChannelGuide.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ChannelInfoDto.cs">
|
||||
<Link>LiveTv\ChannelInfoDto.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ChannelQuery.cs">
|
||||
<Link>LiveTv\ChannelQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ChannelType.cs">
|
||||
<Link>LiveTv\ChannelType.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\LiveTvServiceInfo.cs">
|
||||
<Link>LiveTv\LiveTvServiceInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ProgramInfo.cs">
|
||||
<Link>LiveTv\ProgramInfo.cs</Link>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ProgramInfoDto.cs">
|
||||
<Link>LiveTv\ProgramInfoDto.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\RecordingInfo.cs">
|
||||
<Link>LiveTv\RecordingInfo.cs</Link>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\ProgramQuery.cs">
|
||||
<Link>LiveTv\ProgramQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\RecordingInfoDto.cs">
|
||||
<Link>LiveTv\RecordingInfoDto.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\RecordingQuery.cs">
|
||||
<Link>LiveTv\RecordingQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\RecordingStatus.cs">
|
||||
<Link>LiveTv\RecordingStatus.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\LiveTv\TimerInfoDto.cs">
|
||||
<Link>LiveTv\TimerInfoDto.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Logging\ILogger.cs">
|
||||
<Link>Logging\ILogger.cs</Link>
|
||||
</Compile>
|
||||
|
@ -298,6 +307,9 @@
|
|||
<Compile Include="..\MediaBrowser.Model\Querying\ArtistsQuery.cs">
|
||||
<Link>Querying\ArtistsQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\EpisodeQuery.cs">
|
||||
<Link>Querying\EpisodeQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\ItemCountsQuery.cs">
|
||||
<Link>Querying\ItemCountsQuery.cs</Link>
|
||||
</Compile>
|
||||
|
@ -310,9 +322,6 @@
|
|||
<Compile Include="..\MediaBrowser.Model\Querying\ItemQuery.cs">
|
||||
<Link>Querying\ItemQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\ItemReviewsResult.cs">
|
||||
<Link>Querying\ItemReviewsResult.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\ItemsByNameQuery.cs">
|
||||
<Link>Querying\ItemsByNameQuery.cs</Link>
|
||||
</Compile>
|
||||
|
@ -328,6 +337,9 @@
|
|||
<Compile Include="..\MediaBrowser.Model\Querying\PersonsQuery.cs">
|
||||
<Link>Querying\PersonsQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\QueryResult.cs">
|
||||
<Link>Querying\QueryResult.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\SessionQuery.cs">
|
||||
<Link>Querying\SessionQuery.cs</Link>
|
||||
</Compile>
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace MediaBrowser.Model.ApiClient
|
|||
/// <param name="startIndex">The start index.</param>
|
||||
/// <param name="limit">The limit.</param>
|
||||
/// <returns>Task{ItemReviewsResult}.</returns>
|
||||
Task<ItemReviewsResult> GetCriticReviews(string itemId, CancellationToken cancellationToken, int? startIndex = null, int? limit = null);
|
||||
Task<QueryResult<ItemReview>> GetCriticReviews(string itemId, CancellationToken cancellationToken, int? startIndex = null, int? limit = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the theme songs async.
|
||||
|
@ -225,6 +225,20 @@ namespace MediaBrowser.Model.ApiClient
|
|||
/// <returns>Task{ItemCounts}.</returns>
|
||||
Task<ItemCounts> GetItemCountsAsync(ItemCountsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the episodes asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>Task{ItemsResult}.</returns>
|
||||
Task<ItemsResult> GetEpisodesAsync(EpisodeQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the seasons asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>Task{ItemsResult}.</returns>
|
||||
Task<ItemsResult> GetSeasonsAsync(SeasonQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Queries for items
|
||||
/// </summary>
|
||||
|
|
|
@ -312,6 +312,12 @@ namespace MediaBrowser.Model.Dto
|
|||
/// <value>The series id.</value>
|
||||
public string SeriesId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the season identifier.
|
||||
/// </summary>
|
||||
/// <value>The season identifier.</value>
|
||||
public string SeasonId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the special feature count.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Model.Dto
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -6,6 +7,8 @@ namespace MediaBrowser.Model.Dto
|
|||
/// </summary>
|
||||
public class ItemByNameCounts
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the total count.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Model.LiveTv
|
||||
{
|
||||
public class ChannelGuide
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the service.
|
||||
/// </summary>
|
||||
/// <value>The name of the service.</value>
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ChannelId for the EPG.
|
||||
/// </summary>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of all the programs for a specific channel
|
||||
/// </summary>
|
||||
public List<ProgramInfo> Programs { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,4 +1,8 @@
|
|||
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Model.LiveTv
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -18,6 +22,12 @@ namespace MediaBrowser.Model.LiveTv
|
|||
/// <value>The identifier.</value>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the image tags.
|
||||
/// </summary>
|
||||
/// <value>The image tags.</value>
|
||||
public Dictionary<ImageType, Guid> ImageTags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number.
|
||||
/// </summary>
|
||||
|
@ -35,5 +45,28 @@ namespace MediaBrowser.Model.LiveTv
|
|||
/// </summary>
|
||||
/// <value>The type of the channel.</value>
|
||||
public ChannelType ChannelType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type.
|
||||
/// </summary>
|
||||
/// <value>The type.</value>
|
||||
public string Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the media.
|
||||
/// </summary>
|
||||
/// <value>The type of the media.</value>
|
||||
public string MediaType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user data.
|
||||
/// </summary>
|
||||
/// <value>The user data.</value>
|
||||
public UserItemDataDto UserData { get; set; }
|
||||
|
||||
public ChannelInfoDto()
|
||||
{
|
||||
ImageTags = new Dictionary<ImageType, Guid>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
27
MediaBrowser.Model/LiveTv/ChannelQuery.cs
Normal file
27
MediaBrowser.Model/LiveTv/ChannelQuery.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
|
||||
namespace MediaBrowser.Model.LiveTv
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ChannelQuery.
|
||||
/// </summary>
|
||||
public class ChannelQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the service.
|
||||
/// </summary>
|
||||
/// <value>The name of the service.</value>
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the channel.
|
||||
/// </summary>
|
||||
/// <value>The type of the channel.</value>
|
||||
public ChannelType? ChannelType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user identifier.
|
||||
/// </summary>
|
||||
/// <value>The user identifier.</value>
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace MediaBrowser.Model.LiveTv
|
||||
{
|
||||
public class ProgramInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Id of the program.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the program
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of the progam.
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the program, in UTC.
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end date of the program, in UTC.
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Genre of the program.
|
||||
/// </summary>
|
||||
public string Genre { get; set; }
|
||||
}
|
||||
}
|
120
MediaBrowser.Model/LiveTv/ProgramInfoDto.cs
Normal file
120
MediaBrowser.Model/LiveTv/ProgramInfoDto.cs
Normal file
|
@ -0,0 +1,120 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Model.LiveTv
|
||||
{
|
||||
public class ProgramInfoDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Id of the program.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the external identifier.
|
||||
/// </summary>
|
||||
/// <value>The external identifier.</value>
|
||||
public string ExternalId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the channel identifier.
|
||||
/// </summary>
|
||||
/// <value>The channel identifier.</value>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the community rating.
|
||||
/// </summary>
|
||||
/// <value>The community rating.</value>
|
||||
public float? CommunityRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aspect ratio.
|
||||
/// </summary>
|
||||
/// <value>The aspect ratio.</value>
|
||||
public string AspectRatio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the official rating.
|
||||
/// </summary>
|
||||
/// <value>The official rating.</value>
|
||||
public string OfficialRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the service.
|
||||
/// </summary>
|
||||
/// <value>The name of the service.</value>
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the program
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of the progam.
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the program, in UTC.
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end date of the program, in UTC.
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Genre of the program.
|
||||
/// </summary>
|
||||
public List<string> Genres { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the quality.
|
||||
/// </summary>
|
||||
/// <value>The quality.</value>
|
||||
public ProgramVideoQuality Quality { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the audio.
|
||||
/// </summary>
|
||||
/// <value>The audio.</value>
|
||||
public ProgramAudio Audio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the original air date.
|
||||
/// </summary>
|
||||
/// <value>The original air date.</value>
|
||||
public DateTime? OriginalAirDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is repeat.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value>
|
||||
public bool IsRepeat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the episode title.
|
||||
/// </summary>
|
||||
/// <value>The episode title.</value>
|
||||
public string EpisodeTitle { get; set; }
|
||||
|
||||
public ProgramInfoDto()
|
||||
{
|
||||
Genres = new List<string>();
|
||||
}
|
||||
}
|
||||
|
||||
public enum ProgramVideoQuality
|
||||
{
|
||||
StandardDefinition,
|
||||
HighDefinition
|
||||
}
|
||||
|
||||
public enum ProgramAudio
|
||||
{
|
||||
Stereo
|
||||
}
|
||||
}
|
31
MediaBrowser.Model/LiveTv/ProgramQuery.cs
Normal file
31
MediaBrowser.Model/LiveTv/ProgramQuery.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
namespace MediaBrowser.Model.LiveTv
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ProgramQuery.
|
||||
/// </summary>
|
||||
public class ProgramQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the service.
|
||||
/// </summary>
|
||||
/// <value>The name of the service.</value>
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the channel identifier.
|
||||
/// </summary>
|
||||
/// <value>The channel identifier.</value>
|
||||
public string[] ChannelIdList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user identifier.
|
||||
/// </summary>
|
||||
/// <value>The user identifier.</value>
|
||||
public string UserId { get; set; }
|
||||
|
||||
public ProgramQuery()
|
||||
{
|
||||
ChannelIdList = new string[] { };
|
||||
}
|
||||
}
|
||||
}
|
119
MediaBrowser.Model/LiveTv/RecordingInfoDto.cs
Normal file
119
MediaBrowser.Model/LiveTv/RecordingInfoDto.cs
Normal file
|
@ -0,0 +1,119 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Model.LiveTv
|
||||
{
|
||||
public class RecordingInfoDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Id of the recording.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the external identifier.
|
||||
/// </summary>
|
||||
/// <value>The external identifier.</value>
|
||||
public string ExternalId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the program identifier.
|
||||
/// </summary>
|
||||
/// <value>The program identifier.</value>
|
||||
public string ProgramId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ChannelId of the recording.
|
||||
/// </summary>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ChannelName of the recording.
|
||||
/// </summary>
|
||||
public string ChannelName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the recording.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path.
|
||||
/// </summary>
|
||||
/// <value>The path.</value>
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of the recording.
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status.
|
||||
/// </summary>
|
||||
/// <value>The status.</value>
|
||||
public RecordingStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Genre of the program.
|
||||
/// </summary>
|
||||
public List<string> Genres { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is repeat.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value>
|
||||
public bool IsRepeat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the episode title.
|
||||
/// </summary>
|
||||
/// <value>The episode title.</value>
|
||||
public string EpisodeTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the duration ms.
|
||||
/// </summary>
|
||||
/// <value>The duration ms.</value>
|
||||
public int DurationMs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the media.
|
||||
/// </summary>
|
||||
/// <value>The type of the media.</value>
|
||||
public string MediaType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the channel.
|
||||
/// </summary>
|
||||
/// <value>The type of the channel.</value>
|
||||
public ChannelType ChannelType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the official rating.
|
||||
/// </summary>
|
||||
/// <value>The official rating.</value>
|
||||
public string OfficialRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the community rating.
|
||||
/// </summary>
|
||||
/// <value>The community rating.</value>
|
||||
public float? CommunityRating { get; set; }
|
||||
|
||||
public RecordingInfoDto()
|
||||
{
|
||||
Genres = new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,9 +6,30 @@
|
|||
public class RecordingQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance has recorded.
|
||||
/// Gets or sets the channel identifier.
|
||||
/// </summary>
|
||||
/// <value><c>null</c> if [has recorded] contains no value, <c>true</c> if [has recorded]; otherwise, <c>false</c>.</value>
|
||||
public bool? HasRecorded { get; set; }
|
||||
/// <value>The channel identifier.</value>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the service.
|
||||
/// </summary>
|
||||
/// <value>The name of the service.</value>
|
||||
public string ServiceName { get; set; }
|
||||
}
|
||||
|
||||
public class TimerQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the channel identifier.
|
||||
/// </summary>
|
||||
/// <value>The channel identifier.</value>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the service.
|
||||
/// </summary>
|
||||
/// <value>The name of the service.</value>
|
||||
public string ServiceName { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
22
MediaBrowser.Model/LiveTv/RecordingStatus.cs
Normal file
22
MediaBrowser.Model/LiveTv/RecordingStatus.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
|
||||
namespace MediaBrowser.Model.LiveTv
|
||||
{
|
||||
public enum RecordingStatus
|
||||
{
|
||||
Pending,
|
||||
InProgress,
|
||||
Completed,
|
||||
CompletedWithError,
|
||||
Conflicted,
|
||||
Deleted
|
||||
}
|
||||
|
||||
public enum RecurrenceType
|
||||
{
|
||||
Manual,
|
||||
NewProgramEventsOneChannel,
|
||||
AllProgramEventsOneChannel,
|
||||
NewProgramEventsAllChannels,
|
||||
AllProgramEventsAllChannels
|
||||
}
|
||||
}
|
|
@ -1,15 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Model.LiveTv
|
||||
{
|
||||
public class RecordingInfo
|
||||
public class TimerInfoDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Id of the recording.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the external identifier.
|
||||
/// </summary>
|
||||
/// <value>The external identifier.</value>
|
||||
public string ExternalId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ChannelId of the recording.
|
||||
/// </summary>
|
||||
|
@ -20,6 +25,12 @@ namespace MediaBrowser.Model.LiveTv
|
|||
/// </summary>
|
||||
public string ChannelName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the program identifier.
|
||||
/// </summary>
|
||||
/// <value>The program identifier.</value>
|
||||
public string ProgramId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the recording.
|
||||
/// </summary>
|
||||
|
@ -41,38 +52,33 @@ namespace MediaBrowser.Model.LiveTv
|
|||
public DateTime EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Status of the recording.
|
||||
/// Gets or sets the status.
|
||||
/// </summary>
|
||||
public string Status { get; set; } //TODO: Enum for status?? Difference NextPvr,Argus,...
|
||||
/// <value>The status.</value>
|
||||
public RecordingStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Quality of the Recording.
|
||||
/// Gets or sets the series timer identifier.
|
||||
/// </summary>
|
||||
public string Quality { get; set; } // TODO: Enum for quality?? Difference NextPvr,Argus,...
|
||||
/// <value>The series timer identifier.</value>
|
||||
public string SeriesTimerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Recurring recording?
|
||||
/// Gets or sets the pre padding seconds.
|
||||
/// </summary>
|
||||
public bool Recurring { get; set; }
|
||||
/// <value>The pre padding seconds.</value>
|
||||
public int PrePaddingSeconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Parent recurring.
|
||||
/// Gets or sets the post padding seconds.
|
||||
/// </summary>
|
||||
public string RecurringParent { get; set; }
|
||||
/// <value>The post padding seconds.</value>
|
||||
public int PostPaddingSeconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Start date for the recurring, in UTC.
|
||||
/// Gets or sets the duration ms.
|
||||
/// </summary>
|
||||
public DateTime RecurrringStartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// End date for the recurring, in UTC
|
||||
/// </summary>
|
||||
public DateTime RecurringEndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When do we need the recording?
|
||||
/// </summary>
|
||||
public List<string> DayMask { get; set; }
|
||||
/// <value>The duration ms.</value>
|
||||
public int DurationMs { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,9 +60,13 @@
|
|||
<Compile Include="Dto\ItemCounts.cs" />
|
||||
<Compile Include="Dto\ItemIndex.cs" />
|
||||
<Compile Include="Entities\PackageReviewInfo.cs" />
|
||||
<Compile Include="LiveTv\ChannelGuide.cs" />
|
||||
<Compile Include="LiveTv\ProgramInfo.cs" />
|
||||
<Compile Include="LiveTv\ChannelInfoDto.cs" />
|
||||
<Compile Include="LiveTv\ChannelQuery.cs" />
|
||||
<Compile Include="LiveTv\ProgramInfoDto.cs" />
|
||||
<Compile Include="LiveTv\ProgramQuery.cs" />
|
||||
<Compile Include="LiveTv\RecordingQuery.cs" />
|
||||
<Compile Include="LiveTv\RecordingStatus.cs" />
|
||||
<Compile Include="LiveTv\TimerInfoDto.cs" />
|
||||
<Compile Include="Providers\ImageProviderInfo.cs" />
|
||||
<Compile Include="Providers\RemoteImageInfo.cs" />
|
||||
<Compile Include="Dto\StudioDto.cs" />
|
||||
|
@ -76,10 +80,9 @@
|
|||
<Compile Include="IO\IIsoManager.cs" />
|
||||
<Compile Include="IO\IIsoMount.cs" />
|
||||
<Compile Include="IO\IIsoMounter.cs" />
|
||||
<Compile Include="LiveTv\ChannelInfoDto.cs" />
|
||||
<Compile Include="LiveTv\ChannelType.cs" />
|
||||
<Compile Include="LiveTv\LiveTvServiceInfo.cs" />
|
||||
<Compile Include="LiveTv\RecordingInfo.cs" />
|
||||
<Compile Include="LiveTv\RecordingInfoDto.cs" />
|
||||
<Compile Include="Net\WebSocketMessage.cs" />
|
||||
<Compile Include="Net\WebSocketMessageType.cs" />
|
||||
<Compile Include="Net\WebSocketState.cs" />
|
||||
|
@ -90,11 +93,12 @@
|
|||
<Compile Include="Notifications\NotificationsSummary.cs" />
|
||||
<Compile Include="Providers\RemoteImageResult.cs" />
|
||||
<Compile Include="Querying\ArtistsQuery.cs" />
|
||||
<Compile Include="Querying\EpisodeQuery.cs" />
|
||||
<Compile Include="Querying\ItemCountsQuery.cs" />
|
||||
<Compile Include="Querying\ItemReviewsResult.cs" />
|
||||
<Compile Include="Querying\ItemsByNameQuery.cs" />
|
||||
<Compile Include="Entities\BaseItemInfo.cs" />
|
||||
<Compile Include="Querying\NextUpQuery.cs" />
|
||||
<Compile Include="Querying\QueryResult.cs" />
|
||||
<Compile Include="Querying\SessionQuery.cs" />
|
||||
<Compile Include="Querying\SimilarItemsQuery.cs" />
|
||||
<Compile Include="Querying\UserQuery.cs" />
|
||||
|
|
45
MediaBrowser.Model/Querying/EpisodeQuery.cs
Normal file
45
MediaBrowser.Model/Querying/EpisodeQuery.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
|
||||
namespace MediaBrowser.Model.Querying
|
||||
{
|
||||
public class EpisodeQuery
|
||||
{
|
||||
public string UserId { get; set; }
|
||||
|
||||
public string SeasonId { get; set; }
|
||||
|
||||
public string SeriesId { get; set; }
|
||||
|
||||
public bool? IsMissing { get; set; }
|
||||
|
||||
public bool? IsVirtualUnaired { get; set; }
|
||||
|
||||
public int? SeasonNumber { get; set; }
|
||||
|
||||
public ItemFields[] Fields { get; set; }
|
||||
|
||||
public EpisodeQuery()
|
||||
{
|
||||
Fields = new ItemFields[] { };
|
||||
}
|
||||
}
|
||||
|
||||
public class SeasonQuery
|
||||
{
|
||||
public string UserId { get; set; }
|
||||
|
||||
public string SeriesId { get; set; }
|
||||
|
||||
public bool? IsMissing { get; set; }
|
||||
|
||||
public bool? IsVirtualUnaired { get; set; }
|
||||
|
||||
public ItemFields[] Fields { get; set; }
|
||||
|
||||
public bool? IsSpecialSeason { get; set; }
|
||||
|
||||
public SeasonQuery()
|
||||
{
|
||||
Fields = new ItemFields[] { };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -266,6 +266,10 @@ namespace MediaBrowser.Model.Querying
|
|||
public double? MinCriticRating { get; set; }
|
||||
|
||||
public int? AiredDuringSeason { get; set; }
|
||||
|
||||
public DateTime? MinPremiereDate { get; set; }
|
||||
|
||||
public DateTime? MaxPremiereDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ItemQuery" /> class.
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace MediaBrowser.Model.Querying
|
|||
/// </summary>
|
||||
public static class ItemSortBy
|
||||
{
|
||||
public const string AiredEpisodeOrder = "AiredEpisodeOrder";
|
||||
/// <summary>
|
||||
/// The album
|
||||
/// </summary>
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
using MediaBrowser.Model.Entities;
|
||||
|
||||
|
||||
namespace MediaBrowser.Model.Querying
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ItemReviewsResult
|
||||
/// </summary>
|
||||
public class ItemReviewsResult
|
||||
public class QueryResult<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the item reviews.
|
||||
/// Gets or sets the items.
|
||||
/// </summary>
|
||||
/// <value>The item reviews.</value>
|
||||
public ItemReview[] ItemReviews { get; set; }
|
||||
/// <value>The items.</value>
|
||||
public T[] Items { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The total number of records available
|
||||
|
@ -22,9 +18,9 @@ namespace MediaBrowser.Model.Querying
|
|||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ItemsResult" /> class.
|
||||
/// </summary>
|
||||
public ItemReviewsResult()
|
||||
public QueryResult()
|
||||
{
|
||||
ItemReviews = new ItemReview[] { };
|
||||
Items = new T[] { };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -92,6 +92,18 @@ namespace MediaBrowser.Model.System
|
|||
/// <value>The program data path.</value>
|
||||
public string ProgramDataPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the items by name path.
|
||||
/// </summary>
|
||||
/// <value>The items by name path.</value>
|
||||
public string ItemsByNamePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the log path.
|
||||
/// </summary>
|
||||
/// <value>The log path.</value>
|
||||
public string LogPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the HTTP server port number.
|
||||
/// </summary>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue