mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-06 03:26:07 +02:00
Merge branch 'dev' into beta
This commit is contained in:
commit
c6580287f5
125 changed files with 2433 additions and 1941 deletions
|
@ -37,7 +37,7 @@
|
|||
</Reference>
|
||||
<Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\ImageMagickSharp.1.0.0.16\lib\net45\ImageMagickSharp.dll</HintPath>
|
||||
<HintPath>..\packages\ImageMagickSharp.1.0.0.17\lib\net45\ImageMagickSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Patterns.Logging">
|
||||
<HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
|
||||
|
|
|
@ -72,11 +72,16 @@ namespace Emby.Drawing.ImageMagick
|
|||
|
||||
private void LogVersion()
|
||||
{
|
||||
_logger.Info("ImageMagick version: " + Wand.VersionString);
|
||||
_logger.Info("ImageMagick version: " + GetVersion());
|
||||
TestWebp();
|
||||
Wand.SetMagickThreadCount(1);
|
||||
}
|
||||
|
||||
public static string GetVersion()
|
||||
{
|
||||
return Wand.VersionString;
|
||||
}
|
||||
|
||||
private bool _webpAvailable = true;
|
||||
private void TestWebp()
|
||||
{
|
||||
|
@ -148,7 +153,7 @@ namespace Emby.Drawing.ImageMagick
|
|||
DrawIndicator(originalImage, width, height, options);
|
||||
|
||||
originalImage.CurrentImage.CompressionQuality = quality;
|
||||
//originalImage.CurrentImage.StripImage();
|
||||
originalImage.CurrentImage.StripImage();
|
||||
|
||||
originalImage.SaveImage(outputPath);
|
||||
}
|
||||
|
@ -165,7 +170,7 @@ namespace Emby.Drawing.ImageMagick
|
|||
DrawIndicator(wand, width, height, options);
|
||||
|
||||
wand.CurrentImage.CompressionQuality = quality;
|
||||
//wand.CurrentImage.StripImage();
|
||||
wand.CurrentImage.StripImage();
|
||||
|
||||
wand.SaveImage(outputPath);
|
||||
}
|
||||
|
@ -175,16 +180,15 @@ namespace Emby.Drawing.ImageMagick
|
|||
}
|
||||
|
||||
private void ScaleImage(MagickWand wand, int width, int height)
|
||||
{
|
||||
if (_config.Configuration.EnableHighQualityImageScaling)
|
||||
{
|
||||
wand.CurrentImage.ResizeImage(width, height);
|
||||
//if (_config.Configuration.EnableHighQualityImageScaling)
|
||||
//{
|
||||
// wand.CurrentImage.ResizeImage(width, height);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// wand.CurrentImage.ScaleImage(width, height);
|
||||
//}
|
||||
}
|
||||
else
|
||||
{
|
||||
wand.CurrentImage.ScaleImage(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
|
||||
<package id="ImageMagickSharp" version="1.0.0.16" targetFramework="net45" />
|
||||
<package id="ImageMagickSharp" version="1.0.0.17" targetFramework="net45" />
|
||||
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
|
||||
</packages>
|
|
@ -198,50 +198,6 @@ namespace MediaBrowser.Api
|
|||
return libraryManager.GetPerson(DeSlugPersonName(name, libraryManager));
|
||||
}
|
||||
|
||||
protected IList<BaseItem> GetAllLibraryItems(string userId, IUserManager userManager, ILibraryManager libraryManager, string parentId, Func<BaseItem,bool> filter)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(parentId))
|
||||
{
|
||||
var folder = (Folder)libraryManager.GetItemById(new Guid(parentId));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(userId))
|
||||
{
|
||||
var user = userManager.GetUserById(userId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentException("User not found");
|
||||
}
|
||||
|
||||
return folder
|
||||
.GetRecursiveChildren(user, filter)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return folder
|
||||
.GetRecursiveChildren(filter);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(userId))
|
||||
{
|
||||
var user = userManager.GetUserById(userId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentException("User not found");
|
||||
}
|
||||
|
||||
return userManager
|
||||
.GetUserById(userId)
|
||||
.RootFolder
|
||||
.GetRecursiveChildren(user, filter)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return libraryManager
|
||||
.RootFolder
|
||||
.GetRecursiveChildren(filter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deslugs an artist name by finding the correct entry in the library
|
||||
/// </summary>
|
||||
|
|
|
@ -102,12 +102,16 @@ namespace MediaBrowser.Api
|
|||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetGameSystemSummaries request)
|
||||
{
|
||||
var gameSystems = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, i => i is GameSystem)
|
||||
var user = request.UserId == null ? null : _userManager.GetUserById(request.UserId);
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(GameSystem).Name }
|
||||
};
|
||||
var parentIds = new string[] { } ;
|
||||
var gameSystems = _libraryManager.GetItems(query, parentIds)
|
||||
.Cast<GameSystem>()
|
||||
.ToList();
|
||||
|
||||
var user = request.UserId == null ? null : _userManager.GetUserById(request.UserId);
|
||||
|
||||
var result = gameSystems
|
||||
.Select(i => GetSummary(i, user))
|
||||
.ToList();
|
||||
|
@ -119,8 +123,15 @@ namespace MediaBrowser.Api
|
|||
|
||||
public object Get(GetPlayerIndex request)
|
||||
{
|
||||
var games = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, i => i is Game)
|
||||
.Cast<Game>();
|
||||
var user = request.UserId == null ? null : _userManager.GetUserById(request.UserId);
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Game).Name }
|
||||
};
|
||||
var parentIds = new string[] { };
|
||||
var games = _libraryManager.GetItems(query, parentIds)
|
||||
.Cast<Game>()
|
||||
.ToList();
|
||||
|
||||
var lookup = games
|
||||
.ToLookup(i => i.PlayersSupported ?? -1)
|
||||
|
|
|
@ -416,7 +416,7 @@ namespace MediaBrowser.Api.Library
|
|||
|
||||
public object Get(GetMediaFolders request)
|
||||
{
|
||||
var items = _libraryManager.GetUserRootFolder().Children.OrderBy(i => i.SortName).ToList();
|
||||
var items = _libraryManager.GetUserRootFolder().Children.Concat(_libraryManager.RootFolder.VirtualChildren).OrderBy(i => i.SortName).ToList();
|
||||
|
||||
if (request.IsHidden.HasValue)
|
||||
{
|
||||
|
@ -610,7 +610,7 @@ namespace MediaBrowser.Api.Library
|
|||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
BaseItem parent = item.Parent;
|
||||
BaseItem parent = item.GetParent();
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
|
@ -621,7 +621,7 @@ namespace MediaBrowser.Api.Library
|
|||
|
||||
baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, dtoOptions, user));
|
||||
|
||||
parent = parent.Parent;
|
||||
parent = parent.GetParent();
|
||||
}
|
||||
|
||||
return baseItemDtos.ToList();
|
||||
|
@ -629,7 +629,7 @@ namespace MediaBrowser.Api.Library
|
|||
|
||||
private BaseItem TranslateParentItem(BaseItem item, User user)
|
||||
{
|
||||
if (item.Parent is AggregateFolder)
|
||||
if (item.GetParent() is AggregateFolder)
|
||||
{
|
||||
return user.RootFolder.GetChildren(user, true).FirstOrDefault(i => i.PhysicalLocations.Contains(item.Path));
|
||||
}
|
||||
|
@ -677,6 +677,50 @@ namespace MediaBrowser.Api.Library
|
|||
return ToOptimizedSerializedResultUsingCache(counts);
|
||||
}
|
||||
|
||||
private IList<BaseItem> GetAllLibraryItems(string userId, IUserManager userManager, ILibraryManager libraryManager, string parentId, Func<BaseItem, bool> filter)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(parentId))
|
||||
{
|
||||
var folder = (Folder)libraryManager.GetItemById(new Guid(parentId));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(userId))
|
||||
{
|
||||
var user = userManager.GetUserById(userId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentException("User not found");
|
||||
}
|
||||
|
||||
return folder
|
||||
.GetRecursiveChildren(user, filter)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return folder
|
||||
.GetRecursiveChildren(filter);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(userId))
|
||||
{
|
||||
var user = userManager.GetUserById(userId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentException("User not found");
|
||||
}
|
||||
|
||||
return userManager
|
||||
.GetUserById(userId)
|
||||
.RootFolder
|
||||
.GetRecursiveChildren(user, filter)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return libraryManager
|
||||
.RootFolder
|
||||
.GetRecursiveChildren(filter);
|
||||
}
|
||||
|
||||
private bool FilterItem(BaseItem item, GetItemCounts request, string userId)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(userId))
|
||||
|
@ -817,9 +861,9 @@ namespace MediaBrowser.Api.Library
|
|||
: (Folder)_libraryManager.RootFolder)
|
||||
: _libraryManager.GetItemById(request.Id);
|
||||
|
||||
while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
||||
while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.GetParent() != null)
|
||||
{
|
||||
item = item.Parent;
|
||||
item = item.GetParent();
|
||||
}
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
@ -860,9 +904,9 @@ namespace MediaBrowser.Api.Library
|
|||
: (Folder)_libraryManager.RootFolder)
|
||||
: _libraryManager.GetItemById(request.Id);
|
||||
|
||||
while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
||||
while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.GetParent() != null)
|
||||
{
|
||||
item = item.Parent;
|
||||
item = item.GetParent();
|
||||
}
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
|
|
@ -117,10 +117,7 @@ namespace MediaBrowser.Api.Movies
|
|||
public async Task<object> Get(GetSimilarMovies request)
|
||||
{
|
||||
var result = await GetSimilarItemsResult(
|
||||
// Strip out secondary versions
|
||||
request, item => (item is Movie) && !((Video)item).PrimaryVersionId.HasValue,
|
||||
|
||||
SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false);
|
||||
request, SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
|
@ -128,10 +125,7 @@ namespace MediaBrowser.Api.Movies
|
|||
public async Task<object> Get(GetSimilarTrailers request)
|
||||
{
|
||||
var result = await GetSimilarItemsResult(
|
||||
// Strip out secondary versions
|
||||
request, item => (item is Movie) && !((Video)item).PrimaryVersionId.HasValue,
|
||||
|
||||
SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false);
|
||||
request, SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
|
@ -140,8 +134,12 @@ namespace MediaBrowser.Api.Movies
|
|||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
IEnumerable<BaseItem> movies = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, i => i is Movie);
|
||||
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name }
|
||||
};
|
||||
var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId };
|
||||
var movies = _libraryManager.GetItems(query, parentIds);
|
||||
movies = _libraryManager.ReplaceVideosWithPrimaryVersions(movies);
|
||||
|
||||
var listEligibleForCategories = new List<BaseItem>();
|
||||
|
@ -184,7 +182,7 @@ namespace MediaBrowser.Api.Movies
|
|||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
private async Task<ItemsResult> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func<BaseItem, bool> includeInSearch, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
|
||||
private async Task<ItemsResult> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
|
||||
{
|
||||
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
|
||||
|
||||
|
@ -192,13 +190,19 @@ namespace MediaBrowser.Api.Movies
|
|||
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
|
||||
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
|
||||
|
||||
Func<BaseItem, bool> filter = i => i.Id != item.Id && includeInSearch(i);
|
||||
|
||||
var inputItems = user == null
|
||||
? _libraryManager.RootFolder.GetRecursiveChildren(filter)
|
||||
: user.RootFolder.GetRecursiveChildren(user, filter);
|
||||
|
||||
var list = inputItems.ToList();
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name }
|
||||
};
|
||||
var parentIds = new string[] { };
|
||||
var list = _libraryManager.GetItems(query, parentIds)
|
||||
.Where(i =>
|
||||
{
|
||||
// Strip out secondary versions
|
||||
var v = i as Video;
|
||||
return v != null && !v.PrimaryVersionId.HasValue;
|
||||
})
|
||||
.ToList();
|
||||
|
||||
if (user != null && user.Configuration.IncludeTrailersInSuggestions)
|
||||
{
|
||||
|
@ -379,9 +383,10 @@ namespace MediaBrowser.Api.Movies
|
|||
{
|
||||
foreach (var name in names)
|
||||
{
|
||||
var itemsWithActor = _libraryManager.GetItemIds(new InternalItemsQuery
|
||||
var itemsWithActor = _libraryManager.GetItemIds(new InternalItemsQuery(user)
|
||||
{
|
||||
Person = name
|
||||
|
||||
});
|
||||
|
||||
var items = allMovies
|
||||
|
|
|
@ -233,7 +233,7 @@ namespace MediaBrowser.Api
|
|||
throw new ResourceNotFoundException(string.Format("Package not found: {0}", request.Name));
|
||||
}
|
||||
|
||||
Task.Run(() => _installationManager.InstallPackage(package, new Progress<double>(), CancellationToken.None));
|
||||
Task.Run(() => _installationManager.InstallPackage(package, true, new Progress<double>(), CancellationToken.None));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -283,7 +283,7 @@ namespace MediaBrowser.Api
|
|||
private T GetParentWithImage<T>(BaseItem item, ImageType type)
|
||||
where T : BaseItem
|
||||
{
|
||||
return item.Parents.OfType<T>().FirstOrDefault(i => i.HasImage(type));
|
||||
return item.GetParents().OfType<T>().FirstOrDefault(i => i.HasImage(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,11 +68,7 @@ namespace MediaBrowser.Api
|
|||
_config.Configuration.EnableLocalizedGuids = true;
|
||||
_config.Configuration.MergeMetadataAndImagesByName = true;
|
||||
_config.Configuration.EnableStandaloneMetadata = true;
|
||||
_config.Configuration.EnableLibraryMetadataSubFolder = true;
|
||||
_config.Configuration.EnableCustomPathSubFolders = true;
|
||||
_config.Configuration.DisableXmlSavers = true;
|
||||
_config.Configuration.DisableStartupScan = true;
|
||||
_config.Configuration.EnableUserViews = true;
|
||||
_config.Configuration.EnableDateLastRefresh = true;
|
||||
_config.SaveConfiguration();
|
||||
}
|
||||
|
|
|
@ -273,29 +273,28 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, i => i is Episode);
|
||||
|
||||
var itemsList = _libraryManager
|
||||
.Sort(items, user, new[] { "PremiereDate", "AirTime", "SortName" }, SortOrder.Ascending)
|
||||
.Cast<Episode>()
|
||||
.ToList();
|
||||
|
||||
var unairedEpisodes = itemsList.Where(i => i.IsUnaired).ToList();
|
||||
|
||||
var minPremiereDate = DateTime.Now.Date.AddDays(-1).ToUniversalTime();
|
||||
var previousEpisodes = itemsList.Where(i => !i.IsUnaired && (i.PremiereDate ?? DateTime.MinValue) >= minPremiereDate).ToList();
|
||||
|
||||
previousEpisodes.AddRange(unairedEpisodes);
|
||||
var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId };
|
||||
|
||||
var pagedItems = ApplyPaging(previousEpisodes, request.StartIndex, request.Limit);
|
||||
var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Episode).Name },
|
||||
SortBy = new[] { "PremiereDate", "AirTime", "SortName" },
|
||||
SortOrder = SortOrder.Ascending,
|
||||
MinPremiereDate = minPremiereDate,
|
||||
StartIndex = request.StartIndex,
|
||||
Limit = request.Limit
|
||||
|
||||
}, parentIds);
|
||||
|
||||
var options = GetDtoOptions(request);
|
||||
|
||||
var returnItems = _dtoService.GetBaseItemDtos(pagedItems, options, user).ToArray();
|
||||
var returnItems = _dtoService.GetBaseItemDtos(itemsResult.Items, options, user).ToArray();
|
||||
|
||||
var result = new ItemsResult
|
||||
{
|
||||
TotalRecordCount = itemsList.Count,
|
||||
TotalRecordCount = itemsResult.TotalRecordCount,
|
||||
Items = returnItems
|
||||
};
|
||||
|
||||
|
|
|
@ -199,6 +199,8 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
[ApiMember(Name = "Genres", Description = "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Genres { get; set; }
|
||||
|
||||
public string GenreIds { get; set; }
|
||||
|
||||
[ApiMember(Name = "OfficialRatings", Description = "Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string OfficialRatings { get; set; }
|
||||
|
||||
|
@ -378,6 +380,11 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return (StudioIds ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetGenreIds()
|
||||
{
|
||||
return (GenreIds ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetPersonTypes()
|
||||
{
|
||||
return (PersonTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
|
|
@ -112,6 +112,11 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
user == null ? _libraryManager.RootFolder : user.RootFolder :
|
||||
parentItem;
|
||||
|
||||
if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
item = user == null ? _libraryManager.RootFolder : user.RootFolder;
|
||||
}
|
||||
|
||||
// Default list type = children
|
||||
|
||||
if (!string.IsNullOrEmpty(request.Ids))
|
||||
|
@ -210,6 +215,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
Tags = request.GetTags(),
|
||||
OfficialRatings = request.GetOfficialRatings(),
|
||||
Genres = request.GetGenres(),
|
||||
GenreIds = request.GetGenreIds(),
|
||||
Studios = request.GetStudios(),
|
||||
StudioIds = request.GetStudioIds(),
|
||||
Person = request.Person,
|
||||
|
@ -422,15 +428,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return false;
|
||||
}
|
||||
|
||||
// Min index number
|
||||
if (request.MinIndexNumber.HasValue)
|
||||
{
|
||||
if (!(i.IndexNumber.HasValue && i.IndexNumber.Value >= request.MinIndexNumber.Value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Min official rating
|
||||
if (!string.IsNullOrEmpty(request.MinOfficialRating))
|
||||
{
|
||||
|
|
|
@ -26,6 +26,8 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
[ApiMember(Name = "IncludeExternalContent", Description = "Whether or not to include external views such as channels or live tv", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "POST")]
|
||||
public bool? IncludeExternalContent { get; set; }
|
||||
|
||||
public string PresetViews { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Users/{UserId}/SpecialViewOptions", "GET")]
|
||||
|
@ -75,9 +77,24 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
query.IncludeExternalContent = request.IncludeExternalContent.Value;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.PresetViews))
|
||||
{
|
||||
query.PresetViews = request.PresetViews.Split(',');
|
||||
}
|
||||
|
||||
var app = AuthorizationContext.GetAuthorizationInfo(Request).Client ?? string.Empty;
|
||||
if (app.IndexOf("emby rt", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
query.PresetViews = new[] { CollectionType.Music, CollectionType.Movies, CollectionType.TvShows };
|
||||
}
|
||||
//query.PresetViews = new[] { CollectionType.Music, CollectionType.Movies, CollectionType.TvShows };
|
||||
|
||||
var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
dtoOptions.Fields = new List<ItemFields>();
|
||||
dtoOptions.Fields.Add(ItemFields.PrimaryImageAspectRatio);
|
||||
dtoOptions.Fields.Add(ItemFields.DisplayPreferencesId);
|
||||
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
|
@ -123,7 +140,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
var views = user.RootFolder
|
||||
.GetChildren(user, true)
|
||||
.OfType<Folder>()
|
||||
.Where(i => !UserView.IsExcludedFromGrouping(i))
|
||||
.Where(UserView.IsEligibleForGrouping)
|
||||
.ToList();
|
||||
|
||||
var list = views
|
||||
|
@ -141,9 +158,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
private bool IsEligibleForSpecialView(ICollectionFolder view)
|
||||
{
|
||||
var types = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Games, CollectionType.Music, CollectionType.Photos };
|
||||
|
||||
return types.Contains(view.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||
return UserView.IsEligibleForEnhancedView(view.CollectionType);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ namespace MediaBrowser.Common.Implementations
|
|||
/// Gets the HTTP client.
|
||||
/// </summary>
|
||||
/// <value>The HTTP client.</value>
|
||||
protected IHttpClient HttpClient { get; private set; }
|
||||
public IHttpClient HttpClient { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the network manager.
|
||||
/// </summary>
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
<HintPath>..\packages\SimpleInjector.3.1.2\lib\net45\SimpleInjector.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
|
@ -107,6 +108,7 @@
|
|||
<Compile Include="Security\SuppporterInfoResponse.cs" />
|
||||
<Compile Include="Serialization\JsonSerializer.cs" />
|
||||
<Compile Include="Serialization\XmlSerializer.cs" />
|
||||
<Compile Include="Updates\GithubUpdater.cs" />
|
||||
<Compile Include="Updates\InstallationManager.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
196
MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs
Normal file
196
MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs
Normal file
|
@ -0,0 +1,196 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.Updates;
|
||||
|
||||
namespace MediaBrowser.Common.Implementations.Updates
|
||||
{
|
||||
public class GithubUpdater
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private TimeSpan _cacheLength;
|
||||
|
||||
public GithubUpdater(IHttpClient httpClient, IJsonSerializer jsonSerializer, TimeSpan cacheLength)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_cacheLength = cacheLength;
|
||||
}
|
||||
|
||||
public async Task<CheckForUpdateResult> CheckForUpdateResult(string organzation, string repository, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename, CancellationToken cancellationToken)
|
||||
{
|
||||
var url = string.Format("https://api.github.com/repos/{0}/{1}/releases", organzation, repository);
|
||||
|
||||
var options = new HttpRequestOptions
|
||||
{
|
||||
Url = url,
|
||||
EnableKeepAlive = false,
|
||||
CancellationToken = cancellationToken,
|
||||
UserAgent = "Emby/3.0"
|
||||
|
||||
};
|
||||
|
||||
if (_cacheLength.Ticks > 0)
|
||||
{
|
||||
options.CacheMode = CacheMode.Unconditional;
|
||||
options.CacheLength = _cacheLength;
|
||||
}
|
||||
|
||||
using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
|
||||
{
|
||||
var obj = _jsonSerializer.DeserializeFromStream<RootObject[]>(stream);
|
||||
|
||||
return CheckForUpdateResult(obj, minVersion, updateLevel, assetFilename, packageName, targetFilename);
|
||||
}
|
||||
}
|
||||
|
||||
private CheckForUpdateResult CheckForUpdateResult(RootObject[] obj, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename)
|
||||
{
|
||||
if (updateLevel == PackageVersionClass.Release)
|
||||
{
|
||||
obj = obj.Where(i => !i.prerelease).ToArray();
|
||||
}
|
||||
else if (updateLevel == PackageVersionClass.Beta)
|
||||
{
|
||||
obj = obj.Where(i => !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||
}
|
||||
else if (updateLevel == PackageVersionClass.Dev)
|
||||
{
|
||||
obj = obj.Where(i => !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) || i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||
}
|
||||
|
||||
var availableUpdate = obj.Select(i => CheckForUpdateResult(i, minVersion, assetFilename, packageName, targetFilename)).FirstOrDefault(i => i != null);
|
||||
|
||||
return availableUpdate ?? new CheckForUpdateResult
|
||||
{
|
||||
IsUpdateAvailable = false
|
||||
};
|
||||
}
|
||||
|
||||
private CheckForUpdateResult CheckForUpdateResult(RootObject obj, Version minVersion, string assetFilename, string packageName, string targetFilename)
|
||||
{
|
||||
Version version;
|
||||
if (!Version.TryParse(obj.tag_name, out version))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (version < minVersion)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var asset = (obj.assets ?? new List<Asset>()).FirstOrDefault(i => string.Equals(assetFilename, Path.GetFileName(i.browser_download_url), StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (asset == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new CheckForUpdateResult
|
||||
{
|
||||
AvailableVersion = version.ToString(),
|
||||
IsUpdateAvailable = version > minVersion,
|
||||
Package = new PackageVersionInfo
|
||||
{
|
||||
classification = obj.prerelease ?
|
||||
(obj.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase) ? PackageVersionClass.Dev : PackageVersionClass.Beta) :
|
||||
PackageVersionClass.Release,
|
||||
name = packageName,
|
||||
sourceUrl = asset.browser_download_url,
|
||||
targetFilename = targetFilename,
|
||||
versionStr = version.ToString(),
|
||||
requiredVersionStr = "1.0.0",
|
||||
description = obj.body
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public class Uploader
|
||||
{
|
||||
public string login { get; set; }
|
||||
public int id { get; set; }
|
||||
public string avatar_url { get; set; }
|
||||
public string gravatar_id { get; set; }
|
||||
public string url { get; set; }
|
||||
public string html_url { get; set; }
|
||||
public string followers_url { get; set; }
|
||||
public string following_url { get; set; }
|
||||
public string gists_url { get; set; }
|
||||
public string starred_url { get; set; }
|
||||
public string subscriptions_url { get; set; }
|
||||
public string organizations_url { get; set; }
|
||||
public string repos_url { get; set; }
|
||||
public string events_url { get; set; }
|
||||
public string received_events_url { get; set; }
|
||||
public string type { get; set; }
|
||||
public bool site_admin { get; set; }
|
||||
}
|
||||
|
||||
public class Asset
|
||||
{
|
||||
public string url { get; set; }
|
||||
public int id { get; set; }
|
||||
public string name { get; set; }
|
||||
public object label { get; set; }
|
||||
public Uploader uploader { get; set; }
|
||||
public string content_type { get; set; }
|
||||
public string state { get; set; }
|
||||
public int size { get; set; }
|
||||
public int download_count { get; set; }
|
||||
public string created_at { get; set; }
|
||||
public string updated_at { get; set; }
|
||||
public string browser_download_url { get; set; }
|
||||
}
|
||||
|
||||
public class Author
|
||||
{
|
||||
public string login { get; set; }
|
||||
public int id { get; set; }
|
||||
public string avatar_url { get; set; }
|
||||
public string gravatar_id { get; set; }
|
||||
public string url { get; set; }
|
||||
public string html_url { get; set; }
|
||||
public string followers_url { get; set; }
|
||||
public string following_url { get; set; }
|
||||
public string gists_url { get; set; }
|
||||
public string starred_url { get; set; }
|
||||
public string subscriptions_url { get; set; }
|
||||
public string organizations_url { get; set; }
|
||||
public string repos_url { get; set; }
|
||||
public string events_url { get; set; }
|
||||
public string received_events_url { get; set; }
|
||||
public string type { get; set; }
|
||||
public bool site_admin { get; set; }
|
||||
}
|
||||
|
||||
public class RootObject
|
||||
{
|
||||
public string url { get; set; }
|
||||
public string assets_url { get; set; }
|
||||
public string upload_url { get; set; }
|
||||
public string html_url { get; set; }
|
||||
public int id { get; set; }
|
||||
public string tag_name { get; set; }
|
||||
public string target_commitish { get; set; }
|
||||
public string name { get; set; }
|
||||
public bool draft { get; set; }
|
||||
public Author author { get; set; }
|
||||
public bool prerelease { get; set; }
|
||||
public string created_at { get; set; }
|
||||
public string published_at { get; set; }
|
||||
public List<Asset> assets { get; set; }
|
||||
public string tarball_url { get; set; }
|
||||
public string zipball_url { get; set; }
|
||||
public string body { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -438,11 +438,12 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
/// Installs the package.
|
||||
/// </summary>
|
||||
/// <param name="package">The package.</param>
|
||||
/// <param name="isPlugin">if set to <c>true</c> [is plugin].</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">package</exception>
|
||||
public async Task InstallPackage(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken)
|
||||
public async Task InstallPackage(PackageVersionInfo package, bool isPlugin, IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
if (package == null)
|
||||
{
|
||||
|
@ -495,7 +496,7 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
|
||||
try
|
||||
{
|
||||
await InstallPackageInternal(package, innerProgress, linkedToken).ConfigureAwait(false);
|
||||
await InstallPackageInternal(package, isPlugin, innerProgress, linkedToken).ConfigureAwait(false);
|
||||
|
||||
lock (CurrentInstallations)
|
||||
{
|
||||
|
@ -551,18 +552,17 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
/// Installs the package internal.
|
||||
/// </summary>
|
||||
/// <param name="package">The package.</param>
|
||||
/// <param name="isPlugin">if set to <c>true</c> [is plugin].</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
private async Task InstallPackageInternal(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken)
|
||||
private async Task InstallPackageInternal(PackageVersionInfo package, bool isPlugin, IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
// Do the install
|
||||
await PerformPackageInstallation(progress, package, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var extension = Path.GetExtension(package.targetFilename) ?? "";
|
||||
|
||||
// Do plugin-specific processing
|
||||
if (!string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".rar", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".7z", StringComparison.OrdinalIgnoreCase))
|
||||
if (isPlugin)
|
||||
{
|
||||
// Set last update time if we were installed before
|
||||
var plugin = _applicationHost.Plugins.FirstOrDefault(p => string.Equals(p.Id.ToString(), package.guid, StringComparison.OrdinalIgnoreCase))
|
||||
|
|
|
@ -105,11 +105,12 @@ namespace MediaBrowser.Common.Updates
|
|||
/// Installs the package.
|
||||
/// </summary>
|
||||
/// <param name="package">The package.</param>
|
||||
/// <param name="isPlugin">if set to <c>true</c> [is plugin].</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">package</exception>
|
||||
Task InstallPackage(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken);
|
||||
Task InstallPackage(PackageVersionInfo package, bool isPlugin, IProgress<double> progress, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Uninstalls a plugin
|
||||
|
|
|
@ -18,9 +18,9 @@ namespace MediaBrowser.Controller.Channels
|
|||
|
||||
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent);
|
||||
return UnratedItem.ChannelContent;
|
||||
}
|
||||
|
||||
protected override string CreateUserDataKey()
|
||||
|
|
|
@ -6,6 +6,7 @@ using System;
|
|||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
|
@ -20,6 +21,11 @@ namespace MediaBrowser.Controller.Channels
|
|||
return false;
|
||||
}
|
||||
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return UnratedItem.ChannelContent;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsLocalMetadata
|
||||
{
|
||||
|
|
|
@ -42,9 +42,9 @@ namespace MediaBrowser.Controller.Channels
|
|||
return ExternalId;
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent);
|
||||
return UnratedItem.ChannelContent;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
|
|
|
@ -27,9 +27,22 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
public long? Size { get; set; }
|
||||
public string Container { get; set; }
|
||||
public int? TotalBitrate { get; set; }
|
||||
public List<string> Tags { get; set; }
|
||||
public ExtraType? ExtraType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the artist.
|
||||
/// </summary>
|
||||
/// <value>The artist.</value>
|
||||
public List<string> Artists { get; set; }
|
||||
|
||||
public List<string> AlbumArtists { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the album.
|
||||
/// </summary>
|
||||
/// <value>The album.</value>
|
||||
public string Album { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public bool IsThemeMedia
|
||||
{
|
||||
|
@ -43,7 +56,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
{
|
||||
Artists = new List<string>();
|
||||
AlbumArtists = new List<string>();
|
||||
Tags = new List<string>();
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
|
@ -92,14 +104,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
locationType != LocationType.Virtual;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the artist.
|
||||
/// </summary>
|
||||
/// <value>The artist.</value>
|
||||
public List<string> Artists { get; set; }
|
||||
|
||||
public List<string> AlbumArtists { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public List<string> AllArtists
|
||||
{
|
||||
|
@ -114,12 +118,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the album.
|
||||
/// </summary>
|
||||
/// <value>The album.</value>
|
||||
public string Album { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public MusicAlbum AlbumEntity
|
||||
{
|
||||
|
@ -173,9 +171,9 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
return base.CreateUserDataKey();
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Music);
|
||||
return UnratedItem.Music;
|
||||
}
|
||||
|
||||
public SongInfo GetLookupInfo()
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
{
|
||||
get
|
||||
{
|
||||
return Parents.OfType<MusicArtist>().FirstOrDefault();
|
||||
return GetParents().OfType<MusicArtist>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,13 +110,18 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
return config.BlockUnratedItems.Contains(UnratedItem.Music);
|
||||
}
|
||||
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return UnratedItem.Music;
|
||||
}
|
||||
|
||||
public AlbumInfo GetLookupInfo()
|
||||
{
|
||||
var id = GetItemLookupInfo<AlbumInfo>();
|
||||
|
||||
id.AlbumArtists = AlbumArtists;
|
||||
|
||||
var artist = Parents.OfType<MusicArtist>().FirstOrDefault();
|
||||
var artist = GetParents().OfType<MusicArtist>().FirstOrDefault();
|
||||
|
||||
if (artist != null)
|
||||
{
|
||||
|
|
|
@ -138,6 +138,11 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
return config.BlockUnratedItems.Contains(UnratedItem.Music);
|
||||
}
|
||||
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return UnratedItem.Music;
|
||||
}
|
||||
|
||||
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
var items = GetRecursiveChildren().ToList();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Collections;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
@ -24,6 +23,7 @@ using System.Runtime.Serialization;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -34,6 +34,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
protected BaseItem()
|
||||
{
|
||||
Tags = new List<string>();
|
||||
Genres = new List<string>();
|
||||
Studios = new List<string>();
|
||||
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
@ -44,7 +45,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <summary>
|
||||
/// The supported image extensions
|
||||
/// </summary>
|
||||
public static readonly string[] SupportedImageExtensions = { ".png", ".jpg", ".jpeg" };
|
||||
public static readonly string[] SupportedImageExtensions = { ".png", ".jpg", ".jpeg", ".tbn", ".gif" };
|
||||
|
||||
public static readonly List<string> SupportedImageExtensionsList = SupportedImageExtensions.ToList();
|
||||
|
||||
|
@ -103,7 +104,8 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
[IgnoreDataMember]
|
||||
public virtual string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -122,14 +124,23 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[IgnoreDataMember]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is hd.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is hd; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public bool? IsHD { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the audio.
|
||||
/// </summary>
|
||||
/// <value>The audio.</value>
|
||||
[IgnoreDataMember]
|
||||
public ProgramAudio? Audio { 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.
|
||||
|
@ -149,6 +160,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Gets or sets the path.
|
||||
/// </summary>
|
||||
/// <value>The path.</value>
|
||||
[IgnoreDataMember]
|
||||
public virtual string Path { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
|
@ -173,7 +185,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Id of the program.
|
||||
/// If this content came from an external service, the id of the content on that service
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public string ExternalId
|
||||
|
@ -201,11 +213,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
public virtual bool IsHiddenFromUser(User user)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public virtual bool IsOwnedItem
|
||||
{
|
||||
|
@ -325,12 +332,14 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Gets or sets the date created.
|
||||
/// </summary>
|
||||
/// <value>The date created.</value>
|
||||
[IgnoreDataMember]
|
||||
public DateTime DateCreated { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date modified.
|
||||
/// </summary>
|
||||
/// <value>The date modified.</value>
|
||||
[IgnoreDataMember]
|
||||
public DateTime DateModified { get; set; }
|
||||
|
||||
public DateTime DateLastSaved { get; set; }
|
||||
|
@ -407,6 +416,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Gets or sets the name of the forced sort.
|
||||
/// </summary>
|
||||
/// <value>The name of the forced sort.</value>
|
||||
[IgnoreDataMember]
|
||||
public string ForcedSortName
|
||||
{
|
||||
get { return _forcedSortName; }
|
||||
|
@ -447,10 +457,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
var idString = Id.ToString("N");
|
||||
|
||||
if (ConfigurationManager.Configuration.EnableLibraryMetadataSubFolder)
|
||||
{
|
||||
basePath = System.IO.Path.Combine(basePath, "library");
|
||||
}
|
||||
|
||||
return System.IO.Path.Combine(basePath, idString.Substring(0, 2), idString);
|
||||
}
|
||||
|
@ -493,6 +500,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
return sortable;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public Guid ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -502,15 +510,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
[IgnoreDataMember]
|
||||
public Folder Parent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ParentId != Guid.Empty)
|
||||
{
|
||||
return LibraryManager.GetItemById(ParentId) as Folder;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
get { return GetParent() as Folder; }
|
||||
set
|
||||
{
|
||||
|
||||
|
@ -525,16 +525,28 @@ namespace MediaBrowser.Controller.Entities
|
|||
[IgnoreDataMember]
|
||||
public IEnumerable<Folder> Parents
|
||||
{
|
||||
get
|
||||
get { return GetParents().OfType<Folder>(); }
|
||||
}
|
||||
|
||||
public BaseItem GetParent()
|
||||
{
|
||||
var parent = Parent;
|
||||
if (ParentId != Guid.Empty)
|
||||
{
|
||||
return LibraryManager.GetItemById(ParentId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<BaseItem> GetParents()
|
||||
{
|
||||
var parent = GetParent();
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
yield return parent;
|
||||
|
||||
parent = parent.Parent;
|
||||
}
|
||||
parent = parent.GetParent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,19 +558,20 @@ namespace MediaBrowser.Controller.Entities
|
|||
public T FindParent<T>()
|
||||
where T : Folder
|
||||
{
|
||||
return Parents.OfType<T>().FirstOrDefault();
|
||||
return GetParents().OfType<T>().FirstOrDefault();
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public virtual BaseItem DisplayParent
|
||||
{
|
||||
get { return Parent; }
|
||||
get { return GetParent(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When the item first debuted. For movies this could be premiere date, episodes would be first aired
|
||||
/// </summary>
|
||||
/// <value>The premiere date.</value>
|
||||
[IgnoreDataMember]
|
||||
public DateTime? PremiereDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -572,31 +585,35 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Gets or sets the display type of the media.
|
||||
/// </summary>
|
||||
/// <value>The display type of the media.</value>
|
||||
[IgnoreDataMember]
|
||||
public string DisplayMediaType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the official rating.
|
||||
/// </summary>
|
||||
/// <value>The official rating.</value>
|
||||
[IgnoreDataMember]
|
||||
public string OfficialRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the official rating description.
|
||||
/// </summary>
|
||||
/// <value>The official rating description.</value>
|
||||
[IgnoreDataMember]
|
||||
public string OfficialRatingDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the custom rating.
|
||||
/// </summary>
|
||||
/// <value>The custom rating.</value>
|
||||
//[IgnoreDataMember]
|
||||
[IgnoreDataMember]
|
||||
public string CustomRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the overview.
|
||||
/// </summary>
|
||||
/// <value>The overview.</value>
|
||||
[IgnoreDataMember]
|
||||
public string Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -609,37 +626,48 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Gets or sets the genres.
|
||||
/// </summary>
|
||||
/// <value>The genres.</value>
|
||||
[IgnoreDataMember]
|
||||
public List<string> Genres { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the tags.
|
||||
/// </summary>
|
||||
/// <value>The tags.</value>
|
||||
public List<string> Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the home page URL.
|
||||
/// </summary>
|
||||
/// <value>The home page URL.</value>
|
||||
[IgnoreDataMember]
|
||||
public string HomePageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the community rating.
|
||||
/// </summary>
|
||||
/// <value>The community rating.</value>
|
||||
//[IgnoreDataMember]
|
||||
[IgnoreDataMember]
|
||||
public float? CommunityRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the community rating vote count.
|
||||
/// </summary>
|
||||
/// <value>The community rating vote count.</value>
|
||||
[IgnoreDataMember]
|
||||
public int? VoteCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the run time ticks.
|
||||
/// </summary>
|
||||
/// <value>The run time ticks.</value>
|
||||
[IgnoreDataMember]
|
||||
public long? RunTimeTicks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the production year.
|
||||
/// </summary>
|
||||
/// <value>The production year.</value>
|
||||
[IgnoreDataMember]
|
||||
public int? ProductionYear { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -647,19 +675,34 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// This could be episode number, album track number, etc.
|
||||
/// </summary>
|
||||
/// <value>The index number.</value>
|
||||
//[IgnoreDataMember]
|
||||
[IgnoreDataMember]
|
||||
public int? IndexNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// For an episode this could be the season number, or for a song this could be the disc number.
|
||||
/// </summary>
|
||||
/// <value>The parent index number.</value>
|
||||
[IgnoreDataMember]
|
||||
public int? ParentIndexNumber { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public virtual string OfficialRatingForComparison
|
||||
public string OfficialRatingForComparison
|
||||
{
|
||||
get { return OfficialRating; }
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(OfficialRating))
|
||||
{
|
||||
return OfficialRating;
|
||||
}
|
||||
|
||||
var parent = DisplayParent;
|
||||
if (parent != null)
|
||||
{
|
||||
return parent.OfficialRatingForComparison;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
|
@ -821,7 +864,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
[IgnoreDataMember]
|
||||
protected virtual bool SupportsOwnedItems
|
||||
{
|
||||
get { return IsFolder || Parent != null; }
|
||||
get { return IsFolder || GetParent() != null; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
|
@ -846,7 +889,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
var localTrailersChanged = false;
|
||||
|
||||
if (LocationType == LocationType.FileSystem && Parent != null)
|
||||
if (LocationType == LocationType.FileSystem && GetParent() != null)
|
||||
{
|
||||
var hasThemeMedia = this as IHasThemeMedia;
|
||||
if (hasThemeMedia != null)
|
||||
|
@ -1008,7 +1051,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
if (string.IsNullOrWhiteSpace(lang))
|
||||
{
|
||||
lang = Parents
|
||||
lang = GetParents()
|
||||
.Select(i => i.PreferredMetadataLanguage)
|
||||
.FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
|
||||
}
|
||||
|
@ -1038,7 +1081,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
if (string.IsNullOrWhiteSpace(lang))
|
||||
{
|
||||
lang = Parents
|
||||
lang = GetParents()
|
||||
.Select(i => i.PreferredMetadataCountryCode)
|
||||
.FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
|
||||
}
|
||||
|
@ -1119,6 +1162,23 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
|
||||
public int? GetParentalRatingValue()
|
||||
{
|
||||
var rating = CustomRating;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(rating))
|
||||
{
|
||||
rating = OfficialRating;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(rating))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return LocalizationManager.GetRatingLevel(rating);
|
||||
}
|
||||
|
||||
public int? GetInheritedParentalRatingValue()
|
||||
{
|
||||
var rating = CustomRatingForComparison;
|
||||
|
||||
|
@ -1156,6 +1216,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
return true;
|
||||
}
|
||||
|
||||
public virtual UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return UnratedItem.Other;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the block unrated value.
|
||||
/// </summary>
|
||||
|
@ -1174,7 +1239,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
return false;
|
||||
}
|
||||
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Other);
|
||||
return config.BlockUnratedItems.Contains(GetBlockUnratedType());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1206,14 +1271,14 @@ namespace MediaBrowser.Controller.Entities
|
|||
return false;
|
||||
}
|
||||
|
||||
if (Parents.Any(i => !i.IsVisible(user)))
|
||||
if (GetParents().Any(i => !i.IsVisible(user)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checkFolders)
|
||||
{
|
||||
var topParent = Parents.LastOrDefault() ?? this;
|
||||
var topParent = GetParents().LastOrDefault() ?? this;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(topParent.Path))
|
||||
{
|
||||
|
@ -1307,15 +1372,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a person to the item
|
||||
/// </summary>
|
||||
/// <param name="person">The person.</param>
|
||||
/// <exception cref="System.ArgumentNullException"></exception>
|
||||
public void AddPerson(PersonInfo person)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a studio to the item
|
||||
/// </summary>
|
||||
|
@ -1875,5 +1931,54 @@ namespace MediaBrowser.Controller.Entities
|
|||
DateLastSaved.Ticks.ToString(CultureInfo.InvariantCulture)
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IEnumerable<Guid> GetAncestorIds()
|
||||
{
|
||||
return GetParents().Select(i => i.Id).Concat(LibraryManager.GetCollectionFolders(this).Select(i => i.Id));
|
||||
}
|
||||
|
||||
public BaseItem GetTopParent()
|
||||
{
|
||||
if (IsTopParent)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
return GetParents().FirstOrDefault(i => i.IsTopParent);
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public virtual bool IsTopParent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (GetParent() is AggregateFolder || this is Channel || this is BasePluginFolder)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var view = this as UserView;
|
||||
if (view != null && string.Equals(view.ViewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public virtual bool SupportsAncestors
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IEnumerable<Guid> GetIdsForAncestorQuery()
|
||||
{
|
||||
return new[] { Id };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,19 +17,8 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the tags.
|
||||
/// </summary>
|
||||
/// <value>The tags.</value>
|
||||
public List<string> Tags { get; set; }
|
||||
|
||||
public string SeriesName { get; set; }
|
||||
|
||||
public Book()
|
||||
{
|
||||
Tags = new List<string>();
|
||||
}
|
||||
|
||||
public override bool CanDownload()
|
||||
{
|
||||
var locationType = LocationType;
|
||||
|
@ -37,9 +26,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
locationType != LocationType.Virtual;
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Book);
|
||||
return UnratedItem.Book;
|
||||
}
|
||||
|
||||
public BookInfo GetLookupInfo()
|
||||
|
@ -48,7 +37,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
if (string.IsNullOrEmpty(SeriesName))
|
||||
{
|
||||
info.SeriesName = Parents.Select(i => i.Name).FirstOrDefault();
|
||||
info.SeriesName = GetParents().Select(i => i.Name).FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -181,9 +181,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
private List<LinkedChild> GetLinkedChildrenInternal()
|
||||
{
|
||||
return LibraryManager.RootFolder.Children
|
||||
.OfType<Folder>()
|
||||
.Where(i => i.Path != null && PhysicalLocations.Contains(i.Path, StringComparer.OrdinalIgnoreCase))
|
||||
return GetPhysicalParents()
|
||||
.SelectMany(c => c.LinkedChildren)
|
||||
.ToList();
|
||||
}
|
||||
|
@ -199,11 +197,14 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
private IEnumerable<BaseItem> GetActualChildren()
|
||||
{
|
||||
return
|
||||
LibraryManager.RootFolder.Children
|
||||
return GetPhysicalParents().SelectMany(c => c.Children);
|
||||
}
|
||||
|
||||
public IEnumerable<Folder> GetPhysicalParents()
|
||||
{
|
||||
return LibraryManager.RootFolder.Children
|
||||
.OfType<Folder>()
|
||||
.Where(i => i.Path != null && PhysicalLocations.Contains(i.Path, StringComparer.OrdinalIgnoreCase))
|
||||
.SelectMany(c => c.Children);
|
||||
.Where(i => i.Path != null && PhysicalLocations.Contains(i.Path, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
|
|
|
@ -28,7 +28,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
public List<Guid> ThemeSongIds { get; set; }
|
||||
public List<Guid> ThemeVideoIds { get; set; }
|
||||
public List<string> Tags { get; set; }
|
||||
|
||||
public Folder()
|
||||
{
|
||||
|
@ -36,7 +35,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
ThemeSongIds = new List<Guid>();
|
||||
ThemeVideoIds = new List<Guid>();
|
||||
Tags = new List<string>();
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
|
@ -151,8 +149,16 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
await LibraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (!EnableNewFolderQuerying())
|
||||
{
|
||||
await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool EnableNewFolderQuerying()
|
||||
{
|
||||
return ConfigurationManager.Configuration.MigrationVersion >= 1;
|
||||
}
|
||||
|
||||
protected void AddChildrenInternal(IEnumerable<BaseItem> children)
|
||||
{
|
||||
|
@ -196,21 +202,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override string OfficialRatingForComparison
|
||||
{
|
||||
get
|
||||
{
|
||||
// Never want folders to be blocked by "BlockNotRated"
|
||||
if (this is Series)
|
||||
{
|
||||
return base.OfficialRatingForComparison;
|
||||
}
|
||||
|
||||
return !string.IsNullOrWhiteSpace(base.OfficialRatingForComparison) ? base.OfficialRatingForComparison : "None";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the child.
|
||||
/// </summary>
|
||||
|
@ -224,9 +215,14 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
item.SetParent(null);
|
||||
|
||||
if (!EnableNewFolderQuerying())
|
||||
{
|
||||
return ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken);
|
||||
}
|
||||
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the children.
|
||||
/// </summary>
|
||||
|
@ -457,9 +453,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
BaseItem currentChild;
|
||||
|
||||
if (currentChildren.TryGetValue(child.Id, out currentChild))
|
||||
{
|
||||
if (IsValidFromResolver(currentChild, child))
|
||||
if (currentChildren.TryGetValue(child.Id, out currentChild) && IsValidFromResolver(currentChild, child))
|
||||
{
|
||||
var currentChildLocationType = currentChild.LocationType;
|
||||
if (currentChildLocationType != LocationType.Remote &&
|
||||
|
@ -470,20 +464,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
await UpdateIsOffline(currentChild, false).ConfigureAwait(false);
|
||||
validChildren.Add(currentChild);
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
newItems.Add(child);
|
||||
validChildren.Add(child);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Brand new item - needs to be added
|
||||
child.SetParent(this);
|
||||
newItems.Add(child);
|
||||
validChildren.Add(child);
|
||||
}
|
||||
}
|
||||
|
||||
// If any items were added or removed....
|
||||
if (newItems.Count > 0 || currentChildren.Count != validChildren.Count)
|
||||
|
@ -508,7 +497,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
else
|
||||
{
|
||||
await UpdateIsOffline(item, false).ConfigureAwait(false);
|
||||
actualRemovals.Add(item);
|
||||
}
|
||||
}
|
||||
|
@ -519,6 +507,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
foreach (var item in actualRemovals)
|
||||
{
|
||||
Logger.Debug("Removed item: " + item.Path);
|
||||
|
||||
item.SetParent(null);
|
||||
item.IsOffline = false;
|
||||
await LibraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }).ConfigureAwait(false);
|
||||
LibraryManager.ReportItemRemoved(item);
|
||||
}
|
||||
}
|
||||
|
@ -527,9 +520,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
AddChildrenInternal(newItems);
|
||||
|
||||
if (!EnableNewFolderQuerying())
|
||||
{
|
||||
await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
|
@ -721,7 +717,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
return true;
|
||||
}
|
||||
|
||||
return ContainsPath(LibraryManager.GetVirtualFolders(), originalPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -757,20 +753,17 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
protected IEnumerable<BaseItem> GetCachedChildren()
|
||||
{
|
||||
if (ConfigurationManager.Configuration.DisableStartupScan)
|
||||
if (EnableNewFolderQuerying())
|
||||
{
|
||||
return ItemRepository.GetChildrenItems(Id).Select(RetrieveChild).Where(i => i != null);
|
||||
//return ItemRepository.GetItems(new InternalItemsQuery
|
||||
//{
|
||||
// ParentId = Id
|
||||
return ItemRepository.GetItemList(new InternalItemsQuery
|
||||
{
|
||||
ParentId = Id
|
||||
|
||||
//}).Items.Select(RetrieveChild).Where(i => i != null);
|
||||
}).Select(RetrieveChild).Where(i => i != null);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return ItemRepository.GetChildrenItems(Id).Select(RetrieveChild).Where(i => i != null);
|
||||
}
|
||||
}
|
||||
|
||||
private BaseItem RetrieveChild(BaseItem child)
|
||||
{
|
||||
|
@ -832,19 +825,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets allowed children of an item
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param>
|
||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
/// <exception cref="System.ArgumentNullException"></exception>
|
||||
public virtual IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
|
||||
{
|
||||
return GetChildren(user, includeLinkedChildren, false);
|
||||
}
|
||||
|
||||
internal IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren, bool includeHidden)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
|
@ -856,7 +837,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
var result = new Dictionary<Guid, BaseItem>();
|
||||
|
||||
AddChildren(user, includeLinkedChildren, result, includeHidden, false, null);
|
||||
AddChildren(user, includeLinkedChildren, result, false, null);
|
||||
|
||||
return result.Values;
|
||||
}
|
||||
|
@ -872,29 +853,25 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <param name="user">The user.</param>
|
||||
/// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param>
|
||||
/// <param name="result">The result.</param>
|
||||
/// <param name="includeHidden">if set to <c>true</c> [include hidden].</param>
|
||||
/// <param name="recursive">if set to <c>true</c> [recursive].</param>
|
||||
/// <param name="filter">The filter.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
private void AddChildren(User user, bool includeLinkedChildren, Dictionary<Guid, BaseItem> result, bool includeHidden, bool recursive, Func<BaseItem, bool> filter)
|
||||
private void AddChildren(User user, bool includeLinkedChildren, Dictionary<Guid, BaseItem> result, bool recursive, Func<BaseItem, bool> filter)
|
||||
{
|
||||
foreach (var child in GetEligibleChildrenForRecursiveChildren(user))
|
||||
{
|
||||
if (child.IsVisible(user))
|
||||
{
|
||||
if (includeHidden || !child.IsHiddenFromUser(user))
|
||||
{
|
||||
if (filter == null || filter(child))
|
||||
{
|
||||
result[child.Id] = child;
|
||||
}
|
||||
}
|
||||
|
||||
if (recursive && child.IsFolder)
|
||||
{
|
||||
var folder = (Folder)child;
|
||||
|
||||
folder.AddChildren(user, includeLinkedChildren, result, includeHidden, true, filter);
|
||||
folder.AddChildren(user, includeLinkedChildren, result, true, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -935,7 +912,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
var result = new Dictionary<Guid, BaseItem>();
|
||||
|
||||
AddChildren(user, true, result, false, true, filter);
|
||||
AddChildren(user, true, result, true, filter);
|
||||
|
||||
return result.Values;
|
||||
}
|
||||
|
@ -1184,6 +1161,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
Recursive = true,
|
||||
IsFolder = false,
|
||||
IsUnaired = false
|
||||
|
||||
};
|
||||
|
||||
if (!user.Configuration.DisplayMissingEpisodes)
|
||||
|
|
|
@ -21,7 +21,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
RemoteTrailerIds = new List<Guid>();
|
||||
ThemeSongIds = new List<Guid>();
|
||||
ThemeVideoIds = new List<Guid>();
|
||||
Tags = new List<string>();
|
||||
}
|
||||
|
||||
public List<Guid> LocalTrailerIds { get; set; }
|
||||
|
@ -34,12 +33,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
locationType != LocationType.Virtual;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the tags.
|
||||
/// </summary>
|
||||
/// <value>The tags.</value>
|
||||
public List<string> Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the remote trailers.
|
||||
/// </summary>
|
||||
|
@ -105,9 +98,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
return base.GetDeletePaths();
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Game);
|
||||
return UnratedItem.Game;
|
||||
}
|
||||
|
||||
public GameInfo GetLookupInfo()
|
||||
|
|
|
@ -50,6 +50,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
return false;
|
||||
}
|
||||
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return UnratedItem.Game;
|
||||
}
|
||||
|
||||
public GameSystemInfo GetLookupInfo()
|
||||
{
|
||||
var id = GetItemLookupInfo<GameSystemInfo>();
|
||||
|
|
|
@ -16,6 +16,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
IEnumerable<string> PhysicalLocations { get; }
|
||||
}
|
||||
|
||||
public interface ISupportsUserSpecificView
|
||||
{
|
||||
bool EnableUserSpecificView { get; }
|
||||
}
|
||||
|
||||
public static class CollectionFolderExtensions
|
||||
{
|
||||
public static string GetViewType(this ICollectionFolder folder, User user)
|
||||
|
|
18
MediaBrowser.Controller/Entities/IHiddenFromDisplay.cs
Normal file
18
MediaBrowser.Controller/Entities/IHiddenFromDisplay.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public interface IHiddenFromDisplay
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether the specified user is hidden.
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns><c>true</c> if the specified user is hidden; otherwise, <c>false</c>.</returns>
|
||||
bool IsHiddenFromUser(User user);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -30,6 +31,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
public string[] MediaTypes { get; set; }
|
||||
public string[] IncludeItemTypes { get; set; }
|
||||
public string[] ExcludeItemTypes { get; set; }
|
||||
public string[] ExcludeTags { get; set; }
|
||||
public string[] Genres { get; set; }
|
||||
|
||||
public bool? IsMissing { get; set; }
|
||||
|
@ -69,12 +71,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
public string[] Studios { get; set; }
|
||||
public string[] StudioIds { get; set; }
|
||||
public string[] GenreIds { get; set; }
|
||||
public ImageType[] ImageTypes { get; set; }
|
||||
public VideoType[] VideoTypes { get; set; }
|
||||
public UnratedItem[] BlockUnratedItems { get; set; }
|
||||
public int[] Years { get; set; }
|
||||
public string[] Tags { get; set; }
|
||||
public string[] OfficialRatings { get; set; }
|
||||
|
||||
public DateTime? MinPremiereDate { get; set; }
|
||||
public DateTime? MinStartDate { get; set; }
|
||||
public DateTime? MaxStartDate { get; set; }
|
||||
public DateTime? MinEndDate { get; set; }
|
||||
|
@ -87,6 +92,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
public int? MinPlayers { get; set; }
|
||||
public int? MaxPlayers { get; set; }
|
||||
public int? MinIndexNumber { get; set; }
|
||||
public double? MinCriticRating { get; set; }
|
||||
public double? MinCommunityRating { get; set; }
|
||||
|
||||
|
@ -101,9 +107,14 @@ namespace MediaBrowser.Controller.Entities
|
|||
public LocationType? LocationType { get; set; }
|
||||
|
||||
public Guid? ParentId { get; set; }
|
||||
public string[] AncestorIds { get; set; }
|
||||
public string[] TopParentIds { get; set; }
|
||||
|
||||
public LocationType[] ExcludeLocationTypes { get; set; }
|
||||
|
||||
public InternalItemsQuery()
|
||||
{
|
||||
BlockUnratedItems = new UnratedItem[] { };
|
||||
Tags = new string[] { };
|
||||
OfficialRatings = new string[] { };
|
||||
SortBy = new string[] { };
|
||||
|
@ -113,6 +124,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
Genres = new string[] { };
|
||||
Studios = new string[] { };
|
||||
StudioIds = new string[] { };
|
||||
GenreIds = new string[] { };
|
||||
ImageTypes = new ImageType[] { };
|
||||
VideoTypes = new VideoType[] { };
|
||||
Years = new int[] { };
|
||||
|
@ -120,6 +132,29 @@ namespace MediaBrowser.Controller.Entities
|
|||
PersonIds = new string[] { };
|
||||
ChannelIds = new string[] { };
|
||||
ItemIds = new string[] { };
|
||||
AncestorIds = new string[] { };
|
||||
TopParentIds = new string[] { };
|
||||
ExcludeTags = new string[] { };
|
||||
ExcludeLocationTypes = new LocationType[] { };
|
||||
}
|
||||
|
||||
public InternalItemsQuery(User user)
|
||||
: this()
|
||||
{
|
||||
if (user != null)
|
||||
{
|
||||
var policy = user.Policy;
|
||||
MaxParentalRating = policy.MaxParentalRating;
|
||||
|
||||
if (policy.MaxParentalRating.HasValue)
|
||||
{
|
||||
BlockUnratedItems = policy.BlockUnratedItems;
|
||||
}
|
||||
|
||||
ExcludeTags = policy.BlockedTags;
|
||||
|
||||
User = user;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,15 +8,13 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Movies
|
||||
{
|
||||
/// <summary>
|
||||
/// Class BoxSet
|
||||
/// </summary>
|
||||
public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IMetadataContainer, IHasShares
|
||||
public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IHasShares
|
||||
{
|
||||
public List<Share> Shares { get; set; }
|
||||
|
||||
|
@ -65,6 +63,11 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
return config.BlockUnratedItems.Contains(UnratedItem.Movie);
|
||||
}
|
||||
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return UnratedItem.Movie;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool IsPreSorted
|
||||
{
|
||||
|
@ -154,34 +157,6 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
return GetItemLookupInfo<BoxSetInfo>();
|
||||
}
|
||||
|
||||
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
// Refresh bottom up, children first, then the boxset
|
||||
// By then hopefully the movies within will have Tmdb collection values
|
||||
var items = GetRecursiveChildren().ToList();
|
||||
|
||||
var totalItems = items.Count;
|
||||
var numComplete = 0;
|
||||
|
||||
// Refresh songs
|
||||
foreach (var item in items)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= totalItems;
|
||||
progress.Report(percent * 100);
|
||||
}
|
||||
|
||||
// Refresh current item
|
||||
await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
public override bool IsVisible(User user)
|
||||
{
|
||||
var userId = user.Id.ToString("N");
|
||||
|
|
|
@ -130,7 +130,7 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
|
||||
// Must have a parent to have special features
|
||||
// In other words, it must be part of the Parent/Child tree
|
||||
if (LocationType == LocationType.FileSystem && Parent != null && !IsInMixedFolder)
|
||||
if (LocationType == LocationType.FileSystem && GetParent() != null && !IsInMixedFolder)
|
||||
{
|
||||
var specialFeaturesChanged = await RefreshSpecialFeatures(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
|
@ -159,9 +159,9 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
return itemsChanged;
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Movie);
|
||||
return UnratedItem.Movie;
|
||||
}
|
||||
|
||||
public MovieInfo GetLookupInfo()
|
||||
|
|
|
@ -56,9 +56,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.CreateUserDataKey();
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Music);
|
||||
return UnratedItem.Music;
|
||||
}
|
||||
|
||||
public MusicVideoInfo GetLookupInfo()
|
||||
|
|
|
@ -101,6 +101,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsAncestors
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -9,12 +9,10 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
public class Photo : BaseItem, IHasTags, IHasTaglines
|
||||
{
|
||||
public List<string> Tags { get; set; }
|
||||
public List<string> Taglines { get; set; }
|
||||
|
||||
public Photo()
|
||||
{
|
||||
Tags = new List<string>();
|
||||
Taglines = new List<string>();
|
||||
}
|
||||
|
||||
|
@ -51,7 +49,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
get
|
||||
{
|
||||
return Parents.OfType<PhotoAlbum>().FirstOrDefault();
|
||||
return GetParents().OfType<PhotoAlbum>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,10 +68,5 @@ namespace MediaBrowser.Controller.Entities
|
|||
public double? Longitude { get; set; }
|
||||
public double? Altitude { get; set; }
|
||||
public int? IsoSpeedRating { get; set; }
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,9 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public class PhotoAlbum : Folder, IMetadataContainer
|
||||
public class PhotoAlbum : Folder
|
||||
{
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsLocalMetadata
|
||||
{
|
||||
get
|
||||
|
@ -32,31 +33,5 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Other);
|
||||
}
|
||||
|
||||
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
var items = GetRecursiveChildren().ToList();
|
||||
|
||||
var totalItems = items.Count;
|
||||
var numComplete = 0;
|
||||
|
||||
// Refresh songs
|
||||
foreach (var item in items)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= totalItems;
|
||||
progress.Report(percent * 100);
|
||||
}
|
||||
|
||||
// Refresh current item
|
||||
await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,13 +10,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// </summary>
|
||||
public class Studio : BaseItem, IItemByName, IHasTags
|
||||
{
|
||||
public List<string> Tags { get; set; }
|
||||
|
||||
public Studio()
|
||||
{
|
||||
Tags = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
{
|
||||
get
|
||||
{
|
||||
return Season ?? Parent;
|
||||
return Season ?? GetParent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,19 +115,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
return base.CreateUserDataKey();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Our rating comes from our series
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public override string OfficialRatingForComparison
|
||||
{
|
||||
get
|
||||
{
|
||||
var series = Series;
|
||||
return series != null ? series.OfficialRatingForComparison : base.OfficialRatingForComparison;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This Episode's Series Instance
|
||||
/// </summary>
|
||||
|
@ -265,14 +252,28 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<Guid> GetAncestorIds()
|
||||
{
|
||||
var list = base.GetAncestorIds().ToList();
|
||||
|
||||
var seasonId = SeasonId;
|
||||
|
||||
if (seasonId.HasValue && !list.Contains(seasonId.Value))
|
||||
{
|
||||
list.Add(seasonId.Value);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDeletePaths()
|
||||
{
|
||||
return new[] { Path };
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Series);
|
||||
return UnratedItem.Series;
|
||||
}
|
||||
|
||||
public EpisodeInfo GetLookupInfo()
|
||||
|
|
|
@ -6,6 +6,7 @@ using MoreLinq;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.TV
|
||||
{
|
||||
|
@ -32,7 +33,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
[IgnoreDataMember]
|
||||
public override BaseItem DisplayParent
|
||||
{
|
||||
get { return Series ?? Parent; }
|
||||
get { return Series ?? GetParent(); }
|
||||
}
|
||||
|
||||
// Genre, Rating and Stuido will all be the same
|
||||
|
@ -87,19 +88,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Our rating comes from our series
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public override string OfficialRatingForComparison
|
||||
{
|
||||
get
|
||||
{
|
||||
var series = Series;
|
||||
return series != null ? series.OfficialRatingForComparison : base.OfficialRatingForComparison;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the name of the sort.
|
||||
/// </summary>
|
||||
|
@ -234,6 +222,11 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
return false;
|
||||
}
|
||||
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return UnratedItem.Series;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string SeriesName
|
||||
{
|
||||
|
|
|
@ -333,6 +333,11 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
return config.BlockUnratedItems.Contains(UnratedItem.Series);
|
||||
}
|
||||
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return UnratedItem.Series;
|
||||
}
|
||||
|
||||
public SeriesInfo GetLookupInfo()
|
||||
{
|
||||
var info = GetItemLookupInfo<SeriesInfo>();
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
get
|
||||
{
|
||||
// Local trailers are not part of children
|
||||
return Parent == null;
|
||||
return GetParent() == null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,9 +97,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
return base.CreateUserDataKey();
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Trailer);
|
||||
return UnratedItem.Trailer;
|
||||
}
|
||||
|
||||
public TrailerInfo GetLookupInfo()
|
||||
|
|
|
@ -20,7 +20,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
public static IUserManager UserManager { get; set; }
|
||||
public static IXmlSerializer XmlSerializer { get; set; }
|
||||
public bool EnableUserViews { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// From now on all user paths will be Id-based.
|
||||
|
@ -58,6 +57,26 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
private string _name;
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public override string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
|
||||
// lazy load this again
|
||||
SortName = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the folder containing the item.
|
||||
/// If the item is a folder, it returns the folder itself
|
||||
|
|
|
@ -55,13 +55,21 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
|
||||
{
|
||||
var list = base.GetEligibleChildrenForRecursiveChildren(user).ToList();
|
||||
list.AddRange(LibraryManager.RootFolder.VirtualChildren);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the children of this folder from the actual file system
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
protected override IEnumerable<BaseItem> GetNonCachedChildren(IDirectoryService directoryService)
|
||||
{
|
||||
return base.GetNonCachedChildren(directoryService).Concat(LibraryManager.RootFolder.VirtualChildren);
|
||||
return base.GetNonCachedChildren(directoryService);
|
||||
}
|
||||
|
||||
public override bool BeforeMetadataRefresh()
|
||||
|
|
|
@ -6,6 +6,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -25,6 +26,25 @@ namespace MediaBrowser.Controller.Entities
|
|||
return true;
|
||||
}
|
||||
|
||||
public override IEnumerable<Guid> GetIdsForAncestorQuery()
|
||||
{
|
||||
var list = new List<Guid>();
|
||||
|
||||
if (DisplayParentId != Guid.Empty)
|
||||
{
|
||||
list.Add(DisplayParentId);
|
||||
}
|
||||
else if (ParentId != Guid.Empty)
|
||||
{
|
||||
list.Add(ParentId);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(Id);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public override Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query)
|
||||
{
|
||||
var parent = this as Folder;
|
||||
|
@ -81,34 +101,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
return GetChildren(user, false);
|
||||
}
|
||||
|
||||
public static bool IsExcludedFromGrouping(Folder folder)
|
||||
{
|
||||
var standaloneTypes = new List<string>
|
||||
{
|
||||
CollectionType.Books,
|
||||
CollectionType.HomeVideos,
|
||||
CollectionType.Photos,
|
||||
CollectionType.Playlists,
|
||||
CollectionType.BoxSets,
|
||||
CollectionType.MusicVideos
|
||||
};
|
||||
|
||||
var collectionFolder = folder as ICollectionFolder;
|
||||
|
||||
if (collectionFolder == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return standaloneTypes.Contains(collectionFolder.CollectionType ?? string.Empty);
|
||||
}
|
||||
|
||||
public static bool IsUserSpecific(Folder folder)
|
||||
{
|
||||
var standaloneTypes = new List<string>
|
||||
{
|
||||
CollectionType.Playlists,
|
||||
CollectionType.BoxSets
|
||||
CollectionType.Playlists
|
||||
};
|
||||
|
||||
var collectionFolder = folder as ICollectionFolder;
|
||||
|
@ -118,9 +115,65 @@ namespace MediaBrowser.Controller.Entities
|
|||
return false;
|
||||
}
|
||||
|
||||
var supportsUserSpecific = folder as ISupportsUserSpecificView;
|
||||
if (supportsUserSpecific != null && supportsUserSpecific.EnableUserSpecificView)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return standaloneTypes.Contains(collectionFolder.CollectionType ?? string.Empty);
|
||||
}
|
||||
|
||||
public static bool IsEligibleForGrouping(Folder folder)
|
||||
{
|
||||
var collectionFolder = folder as ICollectionFolder;
|
||||
return collectionFolder != null && IsEligibleForGrouping(collectionFolder.CollectionType);
|
||||
}
|
||||
|
||||
public static bool IsEligibleForGrouping(string viewType)
|
||||
{
|
||||
var types = new[]
|
||||
{
|
||||
CollectionType.Movies,
|
||||
CollectionType.TvShows,
|
||||
string.Empty
|
||||
};
|
||||
|
||||
return types.Contains(viewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsEligibleForEnhancedView(string viewType)
|
||||
{
|
||||
var types = new[]
|
||||
{
|
||||
CollectionType.Movies,
|
||||
CollectionType.TvShows
|
||||
};
|
||||
|
||||
return types.Contains(viewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool EnableOriginalFolder(string viewType)
|
||||
{
|
||||
var types = new[]
|
||||
{
|
||||
CollectionType.Games,
|
||||
CollectionType.Books,
|
||||
CollectionType.MusicVideos,
|
||||
CollectionType.HomeVideos,
|
||||
CollectionType.Photos,
|
||||
CollectionType.Music,
|
||||
CollectionType.BoxSets
|
||||
};
|
||||
|
||||
return types.Contains(viewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
protected override Task ValidateChildrenInternal(IProgress<double> progress, System.Threading.CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, Providers.MetadataRefreshOptions refreshOptions, Providers.IDirectoryService directoryService)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPeople
|
||||
{
|
||||
|
|
|
@ -120,59 +120,34 @@ namespace MediaBrowser.Controller.Entities
|
|||
return await GetLiveTvView(queryParent, user, query).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
case CollectionType.Photos:
|
||||
case CollectionType.Books:
|
||||
case CollectionType.HomeVideos:
|
||||
case CollectionType.Games:
|
||||
case CollectionType.MusicVideos:
|
||||
{
|
||||
if (query.Recursive)
|
||||
{
|
||||
return GetResult(queryParent.GetRecursiveChildren(user, true), queryParent, query);
|
||||
}
|
||||
return GetResult(queryParent.GetChildren(user, true), queryParent, query);
|
||||
}
|
||||
|
||||
case CollectionType.Folders:
|
||||
return GetResult(user.RootFolder.GetChildren(user, true), queryParent, query);
|
||||
|
||||
case CollectionType.Games:
|
||||
return await GetGameView(user, queryParent, query).ConfigureAwait(false);
|
||||
|
||||
case CollectionType.Playlists:
|
||||
return await GetPlaylistsView(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case CollectionType.BoxSets:
|
||||
return await GetBoxsetView(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case CollectionType.Photos:
|
||||
return await GetPhotosView(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case CollectionType.TvShows:
|
||||
return await GetTvView(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case CollectionType.Music:
|
||||
return await GetMusicFolders(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case CollectionType.Movies:
|
||||
return await GetMovieFolders(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case SpecialFolder.MusicGenres:
|
||||
return await GetMusicGenres(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case SpecialFolder.MusicGenre:
|
||||
return await GetMusicGenreItems(queryParent, displayParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case SpecialFolder.GameGenres:
|
||||
return await GetGameGenres(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case SpecialFolder.GameGenre:
|
||||
return await GetGameGenreItems(queryParent, displayParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case SpecialFolder.GameSystems:
|
||||
return GetGameSystems(queryParent, user, query);
|
||||
|
||||
case SpecialFolder.LatestGames:
|
||||
return GetLatestGames(queryParent, user, query);
|
||||
|
||||
case SpecialFolder.RecentlyPlayedGames:
|
||||
return GetRecentlyPlayedGames(queryParent, user, query);
|
||||
|
||||
case SpecialFolder.GameFavorites:
|
||||
return GetFavoriteGames(queryParent, user, query);
|
||||
|
||||
case SpecialFolder.TvShowSeries:
|
||||
return GetTvSeries(queryParent, user, query);
|
||||
|
||||
|
@ -212,6 +187,21 @@ namespace MediaBrowser.Controller.Entities
|
|||
case SpecialFolder.MovieCollections:
|
||||
return GetMovieCollections(queryParent, user, query);
|
||||
|
||||
case SpecialFolder.TvFavoriteEpisodes:
|
||||
return GetFavoriteEpisodes(queryParent, user, query);
|
||||
|
||||
case SpecialFolder.TvFavoriteSeries:
|
||||
return GetFavoriteSeries(queryParent, user, query);
|
||||
|
||||
case CollectionType.Music:
|
||||
return await GetMusicFolders(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case SpecialFolder.MusicGenres:
|
||||
return await GetMusicGenres(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case SpecialFolder.MusicGenre:
|
||||
return await GetMusicGenreItems(queryParent, displayParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case SpecialFolder.MusicLatest:
|
||||
return GetMusicLatest(queryParent, user, query);
|
||||
|
||||
|
@ -230,12 +220,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
case SpecialFolder.MusicSongs:
|
||||
return GetMusicSongs(queryParent, user, query);
|
||||
|
||||
case SpecialFolder.TvFavoriteEpisodes:
|
||||
return GetFavoriteEpisodes(queryParent, user, query);
|
||||
|
||||
case SpecialFolder.TvFavoriteSeries:
|
||||
return GetFavoriteSeries(queryParent, user, query);
|
||||
|
||||
case SpecialFolder.MusicFavorites:
|
||||
return await GetMusicFavorites(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
|
@ -262,18 +246,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
private async Task<QueryResult<BaseItem>> FindPlaylists(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
var list = _playlistManager.GetPlaylists(user.Id.ToString("N"));
|
||||
|
||||
return GetResult(list, parent, query);
|
||||
}
|
||||
|
||||
private int GetSpecialItemsLimit()
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
|
||||
private async Task<QueryResult<BaseItem>> GetMusicFolders(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
if (query.Recursive)
|
||||
|
@ -289,7 +261,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
list.Add(await GetUserView(SpecialFolder.MusicPlaylists, "1", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicAlbums, "2", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicAlbumArtists, "3", parent).ConfigureAwait(false));
|
||||
//list.Add(await GetUserView(SpecialFolder.MusicArtists, user, "4", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicArtists, "4", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicSongs, "5", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicGenres, "6", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicFavorites, "7", parent).ConfigureAwait(false));
|
||||
|
@ -422,6 +394,36 @@ namespace MediaBrowser.Controller.Entities
|
|||
return PostFilterAndSort(items, parent, null, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetFavoriteSongs(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.IsFavorite = true;
|
||||
|
||||
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music }, i => (i is Audio.Audio) && FilterItem(i, query));
|
||||
|
||||
return PostFilterAndSort(items, parent, null, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetFavoriteAlbums(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.IsFavorite = true;
|
||||
|
||||
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music }, i => (i is MusicAlbum) && FilterItem(i, query));
|
||||
|
||||
return PostFilterAndSort(items, parent, null, query);
|
||||
}
|
||||
|
||||
private async Task<QueryResult<BaseItem>> FindPlaylists(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
var list = _playlistManager.GetPlaylists(user.Id.ToString("N"));
|
||||
|
||||
return GetResult(list, parent, query);
|
||||
}
|
||||
|
||||
private int GetSpecialItemsLimit()
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
|
||||
private async Task<QueryResult<BaseItem>> GetMovieFolders(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
if (query.Recursive)
|
||||
|
@ -480,24 +482,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
return PostFilterAndSort(items, parent, null, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetFavoriteSongs(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.IsFavorite = true;
|
||||
|
||||
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music }, i => (i is Audio.Audio) && FilterItem(i, query));
|
||||
|
||||
return PostFilterAndSort(items, parent, null, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetFavoriteAlbums(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.IsFavorite = true;
|
||||
|
||||
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music }, i => (i is MusicAlbum) && FilterItem(i, query));
|
||||
|
||||
return PostFilterAndSort(items, parent, null, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }, i => (i is Movie) && FilterItem(i, query));
|
||||
|
@ -617,54 +601,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
return GetResult(list, parent, query);
|
||||
}
|
||||
|
||||
private async Task<QueryResult<BaseItem>> GetGameView(User user, Folder parent, InternalItemsQuery query)
|
||||
{
|
||||
if (query.Recursive)
|
||||
{
|
||||
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => FilterItem(i, query));
|
||||
return PostFilterAndSort(items, parent, null, query);
|
||||
}
|
||||
|
||||
var list = new List<BaseItem>();
|
||||
|
||||
list.Add(await GetUserView(SpecialFolder.LatestGames, "0", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.RecentlyPlayedGames, "1", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.GameFavorites, "2", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.GameSystems, "3", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.GameGenres, "4", parent).ConfigureAwait(false));
|
||||
|
||||
return GetResult(list, parent, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetLatestGames(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
|
||||
query.SortOrder = SortOrder.Descending;
|
||||
|
||||
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => i is Game && FilterItem(i, query));
|
||||
|
||||
return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetRecentlyPlayedGames(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.IsPlayed = true;
|
||||
query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
|
||||
query.SortOrder = SortOrder.Descending;
|
||||
|
||||
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => i is Game && FilterItem(i, query));
|
||||
|
||||
return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetFavoriteGames(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.IsFavorite = true;
|
||||
|
||||
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => i is Game && FilterItem(i, query));
|
||||
return PostFilterAndSort(items, parent, null, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
|
||||
|
@ -745,49 +681,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
return GetResult(items, queryParent, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetGameSystems(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => i is GameSystem && FilterItem(i, query));
|
||||
|
||||
return PostFilterAndSort(items, parent, null, query);
|
||||
}
|
||||
|
||||
private async Task<QueryResult<BaseItem>> GetGameGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query)
|
||||
{
|
||||
var items = GetRecursiveChildren(queryParent, user, new[] { CollectionType.Games },
|
||||
i => i is Game && i.Genres.Contains(displayParent.Name, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
return GetResult(items, queryParent, query);
|
||||
}
|
||||
|
||||
private async Task<QueryResult<BaseItem>> GetGameGenres(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
var tasks = GetRecursiveChildren(parent, user, new[] { CollectionType.Games })
|
||||
.OfType<Game>()
|
||||
.SelectMany(i => i.Genres)
|
||||
.DistinctNames()
|
||||
.Select(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return _libraryManager.GetGameGenre(i);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Full exception logged at lower levels
|
||||
_logger.Error("Error getting game genre");
|
||||
return null;
|
||||
}
|
||||
|
||||
})
|
||||
.Where(i => i != null)
|
||||
.Select(i => GetUserView(i.Name, SpecialFolder.GameGenre, i.SortName, parent));
|
||||
|
||||
var genres = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
return GetResult(genres, parent, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetResult<T>(QueryResult<T> result)
|
||||
where T : BaseItem
|
||||
{
|
||||
|
@ -1061,6 +954,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
return false;
|
||||
}
|
||||
|
||||
if (request.GenreIds.Length > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (request.VideoTypes.Length > 0)
|
||||
{
|
||||
return false;
|
||||
|
@ -1101,10 +999,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
return false;
|
||||
}
|
||||
|
||||
if (request.MinIndexNumber.HasValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static IEnumerable<BaseItem> FilterVirtualEpisodes(
|
||||
private static IEnumerable<BaseItem> FilterVirtualEpisodes(
|
||||
IEnumerable<BaseItem> items,
|
||||
bool? isMissing,
|
||||
bool? isVirtualUnaired,
|
||||
|
@ -1374,7 +1277,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
if (query.IsInBoxSet.HasValue)
|
||||
{
|
||||
var val = query.IsInBoxSet.Value;
|
||||
if (item.Parents.OfType<BoxSet>().Any() != val)
|
||||
if (item.GetParents().OfType<BoxSet>().Any() != val)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1657,6 +1560,16 @@ namespace MediaBrowser.Controller.Entities
|
|||
return false;
|
||||
}
|
||||
|
||||
// Apply genre filter
|
||||
if (query.GenreIds.Length > 0 && !query.GenreIds.Any(id =>
|
||||
{
|
||||
var genreItem = libraryManager.GetItemById(id);
|
||||
return genreItem != null && item.Genres.Contains(genreItem.Name, StringComparer.OrdinalIgnoreCase);
|
||||
}))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Apply year filter
|
||||
if (query.Years.Length > 0)
|
||||
{
|
||||
|
@ -1779,6 +1692,16 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
if (query.MinIndexNumber.HasValue)
|
||||
{
|
||||
var val = query.MinIndexNumber.Value;
|
||||
|
||||
if (!(item.IndexNumber.HasValue && item.IndexNumber.Value >= val))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1789,12 +1712,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
return _libraryManager.RootFolder
|
||||
.Children
|
||||
.OfType<Folder>()
|
||||
.Where(i => !UserView.IsExcludedFromGrouping(i));
|
||||
.Where(UserView.IsEligibleForGrouping);
|
||||
}
|
||||
return user.RootFolder
|
||||
.GetChildren(user, true, true)
|
||||
.GetChildren(user, true)
|
||||
.OfType<Folder>()
|
||||
.Where(i => user.IsFolderGrouped(i.Id) && !UserView.IsExcludedFromGrouping(i));
|
||||
.Where(i => user.IsFolderGrouped(i.Id) && UserView.IsEligibleForGrouping(i));
|
||||
}
|
||||
|
||||
private IEnumerable<Folder> GetMediaFolders(User user, IEnumerable<string> viewTypes)
|
||||
|
|
|
@ -185,12 +185,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
public bool IsShortcut { get; set; }
|
||||
public string ShortcutPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the tags.
|
||||
/// </summary>
|
||||
/// <value>The tags.</value>
|
||||
public List<string> Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the video bit rate.
|
||||
/// </summary>
|
||||
|
@ -356,7 +350,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
// Must have a parent to have additional parts or alternate versions
|
||||
// In other words, it must be part of the Parent/Child tree
|
||||
// The additional parts won't have additional parts themselves
|
||||
if (LocationType == LocationType.FileSystem && Parent != null)
|
||||
if (LocationType == LocationType.FileSystem && GetParent() != null)
|
||||
{
|
||||
if (!IsStacked)
|
||||
{
|
||||
|
|
|
@ -337,7 +337,6 @@ namespace MediaBrowser.Controller.Library
|
|||
string parentId,
|
||||
string viewType,
|
||||
string sortName,
|
||||
string uniqueId,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
|
@ -391,13 +390,11 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <param name="parent">The parent.</param>
|
||||
/// <param name="viewType">Type of the view.</param>
|
||||
/// <param name="sortName">Name of the sort.</param>
|
||||
/// <param name="uniqueId">The unique identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<UserView>.</returns>
|
||||
Task<UserView> GetShadowView(BaseItem parent,
|
||||
string viewType,
|
||||
string sortName,
|
||||
string uniqueId,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
|
@ -543,5 +540,29 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <param name="imageIndex">Index of the image.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the items.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="parentIds">The parent ids.</param>
|
||||
/// <returns>List<BaseItem>.</returns>
|
||||
IEnumerable<BaseItem> GetItems(InternalItemsQuery query, IEnumerable<string> parentIds);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the items result.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="parentIds">The parent ids.</param>
|
||||
/// <returns>QueryResult<BaseItem>.</returns>
|
||||
QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query, IEnumerable<string> parentIds);
|
||||
|
||||
/// <summary>
|
||||
/// Ignores the file.
|
||||
/// </summary>
|
||||
/// <param name="file">The file.</param>
|
||||
/// <param name="parent">The parent.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
|
||||
bool IgnoreFile(FileSystemMetadata file, BaseItem parent);
|
||||
}
|
||||
}
|
|
@ -155,7 +155,7 @@ namespace MediaBrowser.Controller.Library
|
|||
// Not officially supported but in some cases we can handle it.
|
||||
if (item == null)
|
||||
{
|
||||
item = parent.Parents.OfType<T>().FirstOrDefault();
|
||||
item = parent.GetParents().OfType<T>().FirstOrDefault();
|
||||
}
|
||||
|
||||
return item != null;
|
||||
|
|
|
@ -36,7 +36,6 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
public bool IsLive { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public bool IsPremiere { get; set; }
|
||||
public ProgramAudio? Audio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
|
@ -106,9 +105,9 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
}
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram);
|
||||
return UnratedItem.LiveTvProgram;
|
||||
}
|
||||
|
||||
protected override string GetInternalMetadataPath(string basePath)
|
||||
|
@ -140,5 +139,10 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
|
||||
return list;
|
||||
}
|
||||
|
||||
public override bool IsVisibleStandalone(User user)
|
||||
{
|
||||
return IsVisible(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,9 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
return GetClientTypeName() + "-" + Name;
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.LiveTvChannel);
|
||||
return UnratedItem.LiveTvChannel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -40,10 +40,11 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the channel.
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The type of the channel.</value>
|
||||
public ChannelType ChannelType { get; set; }
|
||||
/// <value>The name.</value>
|
||||
[IgnoreDataMember]
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the program, in UTC.
|
||||
|
@ -51,12 +52,6 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
[IgnoreDataMember]
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the audio.
|
||||
/// </summary>
|
||||
/// <value>The audio.</value>
|
||||
public ProgramAudio? Audio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is repeat.
|
||||
/// </summary>
|
||||
|
@ -71,12 +66,6 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
[IgnoreDataMember]
|
||||
public string EpisodeTitle { 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 a value indicating whether this instance is movie.
|
||||
/// </summary>
|
||||
|
@ -153,14 +142,14 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override string MediaType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChannelType == ChannelType.TV ? Model.Entities.MediaType.Video : Model.Entities.MediaType.Audio;
|
||||
}
|
||||
}
|
||||
//[IgnoreDataMember]
|
||||
//public override string MediaType
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// return ChannelType == ChannelType.TV ? Model.Entities.MediaType.Video : Model.Entities.MediaType.Audio;
|
||||
// }
|
||||
//}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public bool IsAiring
|
||||
|
@ -189,9 +178,9 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
return "Program";
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram);
|
||||
return UnratedItem.LiveTvProgram;
|
||||
}
|
||||
|
||||
protected override string GetInternalMetadataPath(string basePath)
|
||||
|
@ -236,5 +225,14 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
return base.SupportsPeople;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsAncestors
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
public bool IsLive { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public bool IsPremiere { get; set; }
|
||||
public ProgramAudio? Audio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
|
@ -121,9 +120,9 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
}
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram);
|
||||
return UnratedItem.LiveTvProgram;
|
||||
}
|
||||
|
||||
protected override string GetInternalMetadataPath(string basePath)
|
||||
|
@ -155,5 +154,10 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
|
||||
return list;
|
||||
}
|
||||
|
||||
public override bool IsVisibleStandalone(User user)
|
||||
{
|
||||
return IsVisible(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
|
@ -11,6 +12,11 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
return false;
|
||||
}
|
||||
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return UnratedItem.LiveTvProgram;
|
||||
}
|
||||
|
||||
public override bool SupportsLocalMetadata
|
||||
{
|
||||
get
|
||||
|
|
|
@ -162,6 +162,7 @@
|
|||
<Compile Include="Entities\IHasThemeMedia.cs" />
|
||||
<Compile Include="Entities\IHasTrailers.cs" />
|
||||
<Compile Include="Entities\IHasUserData.cs" />
|
||||
<Compile Include="Entities\IHiddenFromDisplay.cs" />
|
||||
<Compile Include="Entities\IItemByName.cs" />
|
||||
<Compile Include="Entities\ILibraryItem.cs" />
|
||||
<Compile Include="Entities\ImageSourceInfo.cs" />
|
||||
|
|
|
@ -15,7 +15,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
public IIsoMount MountedIso { get; set; }
|
||||
public VideoType VideoType { get; set; }
|
||||
public List<string> PlayableStreamFileNames { get; set; }
|
||||
public bool ExtractKeyFrameInterval { get; set; }
|
||||
|
||||
public MediaInfoRequest()
|
||||
{
|
||||
|
|
|
@ -176,6 +176,20 @@ namespace MediaBrowser.Controller.Persistence
|
|||
/// <param name="query">The query.</param>
|
||||
/// <returns>QueryResult<Tuple<Guid, System.String>>.</returns>
|
||||
QueryResult<Tuple<Guid, string>> GetItemIdsWithPath(InternalItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item list.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>List<BaseItem>.</returns>
|
||||
IEnumerable<BaseItem> GetItemList(InternalItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the inherited values.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task UpdateInheritedValues(CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -144,6 +144,7 @@ namespace MediaBrowser.Controller.Playlists
|
|||
|
||||
public string PlaylistMediaType { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override string MediaType
|
||||
{
|
||||
get
|
||||
|
|
|
@ -10,24 +10,6 @@ namespace MediaBrowser.Controller.Providers
|
|||
/// <value>The item identifier.</value>
|
||||
public Guid ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the item.
|
||||
/// </summary>
|
||||
/// <value>The name of the item.</value>
|
||||
public string ItemName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the item.
|
||||
/// </summary>
|
||||
/// <value>The type of the item.</value>
|
||||
public string ItemType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the series.
|
||||
/// </summary>
|
||||
/// <value>The name of the series.</value>
|
||||
public string SeriesName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date last metadata refresh.
|
||||
/// </summary>
|
||||
|
@ -40,22 +22,8 @@ namespace MediaBrowser.Controller.Providers
|
|||
/// <value>The date last images refresh.</value>
|
||||
public DateTime? DateLastImagesRefresh { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the last result error message.
|
||||
/// </summary>
|
||||
/// <value>The last result error message.</value>
|
||||
public string LastErrorMessage { get; set; }
|
||||
|
||||
public DateTime? ItemDateModified { get; set; }
|
||||
|
||||
public void AddStatus(string errorMessage)
|
||||
{
|
||||
if (string.IsNullOrEmpty(LastErrorMessage))
|
||||
{
|
||||
LastErrorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDirty { get; private set; }
|
||||
|
||||
public void SetDateLastMetadataRefresh(DateTime? date)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Controller.Library;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Resolvers
|
||||
{
|
||||
|
@ -7,6 +8,6 @@ namespace MediaBrowser.Controller.Resolvers
|
|||
/// </summary>
|
||||
public interface IResolverIgnoreRule
|
||||
{
|
||||
bool ShouldIgnore(ItemResolveArgs args);
|
||||
bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
|||
private readonly ILocalizationManager _localization;
|
||||
private readonly IChannelManager _channelManager;
|
||||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
private readonly IUserViewManager _userViewManager;
|
||||
|
||||
public ContentDirectory(IDlnaManager dlna,
|
||||
IUserDataManager userDataManager,
|
||||
|
@ -34,7 +35,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
|||
IServerConfigurationManager config,
|
||||
IUserManager userManager,
|
||||
ILogger logger,
|
||||
IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager)
|
||||
IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager)
|
||||
: base(logger, httpClient)
|
||||
{
|
||||
_dlna = dlna;
|
||||
|
@ -46,6 +47,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
|||
_localization = localization;
|
||||
_channelManager = channelManager;
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
_userViewManager = userViewManager;
|
||||
}
|
||||
|
||||
private int SystemUpdateId
|
||||
|
@ -86,7 +88,8 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
|||
_config,
|
||||
_localization,
|
||||
_channelManager,
|
||||
_mediaSourceManager)
|
||||
_mediaSourceManager,
|
||||
_userViewManager)
|
||||
.ProcessControlRequest(request);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ using System.Text;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using MediaBrowser.Model.Library;
|
||||
|
||||
namespace MediaBrowser.Dlna.ContentDirectory
|
||||
{
|
||||
|
@ -34,6 +35,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
|||
private readonly IUserDataManager _userDataManager;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly User _user;
|
||||
private readonly IUserViewManager _userViewManager;
|
||||
|
||||
private const string NS_DC = "http://purl.org/dc/elements/1.1/";
|
||||
private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
|
||||
|
@ -47,7 +49,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
|||
|
||||
private readonly DeviceProfile _profile;
|
||||
|
||||
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager)
|
||||
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager)
|
||||
: base(config, logger)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
|
@ -55,6 +57,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
|||
_user = user;
|
||||
_systemUpdateId = systemUpdateId;
|
||||
_channelManager = channelManager;
|
||||
_userViewManager = userViewManager;
|
||||
_profile = profile;
|
||||
_config = config;
|
||||
|
||||
|
@ -450,7 +453,22 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
|||
sortOrders.Add(ItemSortBy.SortName);
|
||||
}
|
||||
|
||||
var queryResult = await folder.GetItems(new InternalItemsQuery
|
||||
QueryResult<BaseItem> queryResult;
|
||||
|
||||
if (folder is UserRootFolder)
|
||||
{
|
||||
var views = await _userViewManager.GetUserViews(new UserViewQuery { UserId = user.Id.ToString("N"), PresetViews = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Music } }, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
queryResult = new QueryResult<BaseItem>
|
||||
{
|
||||
Items = views.Cast<BaseItem>().ToArray()
|
||||
};
|
||||
queryResult.TotalRecordCount = queryResult.Items.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
queryResult = await folder.GetItems(new InternalItemsQuery
|
||||
{
|
||||
Limit = limit,
|
||||
StartIndex = startIndex,
|
||||
|
@ -460,6 +478,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
|||
Filter = FilterUnsupportedContent
|
||||
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var options = _config.GetDlnaConfiguration();
|
||||
|
||||
|
@ -481,23 +500,17 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
|||
|
||||
private QueryResult<ServerItem> GetItemsFromPerson(Person person, User user, int? startIndex, int? limit)
|
||||
{
|
||||
var itemsWithPerson = _libraryManager.GetItems(new InternalItemsQuery
|
||||
var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
|
||||
{
|
||||
Person = person.Name
|
||||
Person = person.Name,
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Series).Name, typeof(ChannelVideoItem).Name },
|
||||
SortBy = new[] { ItemSortBy.SortName },
|
||||
Limit = limit,
|
||||
StartIndex = startIndex
|
||||
|
||||
}).Items;
|
||||
}, new string[] { });
|
||||
|
||||
var items = itemsWithPerson
|
||||
.Where(i => i is Movie || i is Series || i is IChannelItem)
|
||||
.Where(i => i.IsVisibleStandalone(user))
|
||||
.ToList();
|
||||
|
||||
items = _libraryManager.Sort(items, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending)
|
||||
.Skip(startIndex ?? 0)
|
||||
.Take(limit ?? int.MaxValue)
|
||||
.ToList();
|
||||
|
||||
var serverItems = items.Select(i => new ServerItem
|
||||
var serverItems = itemsResult.Items.Select(i => new ServerItem
|
||||
{
|
||||
Item = i,
|
||||
StubType = null
|
||||
|
@ -506,7 +519,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
|||
|
||||
return new QueryResult<ServerItem>
|
||||
{
|
||||
TotalRecordCount = serverItems.Length,
|
||||
TotalRecordCount = itemsResult.TotalRecordCount,
|
||||
Items = serverItems
|
||||
};
|
||||
}
|
||||
|
|
|
@ -966,7 +966,7 @@ namespace MediaBrowser.Dlna.Didl
|
|||
}
|
||||
}
|
||||
|
||||
item = item.Parents.FirstOrDefault(i => i.HasImage(ImageType.Primary));
|
||||
item = item.GetParents().FirstOrDefault(i => i.HasImage(ImageType.Primary));
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
|
|
|
@ -79,14 +79,11 @@
|
|||
<Compile Include="Providers\SeriesXmlProvider.cs" />
|
||||
<Compile Include="Providers\VideoXmlProvider.cs" />
|
||||
<Compile Include="Savers\BoxSetXmlSaver.cs" />
|
||||
<Compile Include="Savers\EpisodeXmlSaver.cs" />
|
||||
<Compile Include="Savers\FolderXmlSaver.cs" />
|
||||
<Compile Include="Savers\GameSystemXmlSaver.cs" />
|
||||
<Compile Include="Savers\GameXmlSaver.cs" />
|
||||
<Compile Include="Savers\MovieXmlSaver.cs" />
|
||||
<Compile Include="Savers\PersonXmlSaver.cs" />
|
||||
<Compile Include="Savers\PlaylistXmlSaver.cs" />
|
||||
<Compile Include="Savers\SeriesXmlSaver.cs" />
|
||||
<Compile Include="Savers\XmlSaverHelpers.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Common.IO;
|
||||
|
||||
namespace MediaBrowser.LocalMetadata.Savers
|
||||
{
|
||||
public class EpisodeXmlProvider : IMetadataFileSaver, IConfigurableProvider
|
||||
{
|
||||
private readonly IItemRepository _itemRepository;
|
||||
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private IFileSystem _fileSystem;
|
||||
|
||||
public EpisodeXmlProvider(IItemRepository itemRepository, IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem)
|
||||
{
|
||||
_itemRepository = itemRepository;
|
||||
_config = config;
|
||||
_libraryManager = libraryManager;
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether [is enabled for] [the specified item].
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="updateType">Type of the update.</param>
|
||||
/// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns>
|
||||
public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType)
|
||||
{
|
||||
if (!item.SupportsLocalMetadata)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return item is Episode && updateType >= ItemUpdateType.MetadataDownload;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return XmlProviderUtils.Name;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get { return !_config.Configuration.DisableXmlSavers; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the specified item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public void Save(IHasMetadata item, CancellationToken cancellationToken)
|
||||
{
|
||||
var episode = (Episode)item;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.Append("<Item>");
|
||||
|
||||
if (!string.IsNullOrEmpty(item.Name))
|
||||
{
|
||||
builder.Append("<EpisodeName>" + SecurityElement.Escape(episode.Name) + "</EpisodeName>");
|
||||
}
|
||||
|
||||
if (episode.IndexNumber.HasValue)
|
||||
{
|
||||
builder.Append("<EpisodeNumber>" + SecurityElement.Escape(episode.IndexNumber.Value.ToString(_usCulture)) + "</EpisodeNumber>");
|
||||
}
|
||||
|
||||
if (episode.IndexNumberEnd.HasValue)
|
||||
{
|
||||
builder.Append("<EpisodeNumberEnd>" + SecurityElement.Escape(episode.IndexNumberEnd.Value.ToString(_usCulture)) + "</EpisodeNumberEnd>");
|
||||
}
|
||||
|
||||
if (episode.AirsAfterSeasonNumber.HasValue)
|
||||
{
|
||||
builder.Append("<airsafter_season>" + SecurityElement.Escape(episode.AirsAfterSeasonNumber.Value.ToString(_usCulture)) + "</airsafter_season>");
|
||||
}
|
||||
if (episode.AirsBeforeEpisodeNumber.HasValue)
|
||||
{
|
||||
builder.Append("<airsbefore_episode>" + SecurityElement.Escape(episode.AirsBeforeEpisodeNumber.Value.ToString(_usCulture)) + "</airsbefore_episode>");
|
||||
}
|
||||
if (episode.AirsBeforeSeasonNumber.HasValue)
|
||||
{
|
||||
builder.Append("<airsbefore_season>" + SecurityElement.Escape(episode.AirsBeforeSeasonNumber.Value.ToString(_usCulture)) + "</airsbefore_season>");
|
||||
}
|
||||
|
||||
if (episode.ParentIndexNumber.HasValue)
|
||||
{
|
||||
builder.Append("<SeasonNumber>" + SecurityElement.Escape(episode.ParentIndexNumber.Value.ToString(_usCulture)) + "</SeasonNumber>");
|
||||
}
|
||||
|
||||
if (episode.AbsoluteEpisodeNumber.HasValue)
|
||||
{
|
||||
builder.Append("<absolute_number>" + SecurityElement.Escape(episode.AbsoluteEpisodeNumber.Value.ToString(_usCulture)) + "</absolute_number>");
|
||||
}
|
||||
|
||||
if (episode.DvdEpisodeNumber.HasValue)
|
||||
{
|
||||
builder.Append("<DVD_episodenumber>" + SecurityElement.Escape(episode.DvdEpisodeNumber.Value.ToString(_usCulture)) + "</DVD_episodenumber>");
|
||||
}
|
||||
|
||||
if (episode.DvdSeasonNumber.HasValue)
|
||||
{
|
||||
builder.Append("<DVD_season>" + SecurityElement.Escape(episode.DvdSeasonNumber.Value.ToString(_usCulture)) + "</DVD_season>");
|
||||
}
|
||||
|
||||
if (episode.PremiereDate.HasValue)
|
||||
{
|
||||
builder.Append("<FirstAired>" + SecurityElement.Escape(episode.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")) + "</FirstAired>");
|
||||
}
|
||||
|
||||
XmlSaverHelpers.AddCommonNodes(episode, _libraryManager, builder);
|
||||
XmlSaverHelpers.AddMediaInfo(episode, builder, _itemRepository);
|
||||
|
||||
builder.Append("</Item>");
|
||||
|
||||
var xmlFilePath = GetSavePath(item);
|
||||
|
||||
XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
|
||||
{
|
||||
"FirstAired",
|
||||
"SeasonNumber",
|
||||
"EpisodeNumber",
|
||||
"EpisodeName",
|
||||
"EpisodeNumberEnd",
|
||||
"airsafter_season",
|
||||
"airsbefore_episode",
|
||||
"airsbefore_season",
|
||||
"DVD_episodenumber",
|
||||
"DVD_season",
|
||||
"absolute_number"
|
||||
|
||||
}, _config, _fileSystem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the save path.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
public string GetSavePath(IHasMetadata item)
|
||||
{
|
||||
var filename = Path.ChangeExtension(Path.GetFileName(item.Path), ".xml");
|
||||
|
||||
return Path.Combine(Path.GetDirectoryName(item.Path), "metadata", filename);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Common.IO;
|
||||
|
||||
namespace MediaBrowser.LocalMetadata.Savers
|
||||
{
|
||||
/// <summary>
|
||||
/// Saves movie.xml for movies, trailers and music videos
|
||||
/// </summary>
|
||||
public class MovieXmlProvider : IMetadataFileSaver, IConfigurableProvider
|
||||
{
|
||||
private readonly IItemRepository _itemRepository;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private IFileSystem _fileSystem;
|
||||
|
||||
public MovieXmlProvider(IItemRepository itemRepository, IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem)
|
||||
{
|
||||
_itemRepository = itemRepository;
|
||||
_config = config;
|
||||
_libraryManager = libraryManager;
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return XmlProviderUtils.Name;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get { return !_config.Configuration.DisableXmlSavers; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether [is enabled for] [the specified item].
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="updateType">Type of the update.</param>
|
||||
/// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns>
|
||||
public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType)
|
||||
{
|
||||
if (!item.SupportsLocalMetadata)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var video = item as Video;
|
||||
|
||||
// Check parent for null to avoid running this against things like video backdrops
|
||||
if (video != null && !(item is Episode) && !video.IsOwnedItem)
|
||||
{
|
||||
return updateType >= ItemUpdateType.MetadataDownload;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the specified item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public void Save(IHasMetadata item, CancellationToken cancellationToken)
|
||||
{
|
||||
var video = (Video)item;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.Append("<Title>");
|
||||
|
||||
XmlSaverHelpers.AddCommonNodes(video, _libraryManager, builder);
|
||||
|
||||
var musicVideo = item as MusicVideo;
|
||||
|
||||
if (musicVideo != null)
|
||||
{
|
||||
if (musicVideo.Artists.Count > 0)
|
||||
{
|
||||
builder.Append("<Artist>" + SecurityElement.Escape(string.Join(";", musicVideo.Artists.ToArray())) + "</Artist>");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(musicVideo.Album))
|
||||
{
|
||||
builder.Append("<Album>" + SecurityElement.Escape(musicVideo.Album) + "</Album>");
|
||||
}
|
||||
}
|
||||
|
||||
var movie = item as Movie;
|
||||
|
||||
if (movie != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(movie.TmdbCollectionName))
|
||||
{
|
||||
builder.Append("<TmdbCollectionName>" + SecurityElement.Escape(movie.TmdbCollectionName) + "</TmdbCollectionName>");
|
||||
}
|
||||
}
|
||||
|
||||
XmlSaverHelpers.AddMediaInfo(video, builder, _itemRepository);
|
||||
|
||||
builder.Append("</Title>");
|
||||
|
||||
var xmlFilePath = GetSavePath(item);
|
||||
|
||||
XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
|
||||
{
|
||||
// Deprecated. No longer saving in this field.
|
||||
"IMDBrating",
|
||||
|
||||
// Deprecated. No longer saving in this field.
|
||||
"Description",
|
||||
|
||||
"Artist",
|
||||
"Album",
|
||||
"TmdbCollectionName"
|
||||
}, _config, _fileSystem);
|
||||
}
|
||||
|
||||
public string GetSavePath(IHasMetadata item)
|
||||
{
|
||||
return GetMovieSavePath((Video)item);
|
||||
}
|
||||
|
||||
public static string GetMovieSavePath(Video item)
|
||||
{
|
||||
if (item.IsInMixedFolder)
|
||||
{
|
||||
return Path.ChangeExtension(item.Path, ".xml");
|
||||
}
|
||||
|
||||
return Path.Combine(item.ContainingFolderPath, "movie.xml");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,154 +0,0 @@
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Common.IO;
|
||||
|
||||
namespace MediaBrowser.LocalMetadata.Savers
|
||||
{
|
||||
public class SeriesXmlProvider : IMetadataFileSaver, IConfigurableProvider
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private IFileSystem _fileSystem;
|
||||
|
||||
public SeriesXmlProvider(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem)
|
||||
{
|
||||
_config = config;
|
||||
_libraryManager = libraryManager;
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return XmlProviderUtils.Name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether [is enabled for] [the specified item].
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="updateType">Type of the update.</param>
|
||||
/// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns>
|
||||
public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType)
|
||||
{
|
||||
if (!item.SupportsLocalMetadata)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return item is Series && updateType >= ItemUpdateType.MetadataDownload;
|
||||
}
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get { return !_config.Configuration.DisableXmlSavers; }
|
||||
}
|
||||
|
||||
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||
|
||||
/// <summary>
|
||||
/// Saves the specified item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public void Save(IHasMetadata item, CancellationToken cancellationToken)
|
||||
{
|
||||
var series = (Series)item;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.Append("<Series>");
|
||||
|
||||
var tvdb = item.GetProviderId(MetadataProviders.Tvdb);
|
||||
|
||||
if (!string.IsNullOrEmpty(tvdb))
|
||||
{
|
||||
builder.Append("<id>" + SecurityElement.Escape(tvdb) + "</id>");
|
||||
}
|
||||
|
||||
if (series.Status.HasValue)
|
||||
{
|
||||
builder.Append("<Status>" + SecurityElement.Escape(series.Status.Value.ToString()) + "</Status>");
|
||||
}
|
||||
|
||||
if (series.Studios.Count > 0)
|
||||
{
|
||||
builder.Append("<Network>" + SecurityElement.Escape(series.Studios[0]) + "</Network>");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(series.AirTime))
|
||||
{
|
||||
builder.Append("<Airs_Time>" + SecurityElement.Escape(series.AirTime) + "</Airs_Time>");
|
||||
}
|
||||
|
||||
if (series.AirDays != null)
|
||||
{
|
||||
if (series.AirDays.Count == 7)
|
||||
{
|
||||
builder.Append("<Airs_DayOfWeek>" + SecurityElement.Escape("Daily") + "</Airs_DayOfWeek>");
|
||||
}
|
||||
else if (series.AirDays.Count > 0)
|
||||
{
|
||||
builder.Append("<Airs_DayOfWeek>" + SecurityElement.Escape(series.AirDays[0].ToString()) + "</Airs_DayOfWeek>");
|
||||
}
|
||||
}
|
||||
|
||||
if (series.PremiereDate.HasValue)
|
||||
{
|
||||
builder.Append("<FirstAired>" + SecurityElement.Escape(series.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")) + "</FirstAired>");
|
||||
}
|
||||
|
||||
if (series.AnimeSeriesIndex.HasValue)
|
||||
{
|
||||
builder.Append("<AnimeSeriesIndex>" + SecurityElement.Escape(series.AnimeSeriesIndex.Value.ToString(UsCulture)) + "</AnimeSeriesIndex>");
|
||||
}
|
||||
|
||||
XmlSaverHelpers.AddCommonNodes(series, _libraryManager, builder);
|
||||
|
||||
builder.Append("</Series>");
|
||||
|
||||
var xmlFilePath = GetSavePath(item);
|
||||
|
||||
XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
|
||||
{
|
||||
"id",
|
||||
"Status",
|
||||
"Network",
|
||||
"Airs_Time",
|
||||
"Airs_DayOfWeek",
|
||||
"FirstAired",
|
||||
|
||||
// Don't preserve old series node
|
||||
"Series",
|
||||
|
||||
"SeriesName",
|
||||
|
||||
// Deprecated. No longer saving in this field.
|
||||
"AnimeSeriesIndex"
|
||||
}, _config, _fileSystem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the save path.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
public string GetSavePath(IHasMetadata item)
|
||||
{
|
||||
return Path.Combine(item.Path, "series.xml");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -122,10 +122,15 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
|||
var subtitle = await GetSubtitleStream(itemId, mediaSourceId, subtitleStreamIndex, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
using (var stream = subtitle.Item1)
|
||||
{
|
||||
var inputFormat = subtitle.Item2;
|
||||
|
||||
if (string.Equals(inputFormat, outputFormat, StringComparison.OrdinalIgnoreCase) && TryGetWriter(outputFormat) == null)
|
||||
{
|
||||
return subtitle.Item1;
|
||||
}
|
||||
|
||||
using (var stream = subtitle.Item1)
|
||||
{
|
||||
return await ConvertSubtitles(stream, inputFormat, outputFormat, startTimeTicks, endTimeTicks, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
@ -288,7 +293,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
|||
return null;
|
||||
}
|
||||
|
||||
private ISubtitleWriter GetWriter(string format)
|
||||
private ISubtitleWriter TryGetWriter(string format)
|
||||
{
|
||||
if (string.IsNullOrEmpty(format))
|
||||
{
|
||||
|
@ -312,6 +317,18 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
|||
return new TtmlWriter();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ISubtitleWriter GetWriter(string format)
|
||||
{
|
||||
var writer = TryGetWriter(format);
|
||||
|
||||
if (writer != null)
|
||||
{
|
||||
return writer;
|
||||
}
|
||||
|
||||
throw new ArgumentException("Unsupported format: " + format);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,16 +11,19 @@ namespace MediaBrowser.Model.Configuration
|
|||
public bool EnableIntrosParentalControl { get; set; }
|
||||
public bool EnableIntrosFromSimilarMovies { get; set; }
|
||||
public string CustomIntroPath { get; set; }
|
||||
public string MediaInfoIntroPath { get; set; }
|
||||
public bool EnableIntrosFromUpcomingDvdMovies { get; set; }
|
||||
public bool EnableIntrosFromUpcomingStreamingMovies { get; set; }
|
||||
|
||||
public int TrailerLimit { get; set; }
|
||||
public string[] Tags { get; set; }
|
||||
|
||||
public CinemaModeConfiguration()
|
||||
{
|
||||
EnableIntrosParentalControl = true;
|
||||
EnableIntrosFromSimilarMovies = true;
|
||||
TrailerLimit = 2;
|
||||
Tags = new[] { "thx" };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,12 @@ namespace MediaBrowser.Model.Configuration
|
|||
/// <value><c>true</c> if this instance is port authorized; otherwise, <c>false</c>.</value>
|
||||
public bool IsPortAuthorized { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [enable high quality image scaling].
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [enable high quality image scaling]; otherwise, <c>false</c>.</value>
|
||||
public bool EnableHighQualityImageScaling { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item by name path.
|
||||
/// </summary>
|
||||
|
@ -92,24 +98,6 @@ namespace MediaBrowser.Model.Configuration
|
|||
/// <value><c>true</c> if [enable localized guids]; otherwise, <c>false</c>.</value>
|
||||
public bool EnableLocalizedGuids { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [disable startup scan].
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [disable startup scan]; otherwise, <c>false</c>.</value>
|
||||
public bool DisableStartupScan { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [enable user views].
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [enable user views]; otherwise, <c>false</c>.</value>
|
||||
public bool EnableUserViews { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [enable library metadata sub folder].
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [enable library metadata sub folder]; otherwise, <c>false</c>.</value>
|
||||
public bool EnableLibraryMetadataSubFolder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the preferred metadata language.
|
||||
/// </summary>
|
||||
|
@ -219,15 +207,14 @@ namespace MediaBrowser.Model.Configuration
|
|||
|
||||
public int SharingExpirationDays { get; set; }
|
||||
|
||||
public bool DisableXmlSavers { get; set; }
|
||||
public bool EnableWindowsShortcuts { get; set; }
|
||||
|
||||
public bool EnableVideoFrameByFrameAnalysis { get; set; }
|
||||
|
||||
public bool EnableDateLastRefresh { get; set; }
|
||||
|
||||
public string[] Migrations { get; set; }
|
||||
|
||||
public int MigrationVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
|
||||
/// </summary>
|
||||
|
|
|
@ -359,12 +359,13 @@ namespace MediaBrowser.Providers.Manager
|
|||
private void ClearImages(IHasImages item, ImageType type)
|
||||
{
|
||||
var deleted = false;
|
||||
var deletedImages = new List<ItemImageInfo>();
|
||||
|
||||
foreach (var image in item.GetImages(type).ToList())
|
||||
{
|
||||
if (!image.IsLocalFile)
|
||||
{
|
||||
// TODO: Need to get this image removed
|
||||
deletedImages.Add(image);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -384,6 +385,11 @@ namespace MediaBrowser.Providers.Manager
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var image in deletedImages)
|
||||
{
|
||||
item.RemoveImage(image);
|
||||
}
|
||||
|
||||
if (deleted)
|
||||
{
|
||||
item.ValidateImages(new DirectoryService(_logger, _fileSystem));
|
||||
|
|
|
@ -1038,7 +1038,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
.ToList();
|
||||
|
||||
var musicArtists = albums
|
||||
.Select(i => i.Parent)
|
||||
.Select(i => i.GetParent())
|
||||
.OfType<MusicArtist>()
|
||||
.ToList();
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
|
@ -130,6 +131,8 @@ namespace MediaBrowser.Providers.Subtitles
|
|||
|
||||
try
|
||||
{
|
||||
//var isText = MediaStream.IsTextFormat(response.Format);
|
||||
|
||||
using (var fs = _fileSystem.GetFileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
|
||||
{
|
||||
await stream.CopyToAsync(fs).ConfigureAwait(false);
|
||||
|
|
|
@ -104,6 +104,11 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
.OrderBy(i => i.Name);
|
||||
}
|
||||
|
||||
public IEnumerable<Guid> GetInstalledChannelIds()
|
||||
{
|
||||
return GetAllChannels().Select(i => GetInternalChannelId(i.Name));
|
||||
}
|
||||
|
||||
public Task<QueryResult<Channel>> GetChannelsInternal(ChannelQuery query, CancellationToken cancellationToken)
|
||||
{
|
||||
var user = string.IsNullOrWhiteSpace(query.UserId)
|
||||
|
@ -408,25 +413,15 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
|
||||
private async Task<Channel> GetChannel(IChannel channelInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
var parentFolder = await GetInternalChannelFolder(cancellationToken).ConfigureAwait(false);
|
||||
var parentFolderId = parentFolder.Id;
|
||||
|
||||
var id = GetInternalChannelId(channelInfo.Name);
|
||||
|
||||
var path = Channel.GetInternalMetadataPath(_config.ApplicationPaths.InternalMetadataPath, id);
|
||||
|
||||
var isNew = false;
|
||||
|
||||
if (!_fileSystem.DirectoryExists(path))
|
||||
{
|
||||
_logger.Debug("Creating directory {0}", path);
|
||||
|
||||
_fileSystem.CreateDirectory(path);
|
||||
|
||||
if (!_fileSystem.DirectoryExists(path))
|
||||
{
|
||||
throw new IOException("Path not created: " + path);
|
||||
}
|
||||
|
||||
isNew = true;
|
||||
}
|
||||
var forceUpdate = false;
|
||||
|
||||
var item = _libraryManager.GetItemById(id) as Channel;
|
||||
var channelId = channelInfo.Name.GetMD5().ToString("N");
|
||||
|
@ -438,18 +433,29 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
Name = channelInfo.Name,
|
||||
Id = id,
|
||||
DateCreated = _fileSystem.GetCreationTimeUtc(path),
|
||||
DateModified = _fileSystem.GetLastWriteTimeUtc(path),
|
||||
Path = path,
|
||||
ChannelId = channelId
|
||||
DateModified = _fileSystem.GetLastWriteTimeUtc(path)
|
||||
};
|
||||
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
if (!string.Equals(item.ChannelId, channelId, StringComparison.OrdinalIgnoreCase))
|
||||
if (!string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
isNew = true;
|
||||
}
|
||||
item.Path = path;
|
||||
|
||||
if (!string.Equals(item.ChannelId, channelId, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
forceUpdate = true;
|
||||
}
|
||||
item.ChannelId = channelId;
|
||||
|
||||
if (item.ParentId != parentFolderId)
|
||||
{
|
||||
forceUpdate = true;
|
||||
}
|
||||
item.ParentId = parentFolderId;
|
||||
|
||||
item.OfficialRating = GetOfficialRating(channelInfo.ParentalRating);
|
||||
item.Overview = channelInfo.Description;
|
||||
|
@ -460,12 +466,16 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
item.Name = channelInfo.Name;
|
||||
}
|
||||
|
||||
await item.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
|
||||
if (isNew)
|
||||
{
|
||||
ForceSave = isNew
|
||||
|
||||
}, cancellationToken);
|
||||
await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else if (forceUpdate)
|
||||
{
|
||||
await item.UpdateToRepository(ItemUpdateType.None, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await item.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), cancellationToken);
|
||||
return item;
|
||||
}
|
||||
|
||||
|
@ -1225,6 +1235,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
{
|
||||
BaseItem item;
|
||||
bool isNew;
|
||||
bool forceUpdate = false;
|
||||
|
||||
if (info.Type == ChannelItemType.Folder)
|
||||
{
|
||||
|
@ -1254,25 +1265,26 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
item.ProductionYear = info.ProductionYear;
|
||||
item.ProviderIds = info.ProviderIds;
|
||||
item.OfficialRating = info.OfficialRating;
|
||||
|
||||
item.DateCreated = info.DateCreated ?? DateTime.UtcNow;
|
||||
item.Tags = info.Tags;
|
||||
}
|
||||
|
||||
var channelItem = (IChannelItem)item;
|
||||
|
||||
channelItem.ChannelId = internalChannelId.ToString("N");
|
||||
|
||||
if (item.ParentId != internalChannelId)
|
||||
{
|
||||
forceUpdate = true;
|
||||
}
|
||||
item.ParentId = internalChannelId;
|
||||
|
||||
if (!string.Equals(channelItem.ExternalId, info.Id, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
isNew = true;
|
||||
forceUpdate = true;
|
||||
}
|
||||
channelItem.ExternalId = info.Id;
|
||||
|
||||
if (isNew)
|
||||
{
|
||||
channelItem.Tags = info.Tags;
|
||||
}
|
||||
|
||||
var channelMediaItem = item as IChannelMediaItem;
|
||||
|
||||
if (channelMediaItem != null)
|
||||
|
@ -1300,6 +1312,10 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
await _libraryManager.UpdatePeople(item, info.People ?? new List<PersonInfo>()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else if (forceUpdate)
|
||||
{
|
||||
await item.UpdateToRepository(ItemUpdateType.None, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
|
|
@ -123,15 +123,15 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
|
||||
private async Task CleanDatabase(CancellationToken cancellationToken)
|
||||
{
|
||||
var allChannels = await _channelManager.GetChannelsInternal(new ChannelQuery { }, cancellationToken);
|
||||
var installedChannelIds = ((ChannelManager)_channelManager).GetInstalledChannelIds();
|
||||
|
||||
var allIds = _libraryManager.GetItemIds(new InternalItemsQuery
|
||||
var databaseIds = _libraryManager.GetItemIds(new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Channel).Name }
|
||||
});
|
||||
|
||||
var invalidIds = allIds
|
||||
.Except(allChannels.Items.Select(i => i.Id).ToList())
|
||||
var invalidIds = databaseIds
|
||||
.Except(installedChannelIds)
|
||||
.ToList();
|
||||
|
||||
foreach (var id in invalidIds)
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace MediaBrowser.Server.Implementations.Collections
|
|||
return subItem;
|
||||
}
|
||||
|
||||
var parent = subItem.Parent;
|
||||
var parent = subItem.GetParent();
|
||||
|
||||
if (parent != null && parent.HasImage(ImageType.Primary))
|
||||
{
|
||||
|
@ -78,24 +78,9 @@ namespace MediaBrowser.Server.Implementations.Collections
|
|||
return Task.FromResult(GetFinalItems(items, 2));
|
||||
}
|
||||
|
||||
protected override async Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
|
||||
protected override Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
|
||||
{
|
||||
var image = itemsWithImages
|
||||
.Where(i => i.HasImage(ImageType.Primary) && i.GetImageInfo(ImageType.Primary, 0).IsLocalFile && Path.HasExtension(i.GetImagePath(ImageType.Primary)))
|
||||
.Select(i => i.GetImagePath(ImageType.Primary))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(image))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ext = Path.GetExtension(image);
|
||||
|
||||
var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ext);
|
||||
File.Copy(image, outputPath);
|
||||
|
||||
return outputPath;
|
||||
return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace MediaBrowser.Server.Implementations.Collections
|
|||
public Folder GetCollectionsFolder(string userId)
|
||||
{
|
||||
return _libraryManager.RootFolder.Children.OfType<ManualCollectionsFolder>()
|
||||
.FirstOrDefault() ?? _libraryManager.GetUserRootFolder().Children.OfType<ManualCollectionsFolder>()
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.Linq;
|
|||
|
||||
namespace MediaBrowser.Server.Implementations.Collections
|
||||
{
|
||||
public class ManualCollectionsFolder : BasePluginFolder
|
||||
public class ManualCollectionsFolder : BasePluginFolder, IHiddenFromDisplay
|
||||
{
|
||||
public ManualCollectionsFolder()
|
||||
{
|
||||
|
@ -11,11 +11,6 @@ namespace MediaBrowser.Server.Implementations.Collections
|
|||
DisplayMediaType = "CollectionFolder";
|
||||
}
|
||||
|
||||
public override bool IsVisible(User user)
|
||||
{
|
||||
return base.IsVisible(user) && GetChildren(user, false).Any();
|
||||
}
|
||||
|
||||
public override bool IsHidden
|
||||
{
|
||||
get
|
||||
|
@ -24,7 +19,7 @@ namespace MediaBrowser.Server.Implementations.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public override bool IsHiddenFromUser(User user)
|
||||
public bool IsHiddenFromUser(User user)
|
||||
{
|
||||
return !user.Configuration.DisplayCollectionsView;
|
||||
}
|
||||
|
|
|
@ -171,12 +171,36 @@ namespace MediaBrowser.Server.Implementations.Configuration
|
|||
ValidateItemByNamePath(newConfig);
|
||||
ValidatePathSubstitutions(newConfig);
|
||||
ValidateMetadataPath(newConfig);
|
||||
ValidateSslCertificate(newConfig);
|
||||
|
||||
EventHelper.FireEventIfNotNull(ConfigurationUpdating, this, new GenericEventArgs<ServerConfiguration> { Argument = newConfig }, Logger);
|
||||
|
||||
base.ReplaceConfiguration(newConfiguration);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Validates the SSL certificate.
|
||||
/// </summary>
|
||||
/// <param name="newConfig">The new configuration.</param>
|
||||
/// <exception cref="System.IO.DirectoryNotFoundException"></exception>
|
||||
private void ValidateSslCertificate(BaseApplicationConfiguration newConfig)
|
||||
{
|
||||
var serverConfig = (ServerConfiguration)newConfig;
|
||||
|
||||
var newPath = serverConfig.CertificatePath;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(newPath)
|
||||
&& !string.Equals(Configuration.CertificatePath ?? string.Empty, newPath))
|
||||
{
|
||||
// Validate
|
||||
if (!FileSystem.FileExists(newPath))
|
||||
{
|
||||
throw new FileNotFoundException(string.Format("Certificate file '{0}' does not exist.", newPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidatePathSubstitutions(ServerConfiguration newConfig)
|
||||
{
|
||||
foreach (var map in newConfig.PathSubstitutions)
|
||||
|
|
|
@ -3,12 +3,15 @@ using MediaBrowser.Controller.Entities;
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Devices
|
||||
{
|
||||
public class CameraUploadsFolder : BasePluginFolder
|
||||
public class CameraUploadsFolder : BasePluginFolder, ISupportsUserSpecificView
|
||||
{
|
||||
public CameraUploadsFolder()
|
||||
{
|
||||
|
@ -22,21 +25,7 @@ namespace MediaBrowser.Server.Implementations.Devices
|
|||
return false;
|
||||
}
|
||||
|
||||
return GetChildren(user, true).Any() &&
|
||||
base.IsVisible(user);
|
||||
}
|
||||
|
||||
public override bool IsHidden
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.IsHidden || !Children.Any();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsHiddenFromUser(User user)
|
||||
{
|
||||
return false;
|
||||
return base.IsVisible(user) && HasChildren();
|
||||
}
|
||||
|
||||
public override string CollectionType
|
||||
|
@ -48,6 +37,29 @@ namespace MediaBrowser.Server.Implementations.Devices
|
|||
{
|
||||
return typeof(CollectionFolder).Name;
|
||||
}
|
||||
|
||||
private bool? _hasChildren;
|
||||
private bool HasChildren()
|
||||
{
|
||||
if (!_hasChildren.HasValue)
|
||||
{
|
||||
_hasChildren = LibraryManager.GetItemIds(new InternalItemsQuery { ParentId = Id }).Count > 0;
|
||||
}
|
||||
|
||||
return _hasChildren.Value;
|
||||
}
|
||||
|
||||
protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
|
||||
{
|
||||
_hasChildren = null;
|
||||
return base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService);
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public bool EnableUserSpecificView
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
}
|
||||
|
||||
public class CameraUploadsDynamicFolder : IVirtualFolderCreator
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
@ -18,6 +17,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Devices
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ namespace MediaBrowser.Server.Implementations.Devices
|
|||
private readonly IUserManager _userManager;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ILibraryMonitor _libraryMonitor;
|
||||
private readonly IConfigurationManager _config;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly ILogger _logger;
|
||||
private readonly INetworkManager _network;
|
||||
|
||||
|
@ -38,7 +38,7 @@ namespace MediaBrowser.Server.Implementations.Devices
|
|||
/// </summary>
|
||||
public event EventHandler<GenericEventArgs<DeviceInfo>> DeviceOptionsUpdated;
|
||||
|
||||
public DeviceManager(IDeviceRepository repo, IUserManager userManager, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IConfigurationManager config, ILogger logger, INetworkManager network)
|
||||
public DeviceManager(IDeviceRepository repo, IUserManager userManager, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IServerConfigurationManager config, ILogger logger, INetworkManager network)
|
||||
{
|
||||
_repo = repo;
|
||||
_userManager = userManager;
|
||||
|
@ -187,11 +187,6 @@ namespace MediaBrowser.Server.Implementations.Devices
|
|||
}
|
||||
}
|
||||
|
||||
private string GetUploadPath(string deviceId)
|
||||
{
|
||||
return GetUploadPath(GetDevice(deviceId));
|
||||
}
|
||||
|
||||
private string GetUploadPath(DeviceInfo device)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(device.CameraUploadPath))
|
||||
|
@ -205,7 +200,7 @@ namespace MediaBrowser.Server.Implementations.Devices
|
|||
return config.CameraUploadPath;
|
||||
}
|
||||
|
||||
var path = Path.Combine(_config.CommonApplicationPaths.DataPath, "camerauploads");
|
||||
var path = DefaultCameraUploadsPath;
|
||||
|
||||
if (config.EnableCameraUploadSubfolders)
|
||||
{
|
||||
|
@ -215,6 +210,11 @@ namespace MediaBrowser.Server.Implementations.Devices
|
|||
return path;
|
||||
}
|
||||
|
||||
private string DefaultCameraUploadsPath
|
||||
{
|
||||
get { return Path.Combine(_config.CommonApplicationPaths.DataPath, "camerauploads"); }
|
||||
}
|
||||
|
||||
public async Task UpdateDeviceInfo(string id, DeviceOptions options)
|
||||
{
|
||||
var device = GetDevice(id);
|
||||
|
|
|
@ -163,16 +163,11 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
|
||||
if (person != null)
|
||||
{
|
||||
var items = _libraryManager.GetItems(new InternalItemsQuery
|
||||
var items = _libraryManager.GetItems(new InternalItemsQuery(user)
|
||||
{
|
||||
Person = byName.Name
|
||||
|
||||
}).Items;
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
return items.Where(i => i.IsVisibleStandalone(user)).ToList();
|
||||
}
|
||||
}, new string[] { });
|
||||
|
||||
return items.ToList();
|
||||
}
|
||||
|
@ -361,6 +356,8 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
var collectionFolder = item as ICollectionFolder;
|
||||
if (collectionFolder != null)
|
||||
{
|
||||
dto.OriginalCollectionType = collectionFolder.CollectionType;
|
||||
|
||||
dto.CollectionType = user == null ?
|
||||
collectionFolder.CollectionType :
|
||||
collectionFolder.GetViewType(user);
|
||||
|
@ -468,14 +465,16 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
|
||||
var folder = (Folder)item;
|
||||
|
||||
if (!(folder is IChannelItem) && !(folder is Channel))
|
||||
{
|
||||
dto.ChildCount = GetChildCount(folder, user);
|
||||
|
||||
// These are just far too slow.
|
||||
// TODO: Disable for CollectionFolder
|
||||
if (!(folder is UserRootFolder) && !(folder is UserView))
|
||||
if (!(folder is UserRootFolder) && !(folder is UserView) && !(folder is ICollectionFolder))
|
||||
{
|
||||
SetSpecialCounts(folder, user, dto, fields, syncProgress);
|
||||
}
|
||||
}
|
||||
|
||||
dto.UserData.Played = dto.UserData.PlayedPercentage.HasValue && dto.UserData.PlayedPercentage.Value >= 100;
|
||||
}
|
||||
|
@ -815,7 +814,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
/// <returns>BaseItem.</returns>
|
||||
private BaseItem GetParentBackdropItem(BaseItem item, BaseItem owner)
|
||||
{
|
||||
var parent = item.Parent ?? owner;
|
||||
var parent = item.GetParent() ?? owner;
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
|
@ -824,7 +823,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
return parent;
|
||||
}
|
||||
|
||||
parent = parent.Parent;
|
||||
parent = parent.GetParent();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -839,7 +838,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
/// <returns>BaseItem.</returns>
|
||||
private BaseItem GetParentImageItem(BaseItem item, ImageType type, BaseItem owner)
|
||||
{
|
||||
var parent = item.Parent ?? owner;
|
||||
var parent = item.GetParent() ?? owner;
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
|
@ -848,7 +847,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
return parent;
|
||||
}
|
||||
|
||||
parent = parent.Parent;
|
||||
parent = parent.GetParent();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -1042,7 +1041,11 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
dto.IsFolder = item.IsFolder;
|
||||
dto.MediaType = item.MediaType;
|
||||
dto.LocationType = item.LocationType;
|
||||
if (item.IsHD.HasValue && item.IsHD.Value)
|
||||
{
|
||||
dto.IsHD = item.IsHD;
|
||||
}
|
||||
dto.Audio = item.Audio;
|
||||
|
||||
dto.PreferredMetadataCountryCode = item.PreferredMetadataCountryCode;
|
||||
dto.PreferredMetadataLanguage = item.PreferredMetadataLanguage;
|
||||
|
@ -1209,15 +1212,15 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
dto.VoteCount = item.VoteCount;
|
||||
}
|
||||
|
||||
if (item.IsFolder)
|
||||
{
|
||||
var folder = (Folder)item;
|
||||
//if (item.IsFolder)
|
||||
//{
|
||||
// var folder = (Folder)item;
|
||||
|
||||
if (fields.Contains(ItemFields.IndexOptions))
|
||||
{
|
||||
dto.IndexOptions = folder.IndexByOptionStrings.ToArray();
|
||||
}
|
||||
}
|
||||
// if (fields.Contains(ItemFields.IndexOptions))
|
||||
// {
|
||||
// dto.IndexOptions = folder.IndexByOptionStrings.ToArray();
|
||||
// }
|
||||
//}
|
||||
|
||||
var supportsPlaceHolders = item as ISupportsPlaceHolders;
|
||||
if (supportsPlaceHolders != null)
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
|||
// Go up one level for indicators
|
||||
if (baseItem != null)
|
||||
{
|
||||
var parent = baseItem.Parent;
|
||||
var parent = baseItem.GetParent();
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
|
|
|
@ -217,7 +217,7 @@ namespace MediaBrowser.Server.Implementations.IO
|
|||
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
|
||||
void LibraryManager_ItemRemoved(object sender, ItemChangeEventArgs e)
|
||||
{
|
||||
if (e.Item.Parent is AggregateFolder)
|
||||
if (e.Item.GetParent() is AggregateFolder)
|
||||
{
|
||||
StopWatchingPath(e.Item.Path);
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ namespace MediaBrowser.Server.Implementations.IO
|
|||
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
|
||||
void LibraryManager_ItemAdded(object sender, ItemChangeEventArgs e)
|
||||
{
|
||||
if (e.Item.Parent is AggregateFolder)
|
||||
if (e.Item.GetParent() is AggregateFolder)
|
||||
{
|
||||
StartWatchingPath(e.Item.Path);
|
||||
}
|
||||
|
@ -532,9 +532,16 @@ namespace MediaBrowser.Server.Implementations.IO
|
|||
return false;
|
||||
}
|
||||
|
||||
// In order to determine if the file is being written to, we have to request write access
|
||||
// But if the server only has readonly access, this is going to cause this entire algorithm to fail
|
||||
// So we'll take a best guess about our access level
|
||||
var requestedFileAccess = ConfigurationManager.Configuration.SaveLocalMeta
|
||||
? FileAccess.ReadWrite
|
||||
: FileAccess.Read;
|
||||
|
||||
try
|
||||
{
|
||||
using (_fileSystem.GetFileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
|
||||
using (_fileSystem.GetFileStream(path, FileMode.Open, requestedFileAccess, FileShare.ReadWrite))
|
||||
{
|
||||
if (_updateTimer != null)
|
||||
{
|
||||
|
@ -651,7 +658,7 @@ namespace MediaBrowser.Server.Implementations.IO
|
|||
// If the item has been deleted find the first valid parent that still exists
|
||||
while (!_fileSystem.DirectoryExists(item.Path) && !_fileSystem.FileExists(item.Path))
|
||||
{
|
||||
item = item.Parent;
|
||||
item = item.GetParent();
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
|
|
|
@ -78,13 +78,11 @@ namespace MediaBrowser.Server.Implementations.Intros
|
|||
|
||||
if (config.EnableIntrosFromMoviesInLibrary)
|
||||
{
|
||||
var inputItems = _libraryManager.GetItems(new InternalItemsQuery
|
||||
var inputItems = _libraryManager.GetItems(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name },
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name }
|
||||
|
||||
User = user
|
||||
|
||||
}).Items;
|
||||
}, new string[]{});
|
||||
|
||||
var itemsWithTrailers = inputItems
|
||||
.Where(i =>
|
||||
|
@ -163,7 +161,7 @@ namespace MediaBrowser.Server.Implementations.Intros
|
|||
private IEnumerable<IntroInfo> GetResult(BaseItem item, IEnumerable<ItemWithTrailer> candidates, CinemaModeConfiguration config, int? ratingLevel)
|
||||
{
|
||||
var customIntros = !string.IsNullOrWhiteSpace(config.CustomIntroPath) ?
|
||||
GetCustomIntros(item) :
|
||||
GetCustomIntros(config) :
|
||||
new List<IntroInfo>();
|
||||
|
||||
var trailerLimit = config.TrailerLimit;
|
||||
|
@ -212,11 +210,11 @@ namespace MediaBrowser.Server.Implementations.Intros
|
|||
return _serverConfig.GetConfiguration<CinemaModeConfiguration>("cinemamode");
|
||||
}
|
||||
|
||||
private List<IntroInfo> GetCustomIntros(BaseItem item)
|
||||
private List<IntroInfo> GetCustomIntros(CinemaModeConfiguration options)
|
||||
{
|
||||
try
|
||||
{
|
||||
return GetCustomIntroFiles()
|
||||
return GetCustomIntroFiles(options, true, false)
|
||||
.OrderBy(i => Guid.NewGuid())
|
||||
.Select(i => new IntroInfo
|
||||
{
|
||||
|
@ -230,17 +228,23 @@ namespace MediaBrowser.Server.Implementations.Intros
|
|||
}
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetCustomIntroFiles(CinemaModeConfiguration options = null)
|
||||
private IEnumerable<string> GetCustomIntroFiles(CinemaModeConfiguration options, bool enableCustomIntros, bool enableMediaInfoIntros)
|
||||
{
|
||||
options = options ?? GetOptions();
|
||||
var list = new List<string>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.CustomIntroPath))
|
||||
if (enableCustomIntros && !string.IsNullOrWhiteSpace(options.CustomIntroPath))
|
||||
{
|
||||
return new List<string>();
|
||||
list.AddRange(_fileSystem.GetFilePaths(options.CustomIntroPath, true)
|
||||
.Where(_libraryManager.IsVideoFile));
|
||||
}
|
||||
|
||||
return _fileSystem.GetFilePaths(options.CustomIntroPath, true)
|
||||
.Where(_libraryManager.IsVideoFile);
|
||||
if (enableMediaInfoIntros && !string.IsNullOrWhiteSpace(options.MediaInfoIntroPath))
|
||||
{
|
||||
list.AddRange(_fileSystem.GetFilePaths(options.MediaInfoIntroPath, true)
|
||||
.Where(_libraryManager.IsVideoFile));
|
||||
}
|
||||
|
||||
return list.Distinct(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private bool FilterByParentalRating(int? ratingLevel, BaseItem item)
|
||||
|
@ -341,7 +345,7 @@ namespace MediaBrowser.Server.Implementations.Intros
|
|||
|
||||
public IEnumerable<string> GetAllIntroFiles()
|
||||
{
|
||||
return GetCustomIntroFiles();
|
||||
return GetCustomIntroFiles(GetOptions(), true, true);
|
||||
}
|
||||
|
||||
private bool IsSupporter
|
||||
|
|
|
@ -47,11 +47,14 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
/// <summary>
|
||||
/// Shoulds the ignore.
|
||||
/// </summary>
|
||||
/// <param name="args">The args.</param>
|
||||
/// <param name="fileInfo">The file information.</param>
|
||||
/// <param name="parent">The parent.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
public bool ShouldIgnore(ItemResolveArgs args)
|
||||
public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent)
|
||||
{
|
||||
var filename = args.FileInfo.Name;
|
||||
var filename = fileInfo.Name;
|
||||
var isHidden = (fileInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
|
||||
var path = fileInfo.FullName;
|
||||
|
||||
// Handle mac .DS_Store
|
||||
// https://github.com/MediaBrowser/MediaBrowser/issues/427
|
||||
|
@ -61,9 +64,11 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
}
|
||||
|
||||
// Ignore hidden files and folders
|
||||
if (args.IsHidden)
|
||||
if (isHidden)
|
||||
{
|
||||
var parentFolderName = Path.GetFileName(Path.GetDirectoryName(args.Path));
|
||||
if (parent == null)
|
||||
{
|
||||
var parentFolderName = Path.GetFileName(Path.GetDirectoryName(path));
|
||||
|
||||
if (string.Equals(parentFolderName, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
@ -73,9 +78,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Sometimes these are marked hidden
|
||||
if (_fileSystem.IsRootPath(args.Path))
|
||||
if (_fileSystem.IsRootPath(path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -83,7 +89,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
return true;
|
||||
}
|
||||
|
||||
if (args.IsDirectory)
|
||||
if (fileInfo.IsDirectory)
|
||||
{
|
||||
// Ignore any folders in our list
|
||||
if (IgnoreFolders.Contains(filename, StringComparer.OrdinalIgnoreCase))
|
||||
|
@ -91,9 +97,11 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
return true;
|
||||
}
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
// Ignore trailer folders but allow it at the collection level
|
||||
if (string.Equals(filename, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase) &&
|
||||
!(args.Parent is AggregateFolder) && !(args.Parent is UserRootFolder))
|
||||
!(parent is AggregateFolder) && !(parent is UserRootFolder))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -108,9 +116,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (args.Parent != null)
|
||||
if (parent != null)
|
||||
{
|
||||
// Don't resolve these into audio files
|
||||
if (string.Equals(_fileSystem.GetFileNameWithoutExtension(filename), BaseItem.ThemeSongFilename) && _libraryManager.IsAudioFile(filename))
|
||||
|
|
|
@ -27,6 +27,7 @@ using MediaBrowser.Server.Implementations.Library.Validators;
|
|||
using MediaBrowser.Server.Implementations.Logging;
|
||||
using MediaBrowser.Server.Implementations.ScheduledTasks;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
@ -36,6 +37,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Model.Library;
|
||||
using MoreLinq;
|
||||
using SortOrder = MediaBrowser.Model.Entities.SortOrder;
|
||||
|
||||
|
@ -140,6 +142,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
|
||||
private readonly Func<IProviderManager> _providerManagerFactory;
|
||||
private readonly Func<IUserViewManager> _userviewManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _library items cache
|
||||
|
@ -167,7 +170,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
/// <param name="userManager">The user manager.</param>
|
||||
/// <param name="configurationManager">The configuration manager.</param>
|
||||
/// <param name="userDataRepository">The user data repository.</param>
|
||||
public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager, IUserDataManager userDataRepository, Func<ILibraryMonitor> libraryMonitorFactory, IFileSystem fileSystem, Func<IProviderManager> providerManagerFactory)
|
||||
public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager, IUserDataManager userDataRepository, Func<ILibraryMonitor> libraryMonitorFactory, IFileSystem fileSystem, Func<IProviderManager> providerManagerFactory, Func<IUserViewManager> userviewManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_taskManager = taskManager;
|
||||
|
@ -177,6 +180,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
_libraryMonitorFactory = libraryMonitorFactory;
|
||||
_fileSystem = fileSystem;
|
||||
_providerManagerFactory = providerManagerFactory;
|
||||
_userviewManager = userviewManager;
|
||||
ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>();
|
||||
_libraryItemsCache = new ConcurrentDictionary<Guid, BaseItem>();
|
||||
|
||||
|
@ -580,7 +584,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
};
|
||||
|
||||
// Return null if ignore rules deem that we should do so
|
||||
if (EntityResolutionIgnoreRules.Any(r => r.ShouldIgnore(args)))
|
||||
if (IgnoreFile(args.FileInfo, args.Parent))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -616,6 +620,11 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
return ResolveItem(args);
|
||||
}
|
||||
|
||||
public bool IgnoreFile(FileSystemMetadata file, BaseItem parent)
|
||||
{
|
||||
return EntityResolutionIgnoreRules.Any(r => r.ShouldIgnore(file, parent));
|
||||
}
|
||||
|
||||
public IEnumerable<FileSystemMetadata> NormalizeRootPathList(IEnumerable<FileSystemMetadata> paths)
|
||||
{
|
||||
var originalList = paths.ToList();
|
||||
|
@ -651,7 +660,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files, IDirectoryService directoryService, Folder parent, string collectionType)
|
||||
{
|
||||
var fileList = files.ToList();
|
||||
var fileList = files.Where(i => !IgnoreFile(i, parent)).ToList();
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
|
@ -732,6 +741,13 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
folder = dbItem;
|
||||
}
|
||||
|
||||
if (folder.ParentId != rootFolder.Id)
|
||||
{
|
||||
folder.ParentId = rootFolder.Id;
|
||||
var task = folder.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None);
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
rootFolder.AddVirtualChild(folder);
|
||||
|
||||
RegisterItem(folder);
|
||||
|
@ -1265,6 +1281,11 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
public QueryResult<BaseItem> GetItems(InternalItemsQuery query)
|
||||
{
|
||||
if (query.User != null)
|
||||
{
|
||||
AddUserToQuery(query, query.User);
|
||||
}
|
||||
|
||||
var result = ItemRepository.GetItemIdsList(query);
|
||||
|
||||
var items = result.Select(GetItemById).Where(i => i != null).ToArray();
|
||||
|
@ -1277,14 +1298,140 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
public QueryResult<BaseItem> QueryItems(InternalItemsQuery query)
|
||||
{
|
||||
if (query.User != null)
|
||||
{
|
||||
AddUserToQuery(query, query.User);
|
||||
}
|
||||
|
||||
return ItemRepository.GetItems(query);
|
||||
}
|
||||
|
||||
public List<Guid> GetItemIds(InternalItemsQuery query)
|
||||
{
|
||||
if (query.User != null)
|
||||
{
|
||||
AddUserToQuery(query, query.User);
|
||||
}
|
||||
|
||||
return ItemRepository.GetItemIdsList(query);
|
||||
}
|
||||
|
||||
public IEnumerable<BaseItem> GetItems(InternalItemsQuery query, IEnumerable<string> parentIds)
|
||||
{
|
||||
var parents = parentIds.Select(i => GetItemById(new Guid(i))).ToList();
|
||||
|
||||
SetTopParentIdsOrAncestors(query, parents);
|
||||
|
||||
return GetItemIds(query).Select(GetItemById);
|
||||
}
|
||||
|
||||
public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query, IEnumerable<string> parentIds)
|
||||
{
|
||||
var parents = parentIds.Select(i => GetItemById(new Guid(i))).ToList();
|
||||
|
||||
SetTopParentIdsOrAncestors(query, parents);
|
||||
|
||||
return GetItems(query);
|
||||
}
|
||||
|
||||
private void SetTopParentIdsOrAncestors(InternalItemsQuery query, List<BaseItem> parents)
|
||||
{
|
||||
if (parents.All(i =>
|
||||
{
|
||||
if ((i is ICollectionFolder) || (i is UserView))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
_logger.Debug("Query requires ancestor query due to type: " + i.GetType().Name);
|
||||
return false;
|
||||
|
||||
}))
|
||||
{
|
||||
// Optimize by querying against top level views
|
||||
query.TopParentIds = parents.SelectMany(i => GetTopParentsForQuery(i, query.User)).Select(i => i.Id.ToString("N")).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need to be able to query from any arbitrary ancestor up the tree
|
||||
query.AncestorIds = parents.SelectMany(i => i.GetIdsForAncestorQuery()).Select(i => i.ToString("N")).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private void AddUserToQuery(InternalItemsQuery query, User user)
|
||||
{
|
||||
if (query.AncestorIds.Length == 0 && !query.ParentId.HasValue && query.ChannelIds.Length == 0 && query.TopParentIds.Length == 0)
|
||||
{
|
||||
var userViews = _userviewManager().GetUserViews(new UserViewQuery
|
||||
{
|
||||
UserId = user.Id.ToString("N"),
|
||||
IncludeHidden = true
|
||||
|
||||
}, CancellationToken.None).Result.ToList();
|
||||
|
||||
query.TopParentIds = userViews.SelectMany(i => GetTopParentsForQuery(i, user)).Select(i => i.Id.ToString("N")).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<BaseItem> GetTopParentsForQuery(BaseItem item, User user)
|
||||
{
|
||||
var view = item as UserView;
|
||||
|
||||
if (view != null)
|
||||
{
|
||||
if (string.Equals(view.ViewType, CollectionType.LiveTv))
|
||||
{
|
||||
return new[] { view };
|
||||
}
|
||||
if (string.Equals(view.ViewType, CollectionType.Channels))
|
||||
{
|
||||
// TODO: Return channels
|
||||
return new[] { view };
|
||||
}
|
||||
|
||||
// Translate view into folders
|
||||
if (view.DisplayParentId != Guid.Empty)
|
||||
{
|
||||
var displayParent = GetItemById(view.DisplayParentId);
|
||||
if (displayParent != null)
|
||||
{
|
||||
return GetTopParentsForQuery(displayParent, user);
|
||||
}
|
||||
return new BaseItem[] { };
|
||||
}
|
||||
if (view.ParentId != Guid.Empty)
|
||||
{
|
||||
var displayParent = GetItemById(view.ParentId);
|
||||
if (displayParent != null)
|
||||
{
|
||||
return GetTopParentsForQuery(displayParent, user);
|
||||
}
|
||||
return new BaseItem[] { };
|
||||
}
|
||||
|
||||
// Handle grouping
|
||||
if (user != null && !string.IsNullOrWhiteSpace(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType))
|
||||
{
|
||||
var collectionFolders = user.RootFolder.GetChildren(user, true).OfType<CollectionFolder>().Where(i => string.IsNullOrWhiteSpace(i.CollectionType) || string.Equals(i.CollectionType, view.ViewType, StringComparison.OrdinalIgnoreCase));
|
||||
return collectionFolders.SelectMany(i => GetTopParentsForQuery(i, user));
|
||||
}
|
||||
return new BaseItem[] { };
|
||||
}
|
||||
|
||||
var collectionFolder = item as CollectionFolder;
|
||||
if (collectionFolder != null)
|
||||
{
|
||||
return collectionFolder.GetPhysicalParents();
|
||||
}
|
||||
|
||||
var topParent = item.GetTopParent();
|
||||
if (topParent != null)
|
||||
{
|
||||
return new[] { topParent };
|
||||
}
|
||||
return new BaseItem[] { };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the intros.
|
||||
/// </summary>
|
||||
|
@ -1577,9 +1724,9 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
public IEnumerable<Folder> GetCollectionFolders(BaseItem item)
|
||||
{
|
||||
while (!(item.Parent is AggregateFolder) && item.Parent != null)
|
||||
while (!(item.GetParent() is AggregateFolder) && item.GetParent() != null)
|
||||
{
|
||||
item = item.Parent;
|
||||
item = item.GetParent();
|
||||
}
|
||||
|
||||
if (item == null)
|
||||
|
@ -1616,7 +1763,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
return type;
|
||||
}
|
||||
|
||||
return item.Parents
|
||||
return item.GetParents()
|
||||
.Select(GetConfiguredContentType)
|
||||
.LastOrDefault(i => !string.IsNullOrWhiteSpace(i));
|
||||
}
|
||||
|
@ -1653,16 +1800,16 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
private string GetTopFolderContentType(BaseItem item)
|
||||
{
|
||||
while (!(item.Parent is AggregateFolder) && item.Parent != null)
|
||||
{
|
||||
item = item.Parent;
|
||||
}
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
while (!(item.GetParent() is AggregateFolder) && item.GetParent() != null)
|
||||
{
|
||||
item = item.GetParent();
|
||||
}
|
||||
|
||||
return GetUserRootFolder().Children
|
||||
.OfType<ICollectionFolder>()
|
||||
.Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path))
|
||||
|
@ -1679,7 +1826,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
string sortName,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return GetNamedViewInternal(user, name, null, viewType, sortName, null, cancellationToken);
|
||||
return GetNamedView(user, name, null, viewType, sortName, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<UserView> GetNamedView(string name,
|
||||
|
@ -1697,8 +1844,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
var refresh = false;
|
||||
|
||||
if (item == null ||
|
||||
!string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase))
|
||||
if (item == null || !string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_fileSystem.CreateDirectory(path);
|
||||
|
||||
|
@ -1717,12 +1863,6 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
refresh = true;
|
||||
}
|
||||
|
||||
if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
item.ViewType = viewType;
|
||||
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (!refresh)
|
||||
{
|
||||
refresh = (DateTime.UtcNow - item.DateLastRefreshed) >= _viewRefreshInterval;
|
||||
|
@ -1748,40 +1888,14 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
return item;
|
||||
}
|
||||
|
||||
public Task<UserView> GetNamedView(User user,
|
||||
public async Task<UserView> GetNamedView(User user,
|
||||
string name,
|
||||
string parentId,
|
||||
string viewType,
|
||||
string sortName,
|
||||
string uniqueId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(parentId))
|
||||
{
|
||||
throw new ArgumentNullException("parentId");
|
||||
}
|
||||
|
||||
return GetNamedViewInternal(user, name, parentId, viewType, sortName, uniqueId, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<UserView> GetNamedViewInternal(User user,
|
||||
string name,
|
||||
string parentId,
|
||||
string viewType,
|
||||
string sortName,
|
||||
string uniqueId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
throw new ArgumentNullException("name");
|
||||
}
|
||||
|
||||
var idValues = "37_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty);
|
||||
if (!string.IsNullOrWhiteSpace(uniqueId))
|
||||
{
|
||||
idValues += uniqueId;
|
||||
}
|
||||
var idValues = "38_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty) + (viewType ?? string.Empty);
|
||||
|
||||
var id = GetNewItemId(idValues, typeof(UserView));
|
||||
|
||||
|
@ -1816,18 +1930,6 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
isNew = true;
|
||||
}
|
||||
|
||||
if (!item.UserId.HasValue)
|
||||
{
|
||||
item.UserId = user.Id;
|
||||
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
item.ViewType = viewType;
|
||||
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var refresh = isNew || (DateTime.UtcNow - item.DateLastRefreshed) >= _viewRefreshInterval;
|
||||
|
||||
if (!refresh && item.DisplayParentId != Guid.Empty)
|
||||
|
@ -1851,7 +1953,6 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
public async Task<UserView> GetShadowView(BaseItem parent,
|
||||
string viewType,
|
||||
string sortName,
|
||||
string uniqueId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (parent == null)
|
||||
|
@ -1862,11 +1963,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
var name = parent.Name;
|
||||
var parentId = parent.Id;
|
||||
|
||||
var idValues = "37_namedview_" + name + parentId + (viewType ?? string.Empty);
|
||||
if (!string.IsNullOrWhiteSpace(uniqueId))
|
||||
{
|
||||
idValues += uniqueId;
|
||||
}
|
||||
var idValues = "38_namedview_" + name + parentId + (viewType ?? string.Empty);
|
||||
|
||||
var id = GetNewItemId(idValues, typeof(UserView));
|
||||
|
||||
|
@ -1897,12 +1994,6 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
isNew = true;
|
||||
}
|
||||
|
||||
if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
item.ViewType = viewType;
|
||||
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var refresh = isNew || (DateTime.UtcNow - item.DateLastRefreshed) >= _viewRefreshInterval;
|
||||
|
||||
if (!refresh && item.DisplayParentId != Guid.Empty)
|
||||
|
|
|
@ -80,15 +80,13 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
{
|
||||
var genreList = genres.ToList();
|
||||
|
||||
var inputItems = _libraryManager.GetItems(new InternalItemsQuery
|
||||
var inputItems = _libraryManager.GetItems(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Audio).Name },
|
||||
|
||||
Genres = genreList.ToArray(),
|
||||
Genres = genreList.ToArray()
|
||||
|
||||
User = user
|
||||
|
||||
}).Items;
|
||||
}, new string[] { });
|
||||
|
||||
var genresDictionary = genreList.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
item.Id = libraryManager.GetNewItemId(item.Path, item.GetType());
|
||||
|
||||
item.IsLocked = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
item.Parents.Any(i => i.IsLocked);
|
||||
item.GetParents().Any(i => i.IsLocked);
|
||||
|
||||
// Make sure DateCreated and DateModified have values
|
||||
var fileInfo = directoryService.GetFile(item.Path);
|
||||
|
@ -78,7 +78,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
EnsureName(item, args.FileInfo);
|
||||
|
||||
item.IsLocked = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
item.Parents.Any(i => i.IsLocked);
|
||||
item.GetParents().Any(i => i.IsLocked);
|
||||
|
||||
// Make sure DateCreated and DateModified have values
|
||||
EnsureDates(fileSystem, item, args, true);
|
||||
|
|
|
@ -67,7 +67,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
string collectionType,
|
||||
IDirectoryService directoryService)
|
||||
{
|
||||
if (IsInvalid(parent, collectionType, files))
|
||||
if (IsInvalid(parent, collectionType))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
return ResolveVideos<Video>(parent, files, directoryService, false);
|
||||
}
|
||||
|
||||
if (parent is Series || parent.Parents.OfType<Series>().Any())
|
||||
if (parent is Series || parent.GetParents().OfType<Series>().Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
{
|
||||
var collectionType = args.GetCollectionType();
|
||||
|
||||
if (IsInvalid(args.Parent, collectionType, args.FileSystemChildren))
|
||||
if (IsInvalid(args.Parent, collectionType))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -193,14 +193,18 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
// Find movies with their own folders
|
||||
if (args.IsDirectory)
|
||||
{
|
||||
var files = args.FileSystemChildren
|
||||
.Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
|
||||
.ToList();
|
||||
|
||||
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return FindMovie<MusicVideo>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType);
|
||||
return FindMovie<MusicVideo>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
|
||||
}
|
||||
|
||||
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType);
|
||||
return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(collectionType))
|
||||
|
@ -208,7 +212,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
// Owned items should just use the plain video type
|
||||
if (args.Parent == null)
|
||||
{
|
||||
return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType);
|
||||
return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
|
||||
}
|
||||
|
||||
if (args.HasParent<Series>())
|
||||
|
@ -216,12 +220,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
return null;
|
||||
}
|
||||
|
||||
return FindMovie<Movie>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType);
|
||||
return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
|
||||
}
|
||||
|
||||
if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return FindMovie<Movie>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType);
|
||||
return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -494,7 +498,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
};
|
||||
}
|
||||
|
||||
private bool IsInvalid(Folder parent, string collectionType, IEnumerable<FileSystemMetadata> files)
|
||||
private bool IsInvalid(Folder parent, string collectionType)
|
||||
{
|
||||
if (parent != null)
|
||||
{
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
|
|||
// Not officially supported but in some cases we can handle it.
|
||||
if (season == null)
|
||||
{
|
||||
season = parent.Parents.OfType<Season>().FirstOrDefault();
|
||||
season = parent.GetParents().OfType<Season>().FirstOrDefault();
|
||||
}
|
||||
|
||||
// If the parent is a Season or Series, then this is an Episode if the VideoResolver returns something
|
||||
|
|
|
@ -157,18 +157,17 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
AddIfMissing(excludeItemTypes, typeof(CollectionFolder).Name);
|
||||
|
||||
var mediaItems = _libraryManager.GetItems(new InternalItemsQuery
|
||||
var mediaItems = _libraryManager.GetItems(new InternalItemsQuery(user)
|
||||
{
|
||||
NameContains = searchTerm,
|
||||
ExcludeItemTypes = excludeItemTypes.ToArray(),
|
||||
IncludeItemTypes = includeItemTypes.ToArray(),
|
||||
MaxParentalRating = user == null ? null : user.Policy.MaxParentalRating,
|
||||
Limit = (query.Limit.HasValue ? (int?)(query.Limit.Value * 3) : null),
|
||||
Limit = query.Limit,
|
||||
|
||||
}).Items;
|
||||
}, new string[] { });
|
||||
|
||||
// Add search hints based on item name
|
||||
hints.AddRange(mediaItems.Where(i => IncludeInSearch(i) && IsVisible(i, user)).Select(item =>
|
||||
hints.AddRange(mediaItems.Where(IncludeInSearch).Select(item =>
|
||||
{
|
||||
var index = GetIndex(item.Name, searchTerm, terms);
|
||||
|
||||
|
@ -184,25 +183,6 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
return Task.FromResult(returnValue);
|
||||
}
|
||||
|
||||
private bool IsVisible(BaseItem item, User user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item is IItemByName)
|
||||
{
|
||||
var dual = item as IHasDualAccess;
|
||||
if (dual == null || dual.IsAccessedByName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return item.IsVisibleStandalone(user);
|
||||
}
|
||||
|
||||
private bool IncludeInSearch(BaseItem item)
|
||||
{
|
||||
var episode = item as Episode;
|
||||
|
|
|
@ -707,8 +707,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
Id = Guid.NewGuid(),
|
||||
DateCreated = DateTime.UtcNow,
|
||||
DateModified = DateTime.UtcNow,
|
||||
UsesIdForConfigurationPath = true,
|
||||
EnableUserViews = true
|
||||
UsesIdForConfigurationPath = true
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library
|
||||
{
|
||||
|
@ -48,103 +49,63 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
.OfType<Folder>()
|
||||
.ToList();
|
||||
|
||||
if (!query.IncludeHidden)
|
||||
{
|
||||
folders = folders.Where(i =>
|
||||
{
|
||||
var hidden = i as IHiddenFromDisplay;
|
||||
return hidden == null || !hidden.IsHiddenFromUser(user);
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
var plainFolderIds = user.Configuration.PlainFolderViews.Select(i => new Guid(i)).ToList();
|
||||
|
||||
var standaloneFolders = folders
|
||||
.Where(i => UserView.IsExcludedFromGrouping(i) || !user.IsFolderGrouped(i.Id))
|
||||
.ToList();
|
||||
|
||||
var foldersWithViewTypes = folders
|
||||
.Except(standaloneFolders)
|
||||
.OfType<ICollectionFolder>()
|
||||
.ToList();
|
||||
var groupedFolders = new List<ICollectionFolder>();
|
||||
|
||||
var list = new List<Folder>();
|
||||
|
||||
var enableUserViews = _config.Configuration.EnableUserViews || user.EnableUserViews;
|
||||
|
||||
if (enableUserViews)
|
||||
{
|
||||
foreach (var folder in standaloneFolders)
|
||||
foreach (var folder in folders)
|
||||
{
|
||||
var collectionFolder = folder as ICollectionFolder;
|
||||
var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType;
|
||||
|
||||
if (UserView.IsUserSpecific(folder))
|
||||
{
|
||||
list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false));
|
||||
list.Add(await _libraryManager.GetNamedView(user, folder.Name, folder.Id.ToString("N"), folderViewType, null, cancellationToken).ConfigureAwait(false));
|
||||
continue;
|
||||
}
|
||||
else if (plainFolderIds.Contains(folder.Id))
|
||||
|
||||
if (plainFolderIds.Contains(folder.Id) && UserView.IsEligibleForEnhancedView(folderViewType))
|
||||
{
|
||||
list.Add(await GetUserView(folder, folderViewType, false, string.Empty, cancellationToken).ConfigureAwait(false));
|
||||
list.Add(folder);
|
||||
continue;
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(folderViewType))
|
||||
|
||||
if (collectionFolder != null && UserView.IsEligibleForGrouping(folder) && user.IsFolderGrouped(folder.Id))
|
||||
{
|
||||
list.Add(await GetUserView(folder, folderViewType, true, string.Empty, cancellationToken).ConfigureAwait(false));
|
||||
groupedFolders.Add(collectionFolder);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (query.PresetViews.Contains(folderViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
list.Add(await GetUserView(folder, folderViewType, string.Empty, cancellationToken).ConfigureAwait(false));
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Deprecate this whole block
|
||||
foreach (var folder in standaloneFolders)
|
||||
{
|
||||
var collectionFolder = folder as ICollectionFolder;
|
||||
var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType;
|
||||
|
||||
if (UserView.IsUserSpecific(folder))
|
||||
foreach (var viewType in new[] { CollectionType.Movies, CollectionType.TvShows })
|
||||
{
|
||||
list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false));
|
||||
}
|
||||
else if (plainFolderIds.Contains(folder.Id))
|
||||
{
|
||||
list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, false, string.Empty, user, cancellationToken).ConfigureAwait(false));
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(folderViewType))
|
||||
{
|
||||
list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false));
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.GetViewType(user)))
|
||||
var parents = groupedFolders.Where(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType))
|
||||
.ToList();
|
||||
|
||||
if (parents.Count > 0)
|
||||
{
|
||||
list.Add(await GetUserView(parents, list, CollectionType.TvShows, string.Empty, user, enableUserViews, cancellationToken).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(parents, viewType, string.Empty, user, query.PresetViews, cancellationToken).ConfigureAwait(false));
|
||||
}
|
||||
|
||||
parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.Music, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.GetViewType(user)))
|
||||
.ToList();
|
||||
|
||||
if (parents.Count > 0)
|
||||
{
|
||||
list.Add(await GetUserView(parents, list, CollectionType.Music, string.Empty, user, enableUserViews, cancellationToken).ConfigureAwait(false));
|
||||
}
|
||||
|
||||
parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.Movies, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.GetViewType(user)))
|
||||
.ToList();
|
||||
|
||||
if (parents.Count > 0)
|
||||
{
|
||||
list.Add(await GetUserView(parents, list, CollectionType.Movies, string.Empty, user, enableUserViews, cancellationToken).ConfigureAwait(false));
|
||||
}
|
||||
|
||||
parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.Games, StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
|
||||
if (parents.Count > 0)
|
||||
{
|
||||
list.Add(await GetUserView(parents, list, CollectionType.Games, string.Empty, user, enableUserViews, cancellationToken).ConfigureAwait(false));
|
||||
}
|
||||
|
||||
if (user.Configuration.DisplayFoldersView)
|
||||
|
@ -180,6 +141,18 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
{
|
||||
var index = orders.IndexOf(i.Id.ToString("N"));
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
var view = i as UserView;
|
||||
if (view != null)
|
||||
{
|
||||
if (view.DisplayParentId != Guid.Empty)
|
||||
{
|
||||
index = orders.IndexOf(view.DisplayParentId.ToString("N"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return index == -1 ? int.MaxValue : index;
|
||||
})
|
||||
.ThenBy(sorted.IndexOf)
|
||||
|
@ -200,32 +173,25 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
return GetUserSubView(name, parentId, type, sortName, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<UserView> GetUserView(List<ICollectionFolder> parents, List<Folder> currentViews, string viewType, string sortName, User user, bool enableUserViews, CancellationToken cancellationToken)
|
||||
private async Task<Folder> GetUserView(List<ICollectionFolder> parents, string viewType, string sortName, User user, string[] presetViews, CancellationToken cancellationToken)
|
||||
{
|
||||
if (parents.Count == 1 && parents.All(i => string.Equals((enableUserViews ? i.GetViewType(user) : i.CollectionType), viewType, StringComparison.OrdinalIgnoreCase)))
|
||||
if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
var parentId = parents[0].Id;
|
||||
if (!presetViews.Contains(viewType, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return (Folder)parents[0];
|
||||
}
|
||||
|
||||
var enableRichView = !user.Configuration.PlainFolderViews.Contains(parentId.ToString("N"), StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
return await GetUserView((Folder)parents[0], viewType, enableRichView, string.Empty, cancellationToken).ConfigureAwait(false);
|
||||
return await GetUserView((Folder)parents[0], viewType, string.Empty, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var name = _localizationManager.GetLocalizedString("ViewType" + viewType);
|
||||
return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public Task<UserView> GetUserView(Guid parentId, string name, string viewType, bool enableRichView, string sortName, User user, CancellationToken cancellationToken)
|
||||
public Task<UserView> GetUserView(Folder parent, string viewType, string sortName, CancellationToken cancellationToken)
|
||||
{
|
||||
viewType = enableRichView ? viewType : null;
|
||||
return _libraryManager.GetNamedView(user, name, parentId.ToString("N"), viewType, sortName, null, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<UserView> GetUserView(Folder parent, string viewType, bool enableRichView, string sortName, CancellationToken cancellationToken)
|
||||
{
|
||||
viewType = enableRichView ? viewType : null;
|
||||
|
||||
return _libraryManager.GetShadowView(parent, viewType, sortName, null, cancellationToken);
|
||||
return _libraryManager.GetShadowView(parent, viewType, sortName, cancellationToken);
|
||||
}
|
||||
|
||||
public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request)
|
||||
|
@ -236,16 +202,8 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
var currentUser = user;
|
||||
|
||||
Func<BaseItem, bool> filter = i =>
|
||||
var libraryItems = GetItemsForLatestItems(user, request.ParentId, includeTypes, request.Limit ?? 10).Where(i =>
|
||||
{
|
||||
if (includeTypes.Length > 0)
|
||||
{
|
||||
if (!includeTypes.Contains(i.GetType().Name, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (request.IsPlayed.HasValue)
|
||||
{
|
||||
var val = request.IsPlayed.Value;
|
||||
|
@ -255,29 +213,12 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
}
|
||||
}
|
||||
|
||||
return i.LocationType != LocationType.Virtual && !i.IsFolder;
|
||||
};
|
||||
|
||||
// Avoid implicitly captured closure
|
||||
var libraryItems = string.IsNullOrEmpty(request.ParentId) && user != null ?
|
||||
GetItemsConfiguredForLatest(user, filter) :
|
||||
GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, filter);
|
||||
|
||||
libraryItems = libraryItems.OrderByDescending(i => i.DateCreated);
|
||||
|
||||
if (request.IsPlayed.HasValue)
|
||||
{
|
||||
var takeLimit = (request.Limit ?? 20) * 20;
|
||||
libraryItems = libraryItems.Take(takeLimit);
|
||||
}
|
||||
|
||||
// Avoid implicitly captured closure
|
||||
var items = libraryItems
|
||||
.ToList();
|
||||
return true;
|
||||
});
|
||||
|
||||
var list = new List<Tuple<BaseItem, List<BaseItem>>>();
|
||||
|
||||
foreach (var item in items)
|
||||
foreach (var item in libraryItems)
|
||||
{
|
||||
// Only grab the index container for media
|
||||
var container = item.IsFolder || !request.GroupItems ? null : item.LatestItemsIndexContainer;
|
||||
|
@ -309,59 +250,34 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
return list;
|
||||
}
|
||||
|
||||
protected IList<BaseItem> GetAllLibraryItems(string userId, IUserManager userManager, ILibraryManager libraryManager, string parentId, Func<BaseItem, bool> filter)
|
||||
private IEnumerable<BaseItem> GetItemsForLatestItems(User user, string parentId, string[] includeItemTypes, int limit)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(parentId))
|
||||
var parentIds = string.IsNullOrEmpty(parentId)
|
||||
? new string[] { }
|
||||
: new[] { parentId };
|
||||
|
||||
if (parentIds.Length == 0)
|
||||
{
|
||||
var folder = (Folder)libraryManager.GetItemById(new Guid(parentId));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(userId))
|
||||
{
|
||||
var user = userManager.GetUserById(userId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentException("User not found");
|
||||
}
|
||||
|
||||
return folder
|
||||
.GetRecursiveChildren(user, filter)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return folder
|
||||
.GetRecursiveChildren(filter);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(userId))
|
||||
{
|
||||
var user = userManager.GetUserById(userId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentException("User not found");
|
||||
}
|
||||
|
||||
return user
|
||||
.RootFolder
|
||||
.GetRecursiveChildren(user, filter)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return libraryManager
|
||||
.RootFolder
|
||||
.GetRecursiveChildren(filter);
|
||||
}
|
||||
|
||||
private IEnumerable<BaseItem> GetItemsConfiguredForLatest(User user, Func<BaseItem, bool> filter)
|
||||
{
|
||||
// Avoid implicitly captured closure
|
||||
var currentUser = user;
|
||||
|
||||
return user.RootFolder.GetChildren(user, true)
|
||||
parentIds = user.RootFolder.GetChildren(user, true)
|
||||
.OfType<Folder>()
|
||||
.Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N")))
|
||||
.SelectMany(i => i.GetRecursiveChildren(currentUser, filter))
|
||||
.DistinctBy(i => i.Id);
|
||||
.Select(i => i.Id.ToString("N"))
|
||||
.Where(i => !user.Configuration.LatestItemsExcludes.Contains(i))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
var excludeItemTypes = includeItemTypes.Length == 0 ? new[] { "ChannelItem", "LiveTvItem", typeof(Person).Name, typeof(Studio).Name, typeof(Year).Name, typeof(GameGenre).Name, typeof(MusicGenre).Name, typeof(Genre).Name } : new string[] { };
|
||||
|
||||
return _libraryManager.GetItems(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = includeItemTypes,
|
||||
SortOrder = SortOrder.Descending,
|
||||
SortBy = new[] { ItemSortBy.DateCreated },
|
||||
IsFolder = includeItemTypes.Length == 0 ? false : (bool?)null,
|
||||
ExcludeItemTypes = excludeItemTypes,
|
||||
ExcludeLocationTypes = new[] { LocationType.Virtual },
|
||||
Limit = limit * 20
|
||||
|
||||
}, parentIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -560,6 +560,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
}
|
||||
item.ExternalId = channelInfo.Id;
|
||||
|
||||
if (!item.ParentId.Equals(parentFolderId))
|
||||
{
|
||||
isNew = true;
|
||||
}
|
||||
item.ParentId = parentFolderId;
|
||||
|
||||
item.ChannelType = channelInfo.ChannelType;
|
||||
item.ServiceName = serviceName;
|
||||
item.Number = channelInfo.Number;
|
||||
|
@ -622,6 +628,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
};
|
||||
}
|
||||
|
||||
if (!item.ParentId.Equals(channel.Id))
|
||||
{
|
||||
forceUpdate = true;
|
||||
}
|
||||
item.ParentId = channel.Id;
|
||||
|
||||
//item.ChannelType = channelType;
|
||||
if (!string.Equals(item.ServiceName, serviceName, StringComparison.Ordinal))
|
||||
{
|
||||
|
@ -774,6 +786,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
}
|
||||
recording.IsSeries = info.IsSeries;
|
||||
|
||||
if (!item.ParentId.Equals(parentFolderId))
|
||||
{
|
||||
dataChanged = true;
|
||||
}
|
||||
item.ParentId = parentFolderId;
|
||||
|
||||
if (!item.HasImage(ImageType.Primary))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(info.ImagePath))
|
||||
|
@ -851,7 +869,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
{
|
||||
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
|
||||
|
||||
var internalQuery = new InternalItemsQuery
|
||||
var internalQuery = new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
|
||||
MinEndDate = query.MinEndDate,
|
||||
|
@ -869,16 +887,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
SortOrder = query.SortOrder ?? SortOrder.Ascending
|
||||
};
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
internalQuery.MaxParentalRating = user.Policy.MaxParentalRating;
|
||||
|
||||
if (user.Policy.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram))
|
||||
{
|
||||
internalQuery.HasParentalRating = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (query.HasAired.HasValue)
|
||||
{
|
||||
if (query.HasAired.Value)
|
||||
|
@ -913,7 +921,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
{
|
||||
var user = _userManager.GetUserById(query.UserId);
|
||||
|
||||
var internalQuery = new InternalItemsQuery
|
||||
var internalQuery = new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
|
||||
IsAiring = query.IsAiring,
|
||||
|
@ -922,16 +930,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
IsKids = query.IsKids
|
||||
};
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
internalQuery.MaxParentalRating = user.Policy.MaxParentalRating;
|
||||
|
||||
if (user.Policy.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram))
|
||||
{
|
||||
internalQuery.HasParentalRating = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (query.HasAired.HasValue)
|
||||
{
|
||||
if (query.HasAired.Value)
|
||||
|
@ -1399,7 +1397,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
|
||||
await RefreshRecordings(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var internalQuery = new InternalItemsQuery
|
||||
var internalQuery = new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }
|
||||
};
|
||||
|
@ -1409,8 +1407,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
internalQuery.ChannelIds = new[] { query.ChannelId };
|
||||
}
|
||||
|
||||
var queryResult = _libraryManager.GetItems(internalQuery);
|
||||
IEnumerable<ILiveTvRecording> recordings = queryResult.Items.Cast<ILiveTvRecording>();
|
||||
var queryResult = _libraryManager.GetItems(internalQuery, new string[] { });
|
||||
IEnumerable<ILiveTvRecording> recordings = queryResult.Cast<ILiveTvRecording>();
|
||||
|
||||
if (!string.IsNullOrEmpty(query.Id))
|
||||
{
|
||||
|
@ -1516,6 +1514,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
if (channel != null)
|
||||
{
|
||||
dto.ChannelName = channel.Name;
|
||||
dto.MediaType = channel.MediaType;
|
||||
|
||||
if (channel.HasImage(ImageType.Primary))
|
||||
{
|
||||
|
@ -1812,7 +1811,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
var programs = _libraryManager.GetItems(new InternalItemsQuery
|
||||
var programs = _libraryManager.GetItems(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
|
||||
ChannelIds = new[] { id },
|
||||
|
@ -1821,7 +1820,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
Limit = 1,
|
||||
SortBy = new[] { "StartDate" }
|
||||
|
||||
}).Items.Cast<LiveTvProgram>();
|
||||
}, new string[] { }).Cast<LiveTvProgram>();
|
||||
|
||||
var currentProgram = programs.FirstOrDefault();
|
||||
|
||||
|
@ -1836,7 +1835,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
var programs = _libraryManager.GetItems(new InternalItemsQuery
|
||||
var programs = _libraryManager.GetItems(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
|
||||
ChannelIds = new[] { channel.Id.ToString("N") },
|
||||
|
@ -1845,7 +1844,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
Limit = 1,
|
||||
SortBy = new[] { "StartDate" }
|
||||
|
||||
}).Items.Cast<LiveTvProgram>();
|
||||
}, new string[] { }).Cast<LiveTvProgram>();
|
||||
|
||||
var currentProgram = programs.FirstOrDefault();
|
||||
|
||||
|
|
|
@ -124,8 +124,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
|
|||
{
|
||||
if (extractImages)
|
||||
{
|
||||
if (video.VideoType == VideoType.HdDvd || video.VideoType == VideoType.Iso ||
|
||||
video.VideoType == VideoType.BluRay)
|
||||
if (video.VideoType == VideoType.HdDvd || video.VideoType == VideoType.Iso || video.VideoType == VideoType.BluRay)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ using System.Collections.Generic;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Persistence
|
||||
|
@ -24,6 +25,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
public const int MigrationVersion = 7;
|
||||
|
||||
public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
|
@ -64,16 +67,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
innerProgress.RegisterAction(p => progress.Report(45 + (.55 * p)));
|
||||
await CleanDeletedItems(cancellationToken, innerProgress).ConfigureAwait(false);
|
||||
progress.Report(100);
|
||||
|
||||
await _itemRepo.UpdateInheritedValues(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task UpdateToLatestSchema(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
var itemIds = _libraryManager.GetItemIds(new InternalItemsQuery
|
||||
{
|
||||
IsCurrentSchema = false,
|
||||
|
||||
// These are constantly getting regenerated so don't bother with them here
|
||||
ExcludeItemTypes = new[] { typeof(LiveTvProgram).Name }
|
||||
IsCurrentSchema = false
|
||||
});
|
||||
|
||||
var numComplete = 0;
|
||||
|
@ -115,9 +117,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
progress.Report(percent * 100);
|
||||
}
|
||||
|
||||
if (!_config.Configuration.DisableStartupScan)
|
||||
if (_config.Configuration.MigrationVersion < MigrationVersion)
|
||||
{
|
||||
_config.Configuration.DisableStartupScan = true;
|
||||
_config.Configuration.MigrationVersion = MigrationVersion;
|
||||
_config.SaveConfiguration();
|
||||
}
|
||||
|
||||
|
@ -165,12 +167,22 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
{
|
||||
var result = _itemRepo.GetItemIdsWithPath(new InternalItemsQuery
|
||||
{
|
||||
IsOffline = false,
|
||||
LocationType = LocationType.FileSystem,
|
||||
//Limit = limit,
|
||||
|
||||
// These have their own cleanup routines
|
||||
ExcludeItemTypes = new[] { typeof(Person).Name, typeof(Genre).Name, typeof(MusicGenre).Name, typeof(GameGenre).Name, typeof(Studio).Name, typeof(Year).Name }
|
||||
ExcludeItemTypes = new[]
|
||||
{
|
||||
typeof(Person).Name,
|
||||
typeof(Genre).Name,
|
||||
typeof(MusicGenre).Name,
|
||||
typeof(GameGenre).Name,
|
||||
typeof(Studio).Name,
|
||||
typeof(Year).Name,
|
||||
typeof(Channel).Name,
|
||||
typeof(AggregateFolder).Name,
|
||||
typeof(CollectionFolder).Name
|
||||
}
|
||||
});
|
||||
|
||||
var numComplete = 0;
|
||||
|
@ -191,6 +203,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
|
||||
var libraryItem = _libraryManager.GetItemById(item.Item1);
|
||||
|
||||
if (libraryItem.IsTopParent)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Folder.IsPathOffline(path))
|
||||
{
|
||||
libraryItem.IsOffline = true;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue