Merge branch 'beta'

This commit is contained in:
Luke Pulverenti 2016-05-21 00:49:17 -04:00
commit b253d26aba
44 changed files with 529 additions and 373 deletions

View file

@ -103,7 +103,8 @@ namespace MediaBrowser.Api
User = user,
MediaTypes = request.GetMediaTypes(),
IncludeItemTypes = request.GetIncludeItemTypes(),
Recursive = true
Recursive = true,
EnableTotalRecordCount = false
};
return query;

View file

@ -162,7 +162,10 @@ namespace MediaBrowser.Api
var items = user == null ?
system.GetRecursiveChildren(i => i is Game) :
system.GetRecursiveChildren(user, i => i is Game);
system.GetRecursiveChildren(user, new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Game).Name }
});
var games = items.Cast<Game>().ToList();

View file

@ -65,11 +65,7 @@ namespace MediaBrowser.Api
public void Post(ReportStartupWizardComplete request)
{
_config.Configuration.IsStartupWizardCompleted = true;
_config.Configuration.EnableLocalizedGuids = true;
_config.Configuration.EnableCustomPathSubFolders = true;
_config.Configuration.EnableDateLastRefresh = true;
_config.Configuration.EnableStandaloneMusicKeys = true;
_config.Configuration.EnableCaseSensitiveItemIds = true;
SetWizardFinishValues(_config.Configuration);
_config.SaveConfiguration();
}
@ -111,6 +107,15 @@ namespace MediaBrowser.Api
return result;
}
private void SetWizardFinishValues(ServerConfiguration config)
{
config.EnableLocalizedGuids = true;
config.EnableCustomPathSubFolders = true;
config.EnableDateLastRefresh = true;
config.EnableStandaloneMusicKeys = true;
config.EnableCaseSensitiveItemIds = true;
}
public void Post(UpdateStartupConfiguration request)
{
_config.Configuration.UICulture = request.UICulture;

View file

@ -415,21 +415,10 @@ namespace MediaBrowser.Api
private IEnumerable<Season> FilterVirtualSeasons(GetSeasons request, IEnumerable<Season> items)
{
if (request.IsMissing.HasValue && request.IsVirtualUnaired.HasValue)
{
var isMissing = request.IsMissing.Value;
var isVirtualUnaired = request.IsVirtualUnaired.Value;
if (!isMissing && !isVirtualUnaired)
{
return items.Where(i => !i.IsMissingOrVirtualUnaired);
}
}
if (request.IsMissing.HasValue)
{
var val = request.IsMissing.Value;
items = items.Where(i => (i.IsMissingSeason ?? false) == val);
items = items.Where(i => (i.IsMissingSeason) == val);
}
if (request.IsVirtualUnaired.HasValue)

View file

@ -121,6 +121,13 @@ namespace MediaBrowser.Api.UserLibrary
var includeItemTypes = request.GetIncludeItemTypes();
var mediaTypes = request.GetMediaTypes();
var query = new InternalItemsQuery(user)
{
ExcludeItemTypes = excludeItemTypes,
IncludeItemTypes = includeItemTypes,
MediaTypes = mediaTypes
};
Func<BaseItem, bool> filter = i => FilterItem(request, i, excludeItemTypes, includeItemTypes, mediaTypes);
if (parentItem.IsFolder)
@ -130,7 +137,7 @@ namespace MediaBrowser.Api.UserLibrary
if (!string.IsNullOrWhiteSpace(request.UserId))
{
items = request.Recursive ?
folder.GetRecursiveChildren(user, filter) :
folder.GetRecursiveChildren(user, query) :
folder.GetChildren(user, true).Where(filter);
}
else

View file

@ -138,25 +138,19 @@ namespace MediaBrowser.Api.UserLibrary
if (request.Recursive)
{
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
return result;
return await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
}
if (user == null)
{
var result = await ((Folder)item).GetItems(GetItemsQuery(request, null)).ConfigureAwait(false);
return result;
return await ((Folder)item).GetItems(GetItemsQuery(request, null)).ConfigureAwait(false);
}
var userRoot = item as UserRootFolder;
if (userRoot == null)
{
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
return result;
return await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
}
IEnumerable<BaseItem> items = ((Folder)item).GetChildren(user, true);

View file

@ -55,7 +55,7 @@
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.1\lib\net45\NLog.dll</HintPath>
<HintPath>..\packages\NLog.4.3.4\lib\net45\NLog.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Patterns.Logging">
@ -65,8 +65,8 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>
</Reference>
<Reference Include="SimpleInjector, Version=3.1.3.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleInjector.3.1.3\lib\net45\SimpleInjector.dll</HintPath>
<Reference Include="SimpleInjector, Version=3.1.4.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleInjector.3.1.4\lib\net45\SimpleInjector.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />

View file

@ -2,7 +2,7 @@
<packages>
<package id="CommonIO" version="1.0.0.9" targetFramework="net45" />
<package id="morelinq" version="1.4.0" targetFramework="net45" />
<package id="NLog" version="4.3.1" targetFramework="net45" />
<package id="NLog" version="4.3.4" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
<package id="SimpleInjector" version="3.1.3" targetFramework="net45" />
<package id="SimpleInjector" version="3.1.4" targetFramework="net45" />
</packages>

View file

@ -64,10 +64,37 @@ namespace MediaBrowser.Controller.Entities
protected override IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
{
return CreateResolveArgs(directoryService).FileSystemChildren;
return CreateResolveArgs(directoryService, true).FileSystemChildren;
}
private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService)
private bool _requiresRefresh;
public override bool RequiresRefresh()
{
var changed = base.RequiresRefresh() || _requiresRefresh;
if (!changed)
{
var locations = PhysicalLocations.ToList();
var newLocations = CreateResolveArgs(new DirectoryService(BaseItem.FileSystem), false).PhysicalLocations.ToList();
if (!locations.SequenceEqual(newLocations))
{
changed = true;
}
}
return changed;
}
public override bool BeforeMetadataRefresh()
{
var changed = base.BeforeMetadataRefresh() || _requiresRefresh;
_requiresRefresh = false;
return changed;
}
private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService, bool setPhysicalLocations)
{
var path = ContainingFolderPath;
@ -100,7 +127,11 @@ namespace MediaBrowser.Controller.Entities
args.FileSystemDictionary = fileSystemDictionary;
}
PhysicalLocationsList = args.PhysicalLocations.ToList();
_requiresRefresh = _requiresRefresh || !args.PhysicalLocations.SequenceEqual(PhysicalLocations);
if (setPhysicalLocations)
{
PhysicalLocationsList = args.PhysicalLocations.ToList();
}
return args;
}

View file

@ -56,38 +56,23 @@ namespace MediaBrowser.Controller.Entities.Audio
public IEnumerable<BaseItem> GetTaggedItems(InternalItemsQuery query)
{
var itemByNameFilter = GetItemFilter();
if (query.User != null)
if (query.IncludeItemTypes.Length == 0)
{
return query.User.RootFolder
.GetRecursiveChildren(query.User, i =>
{
if (query.IsFolder.HasValue)
{
if (query.IsFolder.Value != i.IsFolder)
{
return false;
}
}
return itemByNameFilter(i);
});
query.IncludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicVideo).Name, typeof(MusicAlbum).Name };
query.ArtistNames = new[] { Name };
}
return LibraryManager.RootFolder
.GetRecursiveChildren(i =>
{
if (query.IsFolder.HasValue)
{
if (query.IsFolder.Value != i.IsFolder)
{
return false;
}
}
return itemByNameFilter(i);
});
// Need this for now since the artist filter isn't yet supported by the db
if (ConfigurationManager.Configuration.SchemaVersion < 79)
{
var filter = GetItemFilter();
return LibraryManager.GetItemList(query).Where(filter);
}
return LibraryManager.GetItemList(query);
}
[IgnoreDataMember]
protected override IEnumerable<BaseItem> ActualChildren
{
get

View file

@ -23,19 +23,6 @@ namespace MediaBrowser.Controller.Entities
PhysicalLocationsList = new List<string>();
}
/// <summary>
/// Gets a value indicating whether this instance is virtual folder.
/// </summary>
/// <value><c>true</c> if this instance is virtual folder; otherwise, <c>false</c>.</value>
[IgnoreDataMember]
public override bool IsVirtualFolder
{
get
{
return true;
}
}
[IgnoreDataMember]
protected override bool SupportsShortcutChildren
{
@ -83,7 +70,34 @@ namespace MediaBrowser.Controller.Entities
protected override IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
{
return CreateResolveArgs(directoryService).FileSystemChildren;
return CreateResolveArgs(directoryService, true).FileSystemChildren;
}
private bool _requiresRefresh;
public override bool RequiresRefresh()
{
var changed = base.RequiresRefresh() || _requiresRefresh;
if (!changed)
{
var locations = PhysicalLocations.ToList();
var newLocations = CreateResolveArgs(new DirectoryService(BaseItem.FileSystem), false).PhysicalLocations.ToList();
if (!locations.SequenceEqual(newLocations))
{
changed = true;
}
}
return changed;
}
public override bool BeforeMetadataRefresh()
{
var changed = base.BeforeMetadataRefresh() || _requiresRefresh;
_requiresRefresh = false;
return changed;
}
internal override bool IsValidFromResolver(BaseItem newItem)
@ -101,7 +115,7 @@ namespace MediaBrowser.Controller.Entities
return base.IsValidFromResolver(newItem);
}
private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService)
private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService, bool setPhysicalLocations)
{
var path = ContainingFolderPath;
@ -135,7 +149,11 @@ namespace MediaBrowser.Controller.Entities
args.FileSystemDictionary = fileSystemDictionary;
}
PhysicalLocationsList = args.PhysicalLocations.ToList();
_requiresRefresh = _requiresRefresh || !args.PhysicalLocations.SequenceEqual(PhysicalLocations);
if (setPhysicalLocations)
{
PhysicalLocationsList = args.PhysicalLocations.ToList();
}
return args;
}
@ -153,15 +171,6 @@ namespace MediaBrowser.Controller.Entities
/// <returns>Task.</returns>
protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
{
var list = PhysicalLocationsList.ToList();
CreateResolveArgs(directoryService);
if (!list.SequenceEqual(PhysicalLocationsList))
{
return UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken);
}
return Task.FromResult(true);
}
@ -188,6 +197,7 @@ namespace MediaBrowser.Controller.Entities
/// Our children are actually just references to the ones in the physical root...
/// </summary>
/// <value>The actual children.</value>
[IgnoreDataMember]
protected override IEnumerable<BaseItem> ActualChildren
{
get { return GetActualChildren(); }

View file

@ -126,19 +126,6 @@ namespace MediaBrowser.Controller.Entities
/// <value><c>true</c> if this instance is root; otherwise, <c>false</c>.</value>
public bool IsRoot { get; set; }
/// <summary>
/// Gets a value indicating whether this instance is virtual folder.
/// </summary>
/// <value><c>true</c> if this instance is virtual folder; otherwise, <c>false</c>.</value>
[IgnoreDataMember]
public virtual bool IsVirtualFolder
{
get
{
return false;
}
}
public virtual List<LinkedChild> LinkedChildren { get; set; }
[IgnoreDataMember]
@ -285,6 +272,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets the actual children.
/// </summary>
/// <value>The actual children.</value>
[IgnoreDataMember]
protected virtual IEnumerable<BaseItem> ActualChildren
{
get
@ -749,7 +737,7 @@ namespace MediaBrowser.Controller.Entities
{
var user = query.User;
if (RequiresPostFiltering(query))
if (!query.ForceDirect && RequiresPostFiltering(query))
{
IEnumerable<BaseItem> items;
Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
@ -760,7 +748,7 @@ namespace MediaBrowser.Controller.Entities
}
else
{
items = GetRecursiveChildren(user, filter);
items = GetRecursiveChildren(user, query);
}
return PostFilterAndSort(items, query);
@ -784,7 +772,7 @@ namespace MediaBrowser.Controller.Entities
return true;
}
}
var supportsUserDataQueries = ConfigurationManager.Configuration.SchemaVersion >= 76;
if (query.SortBy != null && query.SortBy.Length > 0)
@ -817,21 +805,26 @@ namespace MediaBrowser.Controller.Entities
return true;
}
}
if (ConfigurationManager.Configuration.SchemaVersion < 79)
{
if (query.SortBy.Contains(ItemSortBy.AlbumArtist, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.AlbumArtist");
return true;
}
if (query.SortBy.Contains(ItemSortBy.Artist, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.Artist");
return true;
}
}
if (query.SortBy.Contains(ItemSortBy.AiredEpisodeOrder, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.AiredEpisodeOrder");
return true;
}
if (query.SortBy.Contains(ItemSortBy.AlbumArtist, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.AlbumArtist");
return true;
}
if (query.SortBy.Contains(ItemSortBy.Artist, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.Artist");
return true;
}
if (query.SortBy.Contains(ItemSortBy.Budget, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.Budget");
@ -1109,10 +1102,13 @@ namespace MediaBrowser.Controller.Entities
return true;
}
if (query.ArtistNames.Length > 0)
if (ConfigurationManager.Configuration.SchemaVersion < 79)
{
Logger.Debug("Query requires post-filtering due to ArtistNames");
return true;
if (query.ArtistNames.Length > 0)
{
Logger.Debug("Query requires post-filtering due to ArtistNames");
return true;
}
}
return false;
@ -1178,7 +1174,7 @@ namespace MediaBrowser.Controller.Entities
else
{
items = query.Recursive
? GetRecursiveChildren(user, filter)
? GetRecursiveChildren(user, query)
: GetChildren(user, true).Where(filter);
}
@ -1215,19 +1211,14 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Adds the children to list.
/// </summary>
/// <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="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 recursive, Func<BaseItem, bool> filter)
private void AddChildren(User user, bool includeLinkedChildren, Dictionary<Guid, BaseItem> result, bool recursive, InternalItemsQuery query)
{
foreach (var child in GetEligibleChildrenForRecursiveChildren(user))
{
if (child.IsVisible(user))
{
if (filter == null || filter(child))
if (query == null || UserViewBuilder.FilterItem(child, query))
{
result[child.Id] = child;
}
@ -1236,7 +1227,7 @@ namespace MediaBrowser.Controller.Entities
{
var folder = (Folder)child;
folder.AddChildren(user, includeLinkedChildren, result, true, filter);
folder.AddChildren(user, includeLinkedChildren, result, true, query);
}
}
}
@ -1247,7 +1238,7 @@ namespace MediaBrowser.Controller.Entities
{
if (child.IsVisible(user))
{
if (filter == null || filter(child))
if (query == null || UserViewBuilder.FilterItem(child, query))
{
result[child.Id] = child;
}
@ -1265,10 +1256,10 @@ namespace MediaBrowser.Controller.Entities
/// <exception cref="System.ArgumentNullException"></exception>
public IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true)
{
return GetRecursiveChildren(user, i => true);
return GetRecursiveChildren(user, null);
}
public virtual IEnumerable<BaseItem> GetRecursiveChildren(User user, Func<BaseItem, bool> filter)
public virtual IEnumerable<BaseItem> GetRecursiveChildren(User user, InternalItemsQuery query)
{
if (user == null)
{
@ -1277,7 +1268,7 @@ namespace MediaBrowser.Controller.Entities
var result = new Dictionary<Guid, BaseItem>();
AddChildren(user, true, result, true, filter);
AddChildren(user, true, result, true, query);
return result.Values;
}
@ -1303,7 +1294,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Adds the children to list.
/// </summary>
private void AddChildrenToList(Dictionary<Guid,BaseItem> result, bool includeLinkedChildren, bool recursive, Func<BaseItem, bool> filter)
private void AddChildrenToList(Dictionary<Guid, BaseItem> result, bool includeLinkedChildren, bool recursive, Func<BaseItem, bool> filter)
{
foreach (var child in Children)
{
@ -1534,13 +1525,12 @@ namespace MediaBrowser.Controller.Entities
User = user,
Recursive = true,
IsFolder = false,
IsUnaired = false
EnableTotalRecordCount = false
};
if (!user.Configuration.DisplayMissingEpisodes)
if (!user.Configuration.DisplayMissingEpisodes || !user.Configuration.DisplayUnairedEpisodes)
{
query.IsMissing = false;
query.ExcludeLocationTypes = new[] { LocationType.Virtual };
}
var itemsResult = await GetItems(query).ConfigureAwait(false);
@ -1562,7 +1552,8 @@ namespace MediaBrowser.Controller.Entities
{
User = user,
Recursive = true,
IsFolder = false
IsFolder = false,
EnableTotalRecordCount = false
}).ConfigureAwait(false);
@ -1578,7 +1569,8 @@ namespace MediaBrowser.Controller.Entities
{
Recursive = true,
IsFolder = false,
ExcludeLocationTypes = new[] { LocationType.Virtual }
ExcludeLocationTypes = new[] { LocationType.Virtual },
EnableTotalRecordCount = false
}).Result;
@ -1630,7 +1622,8 @@ namespace MediaBrowser.Controller.Entities
{
Recursive = true,
IsFolder = false,
ExcludeLocationTypes = new[] { LocationType.Virtual }
ExcludeLocationTypes = new[] { LocationType.Virtual },
EnableTotalRecordCount = false
}).Result;

View file

@ -15,12 +15,6 @@ namespace MediaBrowser.Controller.Entities
/// <returns>IEnumerable{BaseItem}.</returns>
IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems);
/// <summary>
/// Gets the item filter.
/// </summary>
/// <returns>Func&lt;BaseItem, System.Boolean&gt;.</returns>
Func<BaseItem, bool> GetItemFilter();
IEnumerable<BaseItem> GetTaggedItems(InternalItemsQuery query);
}

View file

@ -19,8 +19,6 @@ namespace MediaBrowser.Controller.Entities
public User User { get; set; }
public Func<BaseItem, bool> Filter { get; set; }
public bool? IsFolder { get; set; }
public bool? IsFavorite { get; set; }
public bool? IsFavoriteOrLiked { get; set; }
@ -138,6 +136,7 @@ namespace MediaBrowser.Controller.Entities
public bool GroupByPresentationUniqueKey { get; set; }
public bool EnableTotalRecordCount { get; set; }
public bool ForceDirect { get; set; }
public InternalItemsQuery()
{

View file

@ -134,7 +134,7 @@ namespace MediaBrowser.Controller.Entities.TV
if (!result)
{
if (!IsMissingSeason.HasValue)
if (!IsVirtualItem.HasValue)
{
return true;
}
@ -144,18 +144,23 @@ namespace MediaBrowser.Controller.Entities.TV
}
[IgnoreDataMember]
public bool? IsMissingSeason { get; set; }
public bool? IsVirtualItem { get; set; }
[IgnoreDataMember]
public bool IsMissingSeason
{
get { return (IsVirtualItem ?? DetectIsVirtualItem()) && !IsUnaired; }
}
[IgnoreDataMember]
public bool IsVirtualUnaired
{
get { return LocationType == LocationType.Virtual && IsUnaired; }
get { return (IsVirtualItem ?? DetectIsVirtualItem()) && IsUnaired; }
}
[IgnoreDataMember]
public bool IsMissingOrVirtualUnaired
private bool DetectIsVirtualItem()
{
get { return (IsMissingSeason ?? false) || (LocationType == LocationType.Virtual && IsUnaired); }
return LocationType == LocationType.Virtual && GetEpisodes().All(i => i.LocationType == LocationType.Virtual);
}
[IgnoreDataMember]
@ -319,19 +324,14 @@ namespace MediaBrowser.Controller.Entities.TV
{
var hasChanges = base.BeforeMetadataRefresh();
var locationType = LocationType;
if (locationType == LocationType.FileSystem || locationType == LocationType.Offline)
if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path))
{
if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path))
{
IndexNumber = IndexNumber ?? LibraryManager.GetSeasonNumberFromPath(Path);
IndexNumber = IndexNumber ?? LibraryManager.GetSeasonNumberFromPath(Path);
// If a change was made record it
if (IndexNumber.HasValue)
{
hasChanges = true;
}
// If a change was made record it
if (IndexNumber.HasValue)
{
hasChanges = true;
}
}

View file

@ -238,20 +238,13 @@ namespace MediaBrowser.Controller.Entities.TV
seasons = LibraryManager.Sort(base.GetChildren(user, true), user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).OfType<Season>();
}
if (!includeMissingSeasons && !includeVirtualUnaired)
if (!includeMissingSeasons)
{
seasons = seasons.Where(i => !i.IsMissingOrVirtualUnaired);
seasons = seasons.Where(i => !(i.IsMissingSeason));
}
else
if (!includeVirtualUnaired)
{
if (!includeMissingSeasons)
{
seasons = seasons.Where(i => !(i.IsMissingSeason ?? false));
}
if (!includeVirtualUnaired)
{
seasons = seasons.Where(i => !i.IsVirtualUnaired);
}
seasons = seasons.Where(i => !i.IsVirtualUnaired);
}
return seasons;
@ -381,14 +374,18 @@ namespace MediaBrowser.Controller.Entities.TV
}
else
{
episodes = GetRecursiveChildren(user, i => i is Episode)
.Cast<Episode>();
episodes = GetRecursiveChildren(user, new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Episode).Name }
}).Cast<Episode>();
}
}
else
{
episodes = GetRecursiveChildren(user, i => i is Episode)
.Cast<Episode>();
episodes = GetRecursiveChildren(user, new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Episode).Name }
}).Cast<Episode>();
}
episodes = FilterEpisodesBySeason(episodes, seasonNumber, DisplaySpecialsWithSeasons);

View file

@ -305,14 +305,7 @@ namespace MediaBrowser.Controller.Entities
public bool IsFolderGrouped(Guid id)
{
var config = Configuration;
if (config.ExcludeFoldersFromGrouping != null)
{
return !config.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).Contains(id);
}
return config.GroupedFolders.Select(i => new Guid(i)).Contains(id);
return Configuration.GroupedFolders.Select(i => new Guid(i)).Contains(id);
}
[IgnoreDataMember]

View file

@ -64,15 +64,6 @@ namespace MediaBrowser.Controller.Entities
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);
}
public override bool BeforeMetadataRefresh()
{
var hasChanges = base.BeforeMetadataRefresh();

View file

@ -66,7 +66,8 @@ namespace MediaBrowser.Controller.Entities
{
var result = GetItems(new InternalItemsQuery
{
User = user
User = user,
EnableTotalRecordCount = false
}).Result;
@ -83,17 +84,19 @@ namespace MediaBrowser.Controller.Entities
return true;
}
public override IEnumerable<BaseItem> GetRecursiveChildren(User user, Func<BaseItem, bool> filter)
public override IEnumerable<BaseItem> GetRecursiveChildren(User user, InternalItemsQuery query)
{
var result = GetItems(new InternalItemsQuery
{
User = user,
Recursive = true,
Filter = filter
EnableTotalRecordCount = false,
ForceDirect = true
}).Result;
return result.Items;
return result.Items.Where(i => UserViewBuilder.FilterItem(i, query));
}
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)

View file

@ -128,7 +128,11 @@ namespace MediaBrowser.Controller.Entities
{
if (query.Recursive)
{
return GetResult(queryParent.GetRecursiveChildren(user, true), queryParent, query);
query.Recursive = true;
query.ParentId = queryParent.Id;
query.SetUser(user);
return _libraryManager.GetItemsResult(query);
}
return GetResult(queryParent.GetChildren(user, true), queryParent, query);
}
@ -251,7 +255,6 @@ namespace MediaBrowser.Controller.Entities
if (query.Recursive)
{
query.Recursive = true;
query.ParentId = parent.Id;
query.SetUser(user);
if (query.IncludeItemTypes.Length == 0)
@ -259,7 +262,7 @@ namespace MediaBrowser.Controller.Entities
query.IncludeItemTypes = new[] { typeof(MusicArtist).Name, typeof(MusicAlbum).Name, typeof(Audio.Audio).Name, typeof(MusicVideo).Name };
}
return _libraryManager.GetItemsResult(query);
return parent.QueryRecursive(query);
}
var list = new List<BaseItem>();
@ -329,9 +332,13 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetMusicAlbumArtists(Folder parent, User user, InternalItemsQuery query)
{
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
.Where(i => !i.IsFolder)
.OfType<IHasAlbumArtist>();
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Recursive = true,
ParentId = parent.Id,
IncludeItemTypes = new[] { typeof(Audio.Audio).Name }
}).Cast<IHasAlbumArtist>();
var artists = _libraryManager.GetAlbumArtists(items);
@ -340,9 +347,13 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetMusicArtists(Folder parent, User user, InternalItemsQuery query)
{
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
.Where(i => !i.IsFolder)
.OfType<IHasArtist>();
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Recursive = true,
ParentId = parent.Id,
IncludeItemTypes = new[] { typeof(Audio.Audio).Name, typeof(MusicVideo).Name }
}).Cast<IHasArtist>();
var artists = _libraryManager.GetArtists(items);
@ -351,9 +362,13 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetFavoriteArtists(Folder parent, User user, InternalItemsQuery query)
{
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
.Where(i => !i.IsFolder)
.OfType<IHasAlbumArtist>();
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Recursive = true,
ParentId = parent.Id,
IncludeItemTypes = new[] { typeof(Audio.Audio).Name }
}).Cast<IHasAlbumArtist>();
var artists = _libraryManager.GetAlbumArtists(items).Where(i => _userDataManager.GetUserData(user, i).IsFavorite);
@ -448,7 +463,6 @@ namespace MediaBrowser.Controller.Entities
if (query.Recursive)
{
query.Recursive = true;
query.ParentId = parent.Id;
query.SetUser(user);
if (query.IncludeItemTypes.Length == 0)
@ -456,7 +470,7 @@ namespace MediaBrowser.Controller.Entities
query.IncludeItemTypes = new[] { typeof(Movie).Name, typeof(BoxSet).Name };
}
return _libraryManager.GetItemsResult(query);
return parent.QueryRecursive(query);
}
var list = new List<BaseItem>();
@ -613,7 +627,6 @@ namespace MediaBrowser.Controller.Entities
if (query.Recursive)
{
query.Recursive = true;
query.ParentId = parent.Id;
query.SetUser(user);
if (query.IncludeItemTypes.Length == 0)
@ -621,7 +634,7 @@ namespace MediaBrowser.Controller.Entities
query.IncludeItemTypes = new[] { typeof(Series).Name, typeof(Season).Name, typeof(Episode).Name };
}
return _libraryManager.GetItemsResult(query);
return parent.QueryRecursive(query);
}
var list = new List<BaseItem>();
@ -756,9 +769,9 @@ namespace MediaBrowser.Controller.Entities
return PostFilterAndSort(items, queryParent, null, query, _libraryManager);
}
public bool FilterItem(BaseItem item, InternalItemsQuery query)
public static bool FilterItem(BaseItem item, InternalItemsQuery query)
{
return Filter(item, query.User, query, _userDataManager, _libraryManager);
return Filter(item, query.User, query, BaseItem.UserDataManager, BaseItem.LibraryManager);
}
private QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items,
@ -1121,22 +1134,6 @@ namespace MediaBrowser.Controller.Entities
bool? isVirtualUnaired,
bool? isUnaired)
{
if (isMissing.HasValue && isVirtualUnaired.HasValue)
{
if (!isMissing.Value && !isVirtualUnaired.Value)
{
return items.Where(i =>
{
var e = i as Season;
if (e != null)
{
return !e.IsMissingOrVirtualUnaired;
}
return true;
});
}
}
if (isMissing.HasValue)
{
var val = isMissing.Value;
@ -1145,7 +1142,7 @@ namespace MediaBrowser.Controller.Entities
var e = i as Season;
if (e != null)
{
return (e.IsMissingSeason ?? false) == val;
return (e.IsMissingSeason) == val;
}
return true;
});
@ -1277,11 +1274,6 @@ namespace MediaBrowser.Controller.Entities
return false;
}
if (query.Filter != null && !query.Filter(item))
{
return false;
}
UserItemData userData = null;
if (query.IsLiked.HasValue)

View file

@ -63,13 +63,13 @@ namespace MediaBrowser.Controller.Playlists
return GetPlayableItems(user).Result;
}
public override IEnumerable<BaseItem> GetRecursiveChildren(User user, Func<BaseItem, bool> filter)
public override IEnumerable<BaseItem> GetRecursiveChildren(User user, InternalItemsQuery query)
{
var items = GetPlayableItems(user).Result;
if (filter != null)
if (query != null)
{
items = items.Where(filter);
items = items.Where(i => UserViewBuilder.FilterItem(i, query));
}
return items;
@ -129,7 +129,11 @@ namespace MediaBrowser.Controller.Playlists
var items = user == null
? LibraryManager.RootFolder.GetRecursiveChildren(filter)
: user.RootFolder.GetRecursiveChildren(user, filter);
: user.RootFolder.GetRecursiveChildren(user, new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Audio).Name },
ArtistNames = new[] { musicArtist.Name }
});
return LibraryManager.Sort(items, user, new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName }, SortOrder.Ascending);
}

View file

@ -401,10 +401,10 @@ namespace MediaBrowser.Dlna.ContentDirectory
SortOrder = sort.SortOrder,
User = user,
Recursive = true,
Filter = FilterUnsupportedContent,
IsMissing = false,
ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
IsFolder = isFolder,
MediaTypes = mediaTypes.ToArray()
});
}
@ -461,8 +461,10 @@ namespace MediaBrowser.Dlna.ContentDirectory
SortBy = sortOrders.ToArray(),
SortOrder = sort.SortOrder,
User = user,
Filter = FilterUnsupportedContent,
PresetViews = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Music }
IsMissing = false,
PresetViews = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Music },
ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
IsPlaceHolder = false
}).ConfigureAwait(false);
@ -579,29 +581,6 @@ namespace MediaBrowser.Dlna.ContentDirectory
});
}
private bool FilterUnsupportedContent(BaseItem i)
{
// Unplayable
if (i.LocationType == LocationType.Virtual && !i.IsFolder)
{
return false;
}
// Unplayable
var supportsPlaceHolder = i as ISupportsPlaceHolders;
if (supportsPlaceHolder != null && supportsPlaceHolder.IsPlaceHolder)
{
return false;
}
if (i is Game || i is Book)
{
//return false;
}
return true;
}
private ServerItem GetItemFromObjectId(string id, User user)
{
return DidlBuilder.IsIdRoot(id)

View file

@ -215,6 +215,9 @@ namespace MediaBrowser.Model.Configuration
{
Migrations = new string[] { };
EnableLocalizedGuids = true;
EnableCustomPathSubFolders = true;
ImageSavingConvention = ImageSavingConvention.Compatible;
PublicPort = 8096;
PublicHttpsPort = 8920;

View file

@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Extensions;
using System.Diagnostics;
using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Model.Entities
{
@ -53,18 +53,22 @@ namespace MediaBrowser.Model.Entities
if (!string.IsNullOrEmpty(Language))
{
attributes.Add(Language);
attributes.Add(StringHelper.FirstToUpper(Language));
}
if (!string.IsNullOrEmpty(Codec) && !StringHelper.EqualsIgnoreCase(Codec, "dca"))
{
attributes.Add(Codec);
}
if (!string.IsNullOrEmpty(Profile) && !StringHelper.EqualsIgnoreCase(Profile, "lc"))
attributes.Add(AudioCodec.GetFriendlyName(Codec));
}
else if (!string.IsNullOrEmpty(Profile) && !StringHelper.EqualsIgnoreCase(Profile, "lc"))
{
attributes.Add(Profile);
}
if (Channels.HasValue)
if (!string.IsNullOrEmpty(ChannelLayout))
{
attributes.Add(ChannelLayout);
}
else if (Channels.HasValue)
{
attributes.Add(StringHelper.ToStringCultureInvariant(Channels.Value) + " ch");
}

View file

@ -125,5 +125,10 @@ namespace MediaBrowser.Model.Extensions
return sb.ToString();
}
public static string FirstToUpper(this string str)
{
return string.IsNullOrEmpty(str) ? "" : str.Substring(0, 1).ToUpper() + str.Substring(1);
}
}
}

View file

@ -20,12 +20,15 @@ namespace MediaBrowser.Model.LiveTv
public int PrePaddingSeconds { get; set; }
public int PostPaddingSeconds { get; set; }
public string[] MediaLocationsCreated { get; set; }
public LiveTvOptions()
{
EnableMovieProviders = true;
EnableRecordingSubfolders = true;
TunerHosts = new List<TunerHostInfo>();
ListingProviders = new List<ListingsProviderInfo>();
MediaLocationsCreated = new string[] { };
}
}

View file

@ -5,5 +5,22 @@
public const string AAC = "aac";
public const string MP3 = "mp3";
public const string AC3 = "ac3";
public static string GetFriendlyName(string codec)
{
if (string.IsNullOrEmpty(codec)) return "";
switch (codec.ToLower())
{
case "ac3":
return "Dolby Digital";
case "eac3":
return "Dolby Digital+";
case "dca":
return "DTS";
default:
return codec.ToUpper();
}
}
}
}

View file

@ -288,6 +288,8 @@ namespace MediaBrowser.Model.Querying
[Obsolete]
public string Person { get; set; }
public bool EnableTotalRecordCount { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ItemQuery" /> class.
/// </summary>
@ -306,6 +308,8 @@ namespace MediaBrowser.Model.Querying
VideoTypes = new VideoType[] { };
EnableTotalRecordCount = true;
Artists = new string[] { };
Studios = new string[] { };

View file

@ -145,11 +145,15 @@ namespace MediaBrowser.Providers.Manager
bool hasRefreshedMetadata = true;
bool hasRefreshedImages = true;
var requiresRefresh = false;
// Next run metadata providers
if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None)
{
var providers = GetProviders(item, refreshResult, refreshOptions)
// TODO: If this returns true, should we instead just change metadata refresh mode to Full?
requiresRefresh = item.RequiresRefresh();
var providers = GetProviders(item, refreshResult, refreshOptions, requiresRefresh)
.ToList();
var dateLastRefresh = EnableDateLastRefreshed(item)
@ -217,11 +221,11 @@ namespace MediaBrowser.Providers.Manager
var isFirstRefresh = GetLastRefreshDate(item) == default(DateTime);
var beforeSaveResult = await BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh, updateType).ConfigureAwait(false);
var beforeSaveResult = await BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || requiresRefresh, updateType).ConfigureAwait(false);
updateType = updateType | beforeSaveResult;
// Save if changes were made, or it's never been saved before
if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || isFirstRefresh || refreshOptions.ReplaceAllMetadata)
if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || isFirstRefresh || refreshOptions.ReplaceAllMetadata || requiresRefresh)
{
// If any of these properties are set then make sure the updateType is not None, just to force everything to save
if (refreshOptions.ForceSave || refreshOptions.ReplaceAllMetadata)
@ -461,11 +465,8 @@ namespace MediaBrowser.Providers.Manager
/// <summary>
/// Gets the providers.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="status">The status.</param>
/// <param name="options">The options.</param>
/// <returns>IEnumerable{`0}.</returns>
protected IEnumerable<IMetadataProvider> GetProviders(IHasMetadata item, MetadataStatus status, MetadataRefreshOptions options)
protected IEnumerable<IMetadataProvider> GetProviders(IHasMetadata item, MetadataStatus status, MetadataRefreshOptions options, bool requiresRefresh)
{
// Get providers to refresh
var providers = ((ProviderManager)ProviderManager).GetMetadataProviders<TItemType>(item).ToList();
@ -475,7 +476,7 @@ namespace MediaBrowser.Providers.Manager
: status.DateLastMetadataRefresh ?? default(DateTime);
// Run all if either of these flags are true
var runAllProviders = options.ReplaceAllMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || dateLastRefresh == default(DateTime) || item.RequiresRefresh();
var runAllProviders = options.ReplaceAllMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || dateLastRefresh == default(DateTime) || requiresRefresh;
if (!runAllProviders)
{
@ -668,12 +669,6 @@ namespace MediaBrowser.Providers.Manager
// If a local provider fails, consider that a failure
refreshResult.ErrorMessage = ex.Message;
if (options.MetadataRefreshMode != MetadataRefreshMode.FullRefresh)
{
// If the local provider fails don't continue with remote providers because the user's saved metadata could be lost
//return refreshResult;
}
}
}

View file

@ -69,7 +69,7 @@ namespace MediaBrowser.Providers.TV
if (!hasSeason)
{
await AddSeason(series, seasonNumber, cancellationToken).ConfigureAwait(false);
await AddSeason(series, seasonNumber, false, cancellationToken).ConfigureAwait(false);
hasChanges = true;
}
@ -83,7 +83,7 @@ namespace MediaBrowser.Providers.TV
if (!hasSeason)
{
await AddSeason(series, null, cancellationToken).ConfigureAwait(false);
await AddSeason(series, null, false, cancellationToken).ConfigureAwait(false);
hasChanges = true;
}
@ -95,12 +95,9 @@ namespace MediaBrowser.Providers.TV
/// <summary>
/// Adds the season.
/// </summary>
/// <param name="series">The series.</param>
/// <param name="seasonNumber">The season number.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{Season}.</returns>
public async Task<Season> AddSeason(Series series,
int? seasonNumber,
bool isVirtualItem,
CancellationToken cancellationToken)
{
var seasonName = seasonNumber == 0 ?
@ -113,7 +110,8 @@ namespace MediaBrowser.Providers.TV
{
Name = seasonName,
IndexNumber = seasonNumber,
Id = _libraryManager.GetNewItemId((series.Id + (seasonNumber ?? -1).ToString(_usCulture) + seasonName), typeof(Season))
Id = _libraryManager.GetNewItemId((series.Id + (seasonNumber ?? -1).ToString(_usCulture) + seasonName), typeof(Season)),
IsVirtualItem = isVirtualItem
};
season.SetParent(series);

View file

@ -418,7 +418,7 @@ namespace MediaBrowser.Providers.TV
if (season == null)
{
var provider = new DummySeasonProvider(_config, _logger, _localization, _libraryManager, _fileSystem);
season = await provider.AddSeason(series, seasonNumber, cancellationToken).ConfigureAwait(false);
season = await provider.AddSeason(series, seasonNumber, true, cancellationToken).ConfigureAwait(false);
}
var name = string.Format("Episode {0}", episodeNumber.ToString(_usCulture));

View file

@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.TV
{
var episodes = item.GetEpisodes().ToList();
updateType |= SavePremiereDate(item, episodes);
updateType |= SaveIsMissing(item, episodes);
updateType |= SaveIsVirtualItem(item, episodes);
}
return updateType;
@ -67,13 +67,13 @@ namespace MediaBrowser.Providers.TV
return ItemUpdateType.None;
}
private ItemUpdateType SaveIsMissing(Season item, List<Episode> episodes)
private ItemUpdateType SaveIsVirtualItem(Season item, List<Episode> episodes)
{
var isMissing = item.LocationType == LocationType.Virtual && episodes.All(i => i.IsMissingEpisode);
var isVirtualItem = item.LocationType == LocationType.Virtual && (episodes.Count == 0 || episodes.All(i => i.LocationType == LocationType.Virtual));
if (item.IsMissingSeason != isMissing)
if (item.IsVirtualItem != isVirtualItem)
{
item.IsMissingSeason = isMissing;
item.IsVirtualItem = isVirtualItem;
return ItemUpdateType.MetadataEdit;
}

View file

@ -1448,8 +1448,12 @@ namespace MediaBrowser.Server.Implementations.Library
// 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 user.RootFolder
.GetChildren(user, true)
.OfType<CollectionFolder>()
.Where(i => string.IsNullOrWhiteSpace(i.CollectionType) || string.Equals(i.CollectionType, view.ViewType, StringComparison.OrdinalIgnoreCase))
.Where(i => user.IsFolderGrouped(i.Id))
.SelectMany(i => GetTopParentsForQuery(i, user));
}
return new BaseItem[] { };
}

View file

@ -30,7 +30,10 @@ namespace MediaBrowser.Server.Implementations.Library
public IEnumerable<Audio> GetInstantMixFromArtist(MusicArtist artist, User user)
{
var genres = user.RootFolder
.GetRecursiveChildren(user, i => i is Audio)
.GetRecursiveChildren(user, new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Audio).Name }
})
.Cast<Audio>()
.Where(i => i.HasAnyArtist(artist.Name))
.SelectMany(i => i.Genres)
@ -43,7 +46,10 @@ namespace MediaBrowser.Server.Implementations.Library
public IEnumerable<Audio> GetInstantMixFromAlbum(MusicAlbum item, User user)
{
var genres = item
.GetRecursiveChildren(user, i => i is Audio)
.GetRecursiveChildren(user, new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Audio).Name }
})
.Cast<Audio>()
.SelectMany(i => i.Genres)
.Concat(item.Genres)
@ -55,7 +61,10 @@ namespace MediaBrowser.Server.Implementations.Library
public IEnumerable<Audio> GetInstantMixFromFolder(Folder item, User user)
{
var genres = item
.GetRecursiveChildren(user, i => i is Audio)
.GetRecursiveChildren(user, new InternalItemsQuery(user)
{
IncludeItemTypes = new[] {typeof(Audio).Name}
})
.Cast<Audio>()
.SelectMany(i => i.Genres)
.Concat(item.Genres)
@ -67,7 +76,10 @@ namespace MediaBrowser.Server.Implementations.Library
public IEnumerable<Audio> GetInstantMixFromPlaylist(Playlist item, User user)
{
var genres = item
.GetRecursiveChildren(user, i => i is Audio)
.GetRecursiveChildren(user, new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Audio).Name }
})
.Cast<Audio>()
.SelectMany(i => i.Genres)
.Concat(item.Genres)

View file

@ -115,17 +115,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
var recordingFolders = GetRecordingFolders();
var defaultRecordingPath = DefaultRecordingPath;
if (!recordingFolders.Any(i => i.Locations.Contains(defaultRecordingPath, StringComparer.OrdinalIgnoreCase)))
{
RemovePathFromLibrary(defaultRecordingPath);
}
var virtualFolders = _libraryManager.GetVirtualFolders()
.ToList();
var allExistingPaths = virtualFolders.SelectMany(i => i.Locations).ToList();
var pathsAdded = new List<string>();
foreach (var recordingFolder in recordingFolders)
{
var pathsToCreate = recordingFolder.Locations
@ -145,11 +141,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
_logger.ErrorException("Error creating virtual folder", ex);
}
pathsAdded.AddRange(pathsToCreate);
}
var config = GetConfiguration();
var pathsToRemove = config.MediaLocationsCreated
.Except(recordingFolders.SelectMany(i => i.Locations))
.ToList();
if (pathsAdded.Count > 0 || pathsToRemove.Count > 0)
{
pathsAdded.InsertRange(0, config.MediaLocationsCreated);
config.MediaLocationsCreated = pathsAdded.Except(pathsToRemove).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
_config.SaveConfiguration("livetv", config);
}
foreach (var path in pathsToRemove)
{
RemovePathFromLibrary(path);
}
}
private void RemovePathFromLibrary(string path)
{
_logger.Debug("Removing path from library: {0}", path);
var requiresRefresh = false;
var virtualFolders = _libraryManager.GetVirtualFolders()
.ToList();

View file

@ -527,6 +527,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private async Task<LiveTvChannel> GetChannel(ChannelInfo channelInfo, string serviceName, Guid parentFolderId, CancellationToken cancellationToken)
{
var isNew = false;
var forceUpdate = false;
var id = _tvDtoService.GetInternalChannelId(serviceName, channelInfo.Id);
@ -576,10 +577,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (!string.IsNullOrWhiteSpace(channelInfo.ImagePath))
{
item.SetImagePath(ImageType.Primary, channelInfo.ImagePath);
forceUpdate = true;
}
else if (!string.IsNullOrWhiteSpace(channelInfo.ImageUrl))
{
item.SetImagePath(ImageType.Primary, channelInfo.ImageUrl);
forceUpdate = true;
}
}
@ -588,9 +591,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv
item.Name = channelInfo.Name;
}
if (isNew)
{
await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
}
else if (forceUpdate)
{
await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
}
await item.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
{
ForceSave = isNew
ForceSave = isNew || forceUpdate
}, cancellationToken);
@ -1398,16 +1410,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv
.Where(i => i.IsVisibleStandalone(user))
.ToList();
var items = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
if (folders.Count == 0)
{
return new QueryResult<BaseItem>();
}
return _libraryManager.GetItemsResult(new InternalItemsQuery(user)
{
MediaTypes = new[] { MediaType.Video },
Recursive = true,
AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(),
IsFolder = false,
ExcludeLocationTypes = new[] { LocationType.Virtual },
Limit = Math.Min(10, query.Limit ?? int.MaxValue)
Limit = Math.Min(200, query.Limit ?? int.MaxValue),
SortBy = new[] { ItemSortBy.DateCreated },
SortOrder = SortOrder.Descending
});
return items;
}
public async Task<QueryResult<BaseItem>> GetInternalRecordings(RecordingQuery query, CancellationToken cancellationToken)

View file

@ -55,9 +55,9 @@
<Reference Include="Interfaces.IO">
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
</Reference>
<Reference Include="MediaBrowser.Naming, Version=1.0.5917.1514, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MediaBrowser.Naming.1.0.0.49\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
<Reference Include="MediaBrowser.Naming, Version=1.0.5981.21615, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\MediaBrowser.Naming.1.0.0.50\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MoreLinq">
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
@ -68,8 +68,8 @@
<Reference Include="ServiceStack.Api.Swagger">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll</HintPath>
</Reference>
<Reference Include="SimpleInjector, Version=3.1.3.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleInjector.3.1.3\lib\net45\SimpleInjector.dll</HintPath>
<Reference Include="SimpleInjector, Version=3.1.4.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleInjector.3.1.4\lib\net45\SimpleInjector.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SocketHttpListener, Version=1.0.5955.1537, Culture=neutral, processorArchitecture=MSIL">

View file

@ -81,10 +81,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
private IDbCommand _deleteUserDataKeysCommand;
private IDbCommand _saveUserDataKeysCommand;
private IDbCommand _deleteItemValuesCommand;
private IDbCommand _saveItemValuesCommand;
private IDbCommand _updateInheritedRatingCommand;
private IDbCommand _updateInheritedTagsCommand;
public const int LatestSchemaVersion = 78;
public const int LatestSchemaVersion = 79;
/// <summary>
/// Initializes a new instance of the <see cref="SqliteItemRepository"/> class.
@ -136,6 +139,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
"create table if not exists UserDataKeys (ItemId GUID, UserDataKey TEXT, PRIMARY KEY (ItemId, UserDataKey))",
"create index if not exists idx_UserDataKeys1 on UserDataKeys(ItemId)",
"create table if not exists ItemValues (ItemId GUID, Type INT, Value TEXT)",
"create index if not exists idx_ItemValues on ItemValues(ItemId)",
"create table if not exists People (ItemId GUID, Name TEXT NOT NULL, Role TEXT, PersonType TEXT, SortOrder int, ListOrder int)",
"create index if not exists idxPeopleItemId on People(ItemId)",
"create index if not exists idxPeopleName on People(Name)",
@ -232,6 +238,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.AddColumn(Logger, "TypedBaseItems", "PrimaryVersionId", "Text");
_connection.AddColumn(Logger, "TypedBaseItems", "DateLastMediaAdded", "DATETIME");
_connection.AddColumn(Logger, "TypedBaseItems", "Album", "Text");
_connection.AddColumn(Logger, "TypedBaseItems", "IsVirtualItem", "BIT");
_connection.AddColumn(Logger, "UserDataKeys", "Priority", "INT");
@ -353,7 +360,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
"DateLastMediaAdded",
"Album",
"CriticRating",
"CriticRatingSummary"
"CriticRatingSummary",
"IsVirtualItem"
};
private readonly string[] _mediaStreamSaveColumns =
@ -468,7 +476,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
"OriginalTitle",
"PrimaryVersionId",
"DateLastMediaAdded",
"Album"
"Album",
"IsVirtualItem"
};
_saveItemCommand = _connection.CreateCommand();
_saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values (";
@ -565,6 +574,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@UserDataKey");
_saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@Priority");
// item values
_deleteItemValuesCommand = _connection.CreateCommand();
_deleteItemValuesCommand.CommandText = "delete from ItemValues where ItemId=@Id";
_deleteItemValuesCommand.Parameters.Add(_deleteItemValuesCommand, "@Id");
_saveItemValuesCommand = _connection.CreateCommand();
_saveItemValuesCommand.CommandText = "insert into ItemValues (ItemId, Type, Value) values (@ItemId, @Type, @Value)";
_saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@ItemId");
_saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@Type");
_saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@Value");
}
/// <summary>
@ -722,7 +742,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemCommand.GetParameter(index++).Value = item.DateLastRefreshed;
}
_saveItemCommand.GetParameter(index++).Value = item.DateLastSaved;
if (item.DateLastSaved == default(DateTime))
{
_saveItemCommand.GetParameter(index++).Value = null;
}
else
{
_saveItemCommand.GetParameter(index++).Value = item.DateLastSaved;
}
_saveItemCommand.GetParameter(index++).Value = item.IsInMixedFolder;
_saveItemCommand.GetParameter(index++).Value = string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray());
_saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Studios.ToArray());
@ -841,6 +869,16 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemCommand.GetParameter(index++).Value = item.Album;
var season = item as Season;
if (season != null && season.IsVirtualItem.HasValue)
{
_saveItemCommand.GetParameter(index++).Value = season.IsVirtualItem.Value;
}
else
{
_saveItemCommand.GetParameter(index++).Value = null;
}
_saveItemCommand.Transaction = transaction;
_saveItemCommand.ExecuteNonQuery();
@ -851,6 +889,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
UpdateUserDataKeys(item.Id, item.GetUserDataKeys().Distinct(StringComparer.OrdinalIgnoreCase).ToList(), transaction);
UpdateItemValues(item.Id, GetItemValues(item), transaction);
}
transaction.Commit();
@ -1255,6 +1294,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
item.CriticRatingSummary = reader.GetString(57);
}
var season = item as Season;
if (season != null && !reader.IsDBNull(58))
{
season.IsVirtualItem = reader.GetBoolean(58);
}
return item;
}
@ -1661,7 +1706,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
var elapsed = (DateTime.UtcNow - startDate).TotalMilliseconds;
if (elapsed >= 500)
if (elapsed >= 400)
{
Logger.Debug("{2} query time (slow): {0}ms. Query: {1}",
Convert.ToInt32(elapsed),
@ -1795,7 +1840,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
}).ToArray());
}
private Tuple<string,bool> MapOrderByField(string name)
private Tuple<string, bool> MapOrderByField(string name)
{
if (string.Equals(name, ItemSortBy.AirTime, StringComparison.OrdinalIgnoreCase))
{
@ -1838,6 +1883,14 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
return new Tuple<string, bool>("DateLastMediaAdded", false);
}
if (string.Equals(name, ItemSortBy.Artist, StringComparison.OrdinalIgnoreCase))
{
return new Tuple<string, bool>("(select value from itemvalues where ItemId=Guid and Type=0 LIMIT 1)", false);
}
if (string.Equals(name, ItemSortBy.AlbumArtist, StringComparison.OrdinalIgnoreCase))
{
return new Tuple<string, bool>("(select value from itemvalues where ItemId=Guid and Type=1 LIMIT 1)", false);
}
return new Tuple<string, bool>(name, false);
}
@ -2405,17 +2458,20 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.Parameters.Add(cmd, "@IsFavorite", DbType.Boolean).Value = query.IsFavorite.Value;
}
if (query.IsPlayed.HasValue)
if (EnableJoinUserData(query))
{
if (query.IsPlayed.Value)
if (query.IsPlayed.HasValue)
{
whereClauses.Add("(played=@IsPlayed)");
if (query.IsPlayed.Value)
{
whereClauses.Add("(played=@IsPlayed)");
}
else
{
whereClauses.Add("(played is null or played=@IsPlayed)");
}
cmd.Parameters.Add(cmd, "@IsPlayed", DbType.Boolean).Value = query.IsPlayed.Value;
}
else
{
whereClauses.Add("(played is null or played=@IsPlayed)");
}
cmd.Parameters.Add(cmd, "@IsPlayed", DbType.Boolean).Value = query.IsPlayed.Value;
}
if (query.IsResumable.HasValue)
@ -2430,6 +2486,20 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
if (query.ArtistNames.Length > 0)
{
var clauses = new List<string>();
var index = 0;
foreach (var artist in query.ArtistNames)
{
clauses.Add("@ArtistName" + index + " in (select value from itemvalues where ItemId=Guid and Type <= 1)");
cmd.Parameters.Add(cmd, "@ArtistName" + index, DbType.String).Value = artist;
index++;
}
var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
whereClauses.Add(clause);
}
if (query.Genres.Length > 0)
{
var clauses = new List<string>();
@ -2967,6 +3037,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
_deleteUserDataKeysCommand.Transaction = transaction;
_deleteUserDataKeysCommand.ExecuteNonQuery();
// Delete item values
_deleteItemValuesCommand.GetParameter(0).Value = id;
_deleteItemValuesCommand.Transaction = transaction;
_deleteItemValuesCommand.ExecuteNonQuery();
// Delete the item
_deleteItemCommand.GetParameter(0).Value = id;
_deleteItemCommand.Transaction = transaction;
@ -3159,6 +3234,56 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
private List<Tuple<int, string>> GetItemValues(BaseItem item)
{
var list = new List<Tuple<int, string>>();
var hasArtist = item as IHasArtist;
if (hasArtist != null)
{
list.AddRange(hasArtist.Artists.Select(i => new Tuple<int, string>(0, i)));
}
var hasAlbumArtist = item as IHasAlbumArtist;
if (hasAlbumArtist != null)
{
list.AddRange(hasAlbumArtist.AlbumArtists.Select(i => new Tuple<int, string>(1, i)));
}
return list;
}
private void UpdateItemValues(Guid itemId, List<Tuple<int, string>> values, IDbTransaction transaction)
{
if (itemId == Guid.Empty)
{
throw new ArgumentNullException("itemId");
}
if (values == null)
{
throw new ArgumentNullException("keys");
}
CheckDisposed();
// First delete
_deleteItemValuesCommand.GetParameter(0).Value = itemId;
_deleteItemValuesCommand.Transaction = transaction;
_deleteItemValuesCommand.ExecuteNonQuery();
foreach (var pair in values)
{
_saveItemValuesCommand.GetParameter(0).Value = itemId;
_saveItemValuesCommand.GetParameter(1).Value = pair.Item1;
_saveItemValuesCommand.GetParameter(2).Value = pair.Item2;
_saveItemValuesCommand.Transaction = transaction;
_saveItemValuesCommand.ExecuteNonQuery();
}
}
private void UpdateUserDataKeys(Guid itemId, List<string> keys, IDbTransaction transaction)
{
if (itemId == Guid.Empty)

View file

@ -4,10 +4,10 @@
<package id="Emby.XmlTv" version="1.0.0.48" targetFramework="net45" />
<package id="ini-parser" version="2.2.4" targetFramework="net45" />
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
<package id="MediaBrowser.Naming" version="1.0.0.49" targetFramework="net45" />
<package id="MediaBrowser.Naming" version="1.0.0.50" targetFramework="net45" />
<package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
<package id="morelinq" version="1.4.0" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
<package id="SimpleInjector" version="3.1.3" targetFramework="net45" />
<package id="SimpleInjector" version="3.1.4" targetFramework="net45" />
<package id="SocketHttpListener" version="1.0.0.30" targetFramework="net45" />
</packages>

View file

@ -107,9 +107,6 @@
<Content Include="dashboard-ui\components\chromecasthelpers.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\bower_components\fastclick\lib\fastclick.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\components\favoriteitems.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -1686,6 +1683,9 @@
<None Include="dashboard-ui\strings\id.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="dashboard-ui\strings\sk.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="dashboard-ui\strings\zh-HK.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View file

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common.Internal</id>
<version>3.0.647</version>
<version>3.0.648</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@ -12,9 +12,9 @@
<description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
<dependency id="MediaBrowser.Common" version="3.0.647" />
<dependency id="NLog" version="4.3.1" />
<dependency id="SimpleInjector" version="3.1.3" />
<dependency id="MediaBrowser.Common" version="3.0.648" />
<dependency id="NLog" version="4.3.4" />
<dependency id="SimpleInjector" version="3.1.4" />
</dependencies>
</metadata>
<files>

View file

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common</id>
<version>3.0.647</version>
<version>3.0.648</version>
<title>MediaBrowser.Common</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>

View file

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Model.Signed</id>
<version>3.0.647</version>
<title>MediaBrowser.Model - Signed Edition</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
<projectUrl>https://github.com/MediaBrowser/MediaBrowser</projectUrl>
<iconUrl>http://www.mb3admin.com/images/mb3icons1-1.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains common model objects and interfaces used by all Emby solutions.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
</dependencies>
</metadata>
<files>
<file src="dllssigned\net45\MediaBrowser.Model.dll" target="lib\net45\MediaBrowser.Model.dll" />
</files>
</package>

View file

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Server.Core</id>
<version>3.0.647</version>
<version>3.0.648</version>
<title>Media Browser.Server.Core</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Emby Server.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
<dependency id="MediaBrowser.Common" version="3.0.647" />
<dependency id="MediaBrowser.Common" version="3.0.648" />
<dependency id="Interfaces.IO" version="1.0.0.5" />
</dependencies>
</metadata>