mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-03-25 19:46:34 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Collections;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Collections
|
||||
{
|
||||
public class CollectionManager : ICollectionManager
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ILibraryMonitor _iLibraryMonitor;
|
||||
|
||||
public CollectionManager(ILibraryManager libraryManager, IFileSystem fileSystem, ILibraryMonitor iLibraryMonitor)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_fileSystem = fileSystem;
|
||||
_iLibraryMonitor = iLibraryMonitor;
|
||||
}
|
||||
|
||||
public async Task CreateCollection(CollectionCreationOptions options)
|
||||
{
|
||||
var name = options.Name;
|
||||
|
||||
// Need to use the [boxset] suffix
|
||||
// If internet metadata is not found, or if xml saving is off there will be no collection.xml
|
||||
// This could cause it to get re-resolved as a plain folder
|
||||
var folderName = _fileSystem.GetValidFilename(name) + " [boxset]";
|
||||
|
||||
var parentFolder = GetParentFolder(options.ParentId);
|
||||
|
||||
if (parentFolder == null)
|
||||
{
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
var path = Path.Combine(parentFolder.Path, folderName);
|
||||
|
||||
_iLibraryMonitor.ReportFileSystemChangeBeginning(path);
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
var collection = new BoxSet
|
||||
{
|
||||
Name = name,
|
||||
Parent = parentFolder,
|
||||
DisplayMediaType = "Collection",
|
||||
Path = path,
|
||||
DontFetchMeta = options.IsLocked,
|
||||
ProviderIds = options.ProviderIds
|
||||
};
|
||||
|
||||
await parentFolder.AddChild(collection, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
await collection.RefreshMetadata(new MetadataRefreshOptions(), CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Refresh handled internally
|
||||
_iLibraryMonitor.ReportFileSystemChangeComplete(path, false);
|
||||
}
|
||||
}
|
||||
|
||||
private Folder GetParentFolder(Guid? parentId)
|
||||
{
|
||||
if (parentId.HasValue)
|
||||
{
|
||||
if (parentId.Value == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException("parentId");
|
||||
}
|
||||
|
||||
var folder = _libraryManager.GetItemById(parentId.Value) as Folder;
|
||||
|
||||
// Find an actual physical folder
|
||||
if (folder is CollectionFolder)
|
||||
{
|
||||
return _libraryManager.RootFolder.Children.OfType<Folder>().First(i => folder.PhysicalLocations.Contains(i.Path, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
return _libraryManager.RootFolder.Children.OfType<ManualCollectionsFolder>().FirstOrDefault() ??
|
||||
_libraryManager.RootFolder.GetHiddenChildren().OfType<ManualCollectionsFolder>().FirstOrDefault();
|
||||
}
|
||||
|
||||
public async Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids)
|
||||
{
|
||||
var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
|
||||
|
||||
if (collection == null)
|
||||
{
|
||||
throw new ArgumentException("No collection exists with the supplied Id");
|
||||
}
|
||||
|
||||
var list = new List<LinkedChild>();
|
||||
|
||||
foreach (var itemId in ids)
|
||||
{
|
||||
var item = _libraryManager.GetItemById(itemId);
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
throw new ArgumentException("No item exists with the supplied Id");
|
||||
}
|
||||
|
||||
if (collection.LinkedChildren.Any(i => i.ItemId.HasValue && i.ItemId == itemId))
|
||||
{
|
||||
throw new ArgumentException("Item already exists in collection");
|
||||
}
|
||||
|
||||
list.Add(new LinkedChild
|
||||
{
|
||||
ItemName = item.Name,
|
||||
ItemYear = item.ProductionYear,
|
||||
ItemType = item.GetType().Name,
|
||||
Type = LinkedChildType.Manual
|
||||
});
|
||||
}
|
||||
|
||||
collection.LinkedChildren.AddRange(list);
|
||||
|
||||
await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
await collection.RefreshMetadata(CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task RemoveFromCollection(Guid collectionId, IEnumerable<Guid> itemIds)
|
||||
{
|
||||
var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
|
||||
|
||||
if (collection == null)
|
||||
{
|
||||
throw new ArgumentException("No collection exists with the supplied Id");
|
||||
}
|
||||
|
||||
var list = new List<LinkedChild>();
|
||||
|
||||
foreach (var itemId in itemIds)
|
||||
{
|
||||
var child = collection.LinkedChildren.FirstOrDefault(i => i.ItemId.HasValue && i.ItemId.Value == itemId);
|
||||
|
||||
if (child == null)
|
||||
{
|
||||
throw new ArgumentException("No collection title exists with the supplied Id");
|
||||
}
|
||||
|
||||
list.Add(child);
|
||||
}
|
||||
|
||||
var shortcutFiles = Directory
|
||||
.EnumerateFiles(collection.Path, "*", SearchOption.TopDirectoryOnly)
|
||||
.Where(i => _fileSystem.IsShortcut(i))
|
||||
.ToList();
|
||||
|
||||
var shortcutFilesToDelete = list.Where(child => !string.IsNullOrWhiteSpace(child.Path) && child.Type == LinkedChildType.Shortcut)
|
||||
.Select(child => shortcutFiles.FirstOrDefault(i => string.Equals(child.Path, _fileSystem.ResolveShortcut(i), StringComparison.OrdinalIgnoreCase)))
|
||||
.Where(i => !string.IsNullOrWhiteSpace(i))
|
||||
.ToList();
|
||||
|
||||
foreach (var file in shortcutFilesToDelete)
|
||||
{
|
||||
_iLibraryMonitor.ReportFileSystemChangeBeginning(file);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var file in shortcutFilesToDelete)
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
|
||||
foreach (var child in list)
|
||||
{
|
||||
collection.LinkedChildren.Remove(child);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var file in shortcutFilesToDelete)
|
||||
{
|
||||
_iLibraryMonitor.ReportFileSystemChangeComplete(file, false);
|
||||
}
|
||||
}
|
||||
|
||||
await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
await collection.RefreshMetadata(CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Collections
|
||||
{
|
||||
public class CollectionsDynamicFolder : IVirtualFolderCreator
|
||||
{
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
|
||||
public CollectionsDynamicFolder(IApplicationPaths appPaths)
|
||||
{
|
||||
_appPaths = appPaths;
|
||||
}
|
||||
|
||||
public BasePluginFolder GetFolder()
|
||||
{
|
||||
var path = Path.Combine(_appPaths.DataPath, "collections");
|
||||
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
return new ManualCollectionsFolder
|
||||
{
|
||||
Path = path
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class ManualCollectionsFolder : BasePluginFolder
|
||||
{
|
||||
public ManualCollectionsFolder()
|
||||
{
|
||||
Name = "Collections";
|
||||
}
|
||||
|
||||
public override bool IsVisible(User user)
|
||||
{
|
||||
if (!GetChildren(user, true).Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.IsVisible(user);
|
||||
}
|
||||
|
||||
public override bool IsHidden
|
||||
{
|
||||
get
|
||||
{
|
||||
return !ActualChildren.Any() || base.IsHidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,41 +121,51 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
}
|
||||
}
|
||||
|
||||
var itemByName = item as IItemByName;
|
||||
if (itemByName != null)
|
||||
{
|
||||
AttachItemByNameCounts(dto, itemByName, user);
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attaches the item by name counts.
|
||||
/// </summary>
|
||||
/// <param name="dto">The dto.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
private void AttachItemByNameCounts(BaseItemDto dto, IItemByName item, User user)
|
||||
public BaseItemDto GetItemByNameDto<T>(T item, List<ItemFields> fields, User user = null)
|
||||
where T : BaseItem, IItemByName
|
||||
{
|
||||
if (user == null)
|
||||
var libraryItems = user != null ? user.RootFolder.GetRecursiveChildren(user) :
|
||||
_libraryManager.RootFolder.RecursiveChildren;
|
||||
|
||||
return GetItemByNameDto(item, fields, item.GetTaggedItems(libraryItems).ToList(), user);
|
||||
}
|
||||
|
||||
public BaseItemDto GetItemByNameDto<T>(T item, List<ItemFields> fields, List<BaseItem> taggedItems, User user = null)
|
||||
where T : BaseItem, IItemByName
|
||||
{
|
||||
var dto = GetBaseItemDto(item, fields, user);
|
||||
|
||||
if (item is MusicArtist || item is MusicGenre)
|
||||
{
|
||||
return;
|
||||
dto.AlbumCount = taggedItems.Count(i => i is MusicAlbum);
|
||||
dto.MusicVideoCount = taggedItems.Count(i => i is MusicVideo);
|
||||
dto.SongCount = taggedItems.Count(i => i is Audio);
|
||||
}
|
||||
else if (item is GameGenre)
|
||||
{
|
||||
dto.GameCount = taggedItems.Count(i => i is Game);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This populates them all and covers Genre, Person, Studio, Year
|
||||
|
||||
dto.AdultVideoCount = taggedItems.Count(i => i is AdultVideo);
|
||||
dto.AlbumCount = taggedItems.Count(i => i is MusicAlbum);
|
||||
dto.EpisodeCount = taggedItems.Count(i => i is Episode);
|
||||
dto.GameCount = taggedItems.Count(i => i is Game);
|
||||
dto.MovieCount = taggedItems.Count(i => i is Movie);
|
||||
dto.MusicVideoCount = taggedItems.Count(i => i is MusicVideo);
|
||||
dto.SeriesCount = taggedItems.Count(i => i is Series);
|
||||
dto.SongCount = taggedItems.Count(i => i is Audio);
|
||||
dto.TrailerCount = taggedItems.Count(i => i is Trailer);
|
||||
}
|
||||
|
||||
var counts = item.GetItemByNameCounts(user.Id) ?? new ItemByNameCounts();
|
||||
dto.ChildCount = taggedItems.Count;
|
||||
|
||||
dto.ChildCount = counts.TotalCount;
|
||||
|
||||
dto.AdultVideoCount = counts.AdultVideoCount;
|
||||
dto.AlbumCount = counts.AlbumCount;
|
||||
dto.EpisodeCount = counts.EpisodeCount;
|
||||
dto.GameCount = counts.GameCount;
|
||||
dto.MovieCount = counts.MovieCount;
|
||||
dto.MusicVideoCount = counts.MusicVideoCount;
|
||||
dto.SeriesCount = counts.SeriesCount;
|
||||
dto.SongCount = counts.SongCount;
|
||||
dto.TrailerCount = counts.TrailerCount;
|
||||
return dto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -297,6 +307,57 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
|
||||
info.PrimaryImageTag = GetImageCacheTag(item, ImageType.Primary);
|
||||
|
||||
var backropItem = item.HasImage(ImageType.Backdrop) ? item : null;
|
||||
|
||||
var thumbItem = item.HasImage(ImageType.Thumb) ? item : null;
|
||||
|
||||
if (thumbItem == null)
|
||||
{
|
||||
var episode = item as Episode;
|
||||
|
||||
if (episode != null)
|
||||
{
|
||||
var series = episode.Series;
|
||||
|
||||
if (series != null && series.HasImage(ImageType.Thumb))
|
||||
{
|
||||
thumbItem = series;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (backropItem == null)
|
||||
{
|
||||
var episode = item as Episode;
|
||||
|
||||
if (episode != null)
|
||||
{
|
||||
var series = episode.Series;
|
||||
|
||||
if (series != null && series.HasImage(ImageType.Backdrop))
|
||||
{
|
||||
backropItem = series;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (thumbItem == null)
|
||||
{
|
||||
thumbItem = item.Parents.FirstOrDefault(i => i.HasImage(ImageType.Thumb));
|
||||
}
|
||||
|
||||
if (thumbItem != null)
|
||||
{
|
||||
info.ThumbImageTag = GetImageCacheTag(thumbItem, ImageType.Thumb);
|
||||
info.ThumbItemId = GetDtoId(thumbItem);
|
||||
}
|
||||
|
||||
if (thumbItem != null)
|
||||
{
|
||||
info.BackdropImageTag = GetImageCacheTag(backropItem, ImageType.Backdrop);
|
||||
info.BackdropItemId = GetDtoId(backropItem);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using Mono.Nat;
|
||||
using Mono.Nat.Enums;
|
||||
using Mono.Nat.EventArgs;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
@@ -171,12 +171,23 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||
var fileExists = File.Exists(result.TargetPath);
|
||||
var otherDuplicatePaths = GetOtherDuplicatePaths(result.TargetPath, series, seasonNumber, episodeNumber, endingEpiosdeNumber);
|
||||
|
||||
if (!overwriteExisting && (fileExists || otherDuplicatePaths.Count > 0))
|
||||
if (!overwriteExisting)
|
||||
{
|
||||
result.Status = FileSortingStatus.SkippedExisting;
|
||||
result.StatusMessage = string.Empty;
|
||||
result.DuplicatePaths = otherDuplicatePaths;
|
||||
return;
|
||||
if (options.CopyOriginalFile && fileExists && IsSameEpisode(sourcePath, newPath))
|
||||
{
|
||||
_logger.Info("File {0} already copied to new path {1}, stopping organization", sourcePath, newPath);
|
||||
result.Status = FileSortingStatus.SkippedExisting;
|
||||
result.StatusMessage = string.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileExists || otherDuplicatePaths.Count > 0)
|
||||
{
|
||||
result.Status = FileSortingStatus.SkippedExisting;
|
||||
result.StatusMessage = string.Empty;
|
||||
result.DuplicatePaths = otherDuplicatePaths;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PerformFileSorting(options, result);
|
||||
@@ -266,7 +277,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||
|
||||
try
|
||||
{
|
||||
if (copy)
|
||||
if (copy || options.CopyOriginalFile)
|
||||
{
|
||||
File.Copy(result.OriginalPath, result.TargetPath, true);
|
||||
}
|
||||
@@ -293,7 +304,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||
_libraryMonitor.ReportFileSystemChangeComplete(result.TargetPath, true);
|
||||
}
|
||||
|
||||
if (copy)
|
||||
if (copy && !options.CopyOriginalFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -439,5 +450,27 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||
.Replace("%0e", episodeNumber.ToString("00", _usCulture))
|
||||
.Replace("%00e", episodeNumber.ToString("000", _usCulture));
|
||||
}
|
||||
|
||||
private bool IsSameEpisode(string sourcePath, string newPath)
|
||||
{
|
||||
|
||||
FileInfo sourceFileInfo = new FileInfo(sourcePath);
|
||||
FileInfo destinationFileInfo = new FileInfo(newPath);
|
||||
|
||||
try
|
||||
{
|
||||
if (sourceFileInfo.Length == destinationFileInfo.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||
var organizer = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager,
|
||||
_libraryMonitor, _providerManager);
|
||||
|
||||
var result = await organizer.OrganizeEpisodeFile(file.FullName, options, false, cancellationToken).ConfigureAwait(false);
|
||||
var result = await organizer.OrganizeEpisodeFile(file.FullName, options, options.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (result.Status == FileSortingStatus.Success)
|
||||
{
|
||||
|
||||
@@ -306,6 +306,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
throw new ArgumentNullException("path");
|
||||
}
|
||||
|
||||
return GetStaticFileResult(requestContext, path, MimeTypes.GetMimeType(path), fileShare, responseHeaders, isHeadRequest);
|
||||
}
|
||||
|
||||
public object GetStaticFileResult(IRequest requestContext, string path, string contentType,
|
||||
FileShare fileShare = FileShare.Read, IDictionary<string, string> responseHeaders = null,
|
||||
bool isHeadRequest = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentNullException("path");
|
||||
}
|
||||
|
||||
if (fileShare != FileShare.Read && fileShare != FileShare.ReadWrite)
|
||||
{
|
||||
throw new ArgumentException("FileShare must be either Read or ReadWrite");
|
||||
@@ -315,7 +327,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
|
||||
var cacheKey = path + dateModified.Ticks;
|
||||
|
||||
return GetStaticResult(requestContext, cacheKey.GetMD5(), dateModified, null, MimeTypes.GetMimeType(path), () => Task.FromResult(GetFileStream(path, fileShare)), responseHeaders, isHeadRequest);
|
||||
return GetStaticResult(requestContext, cacheKey.GetMD5(), dateModified, null, contentType, () => Task.FromResult(GetFileStream(path, fileShare)), responseHeaders, isHeadRequest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -449,7 +449,14 @@ namespace MediaBrowser.Server.Implementations.IO
|
||||
var paths = _affectedPaths.Keys.ToList();
|
||||
_affectedPaths.Clear();
|
||||
|
||||
await ProcessPathChanges(paths).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await ProcessPathChanges(paths).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error processing directory changes", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void DisposeTimer()
|
||||
|
||||
@@ -5,6 +5,7 @@ using MediaBrowser.Common.ScheduledTasks;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Controller.Library;
|
||||
@@ -484,6 +485,9 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
await ItemRepository.DeleteItem(child.Id, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
BaseItem removed;
|
||||
_libraryItemsCache.TryRemove(item.Id, out removed);
|
||||
|
||||
ReportItemRemoved(item);
|
||||
}
|
||||
|
||||
@@ -922,10 +926,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
/// <returns>Task.</returns>
|
||||
public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
// Ensure the location is unavailable.
|
||||
// Ensure the location is available.
|
||||
Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath);
|
||||
|
||||
return new PeopleValidator(this, _logger).ValidatePeople(cancellationToken, progress);
|
||||
return new PeopleValidator(this, _logger).ValidatePeople(cancellationToken, new MetadataRefreshOptions(), progress);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -953,7 +957,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
// Ensure the location is unavailable.
|
||||
Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.MusicGenrePath);
|
||||
|
||||
return new MusicGenresValidator(this, _userManager, _logger).Run(progress, cancellationToken);
|
||||
return new MusicGenresValidator(this, _logger).Run(progress, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
|
||||
|
||||
var collectionType = args.GetCollectionType();
|
||||
|
||||
// If there's a collection type and it's not music, it can't be a series
|
||||
// If there's a collection type and it's not music, don't allow it.
|
||||
if (!string.IsNullOrEmpty(collectionType) &&
|
||||
!string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
||||
@@ -56,21 +56,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the parent is not a boxset, the only other allowed parent type is Folder
|
||||
if (!(args.Parent is BoxSet))
|
||||
{
|
||||
if (args.Parent.GetType() != typeof(Folder))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since the looping is expensive, this is an optimization to help us avoid it
|
||||
if (args.Path.IndexOf("[tvdbid", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var isDirectory = args.IsDirectory;
|
||||
@@ -89,34 +74,31 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
||||
// Find movies with their own folders
|
||||
if (isDirectory)
|
||||
{
|
||||
if (args.Path.IndexOf("[trailers]", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
string.Equals(collectionType, CollectionType.Trailers, StringComparison.OrdinalIgnoreCase))
|
||||
if (string.Equals(collectionType, CollectionType.Trailers, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return FindMovie<Trailer>(args.Path, args.Parent, args.FileSystemChildren, args.DirectoryService);
|
||||
return FindMovie<Trailer>(args.Path, args.Parent, args.FileSystemChildren, args.DirectoryService, false);
|
||||
}
|
||||
|
||||
if (args.Path.IndexOf("[musicvideos]", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
|
||||
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return FindMovie<MusicVideo>(args.Path, args.Parent, args.FileSystemChildren, args.DirectoryService);
|
||||
return FindMovie<MusicVideo>(args.Path, args.Parent, args.FileSystemChildren, args.DirectoryService, false);
|
||||
}
|
||||
|
||||
if (args.Path.IndexOf("[adultvideos]", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
string.Equals(collectionType, CollectionType.AdultVideos, StringComparison.OrdinalIgnoreCase))
|
||||
if (string.Equals(collectionType, CollectionType.AdultVideos, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return FindMovie<AdultVideo>(args.Path, args.Parent, args.FileSystemChildren, args.DirectoryService);
|
||||
return FindMovie<AdultVideo>(args.Path, args.Parent, args.FileSystemChildren, args.DirectoryService, true);
|
||||
}
|
||||
|
||||
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren, args.DirectoryService);
|
||||
return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren, args.DirectoryService, true);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(collectionType) ||
|
||||
string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(collectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return FindMovie<Movie>(args.Path, args.Parent, args.FileSystemChildren, args.DirectoryService);
|
||||
return FindMovie<Movie>(args.Path, args.Parent, args.FileSystemChildren, args.DirectoryService, true);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -202,8 +184,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
||||
/// <param name="path">The path.</param>
|
||||
/// <param name="parent">The parent.</param>
|
||||
/// <param name="fileSystemEntries">The file system entries.</param>
|
||||
/// <param name="directoryService">The directory service.</param>
|
||||
/// <param name="supportMultiFileItems">if set to <c>true</c> [support multi file items].</param>
|
||||
/// <returns>Movie.</returns>
|
||||
private T FindMovie<T>(string path, Folder parent, IEnumerable<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService)
|
||||
private T FindMovie<T>(string path, Folder parent, IEnumerable<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, bool supportMultiFileItems)
|
||||
where T : Video, new()
|
||||
{
|
||||
var movies = new List<T>();
|
||||
@@ -264,7 +248,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
||||
}
|
||||
}
|
||||
|
||||
if (movies.Count > 1)
|
||||
if (movies.Count > 1 && supportMultiFileItems)
|
||||
{
|
||||
return GetMultiFileMovie(movies);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,12 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
|
||||
var results = await GetSearchHints(inputItems, query).ConfigureAwait(false);
|
||||
|
||||
// Include item types
|
||||
if (query.IncludeItemTypes.Length > 0)
|
||||
{
|
||||
results = results.Where(f => query.IncludeItemTypes.Contains(f.Item.GetType().Name, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
var searchResultArray = results.ToArray();
|
||||
results = searchResultArray;
|
||||
|
||||
@@ -96,7 +102,9 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
if (query.IncludeArtists)
|
||||
{
|
||||
// Find artists
|
||||
var artists = _libraryManager.GetAllArtists(items)
|
||||
var artists = items.OfType<Audio>()
|
||||
.SelectMany(i => i.AllArtists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
foreach (var item in artists)
|
||||
|
||||
@@ -189,15 +189,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
/// Refreshes metadata for each user
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="force">if set to <c>true</c> [force].</param>
|
||||
/// <returns>Task.</returns>
|
||||
public Task RefreshUsersMetadata(CancellationToken cancellationToken, bool force = false)
|
||||
public Task RefreshUsersMetadata(CancellationToken cancellationToken)
|
||||
{
|
||||
var tasks = Users.Select(user => user.RefreshMetadata(new MetadataRefreshOptions
|
||||
{
|
||||
ReplaceAllMetadata = force
|
||||
|
||||
}, cancellationToken)).ToList();
|
||||
var tasks = Users.Select(user => user.RefreshMetadata(new MetadataRefreshOptions(), cancellationToken)).ToList();
|
||||
|
||||
return Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
@@ -69,10 +67,6 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
var userLibraries = _userManager.Users
|
||||
.Select(i => new Tuple<Guid, List<IHasArtist>>(i.Id, i.RootFolder.GetRecursiveChildren(i).OfType<IHasArtist>().ToList()))
|
||||
.ToList();
|
||||
|
||||
var numArtists = allArtists.Count;
|
||||
|
||||
foreach (var artist in allArtists)
|
||||
@@ -91,11 +85,6 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
.ToList();
|
||||
}
|
||||
|
||||
foreach (var lib in userLibraries)
|
||||
{
|
||||
SetItemCounts(artist, lib.Item1, lib.Item2);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= numArtists;
|
||||
@@ -107,37 +96,6 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the item counts.
|
||||
/// </summary>
|
||||
/// <param name="artist">The artist.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="allItems">All items.</param>
|
||||
private void SetItemCounts(MusicArtist artist, Guid? userId, IEnumerable<IHasArtist> allItems)
|
||||
{
|
||||
var name = artist.Name;
|
||||
|
||||
var items = allItems
|
||||
.Where(i => i.HasArtist(name))
|
||||
.ToList();
|
||||
|
||||
var counts = new ItemByNameCounts
|
||||
{
|
||||
TotalCount = items.Count,
|
||||
|
||||
SongCount = items.OfType<Audio>().Count(),
|
||||
|
||||
AlbumCount = items.OfType<MusicAlbum>().Count(),
|
||||
|
||||
MusicVideoCount = items.OfType<MusicVideo>().Count()
|
||||
};
|
||||
|
||||
if (userId.HasValue)
|
||||
{
|
||||
artist.SetItemByNameCounts(userId.Value, counts);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all artists.
|
||||
/// </summary>
|
||||
@@ -147,7 +105,8 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
/// <returns>Task{Artist[]}.</returns>
|
||||
private async Task<List<MusicArtist>> GetAllArtists(IEnumerable<Audio> allSongs, CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
var allArtists = _libraryManager.GetAllArtists(allSongs)
|
||||
var allArtists = allSongs.SelectMany(i => i.AllArtists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var returnArtists = new List<MusicArtist>(allArtists.Count);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -41,38 +40,24 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
/// <returns>Task.</returns>
|
||||
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
var userLibraries = _userManager.Users
|
||||
.Select(i => new Tuple<Guid, List<Game>>(i.Id, i.RootFolder.GetRecursiveChildren(i).OfType<Game>().ToList()))
|
||||
var items = _libraryManager.RootFolder.RecursiveChildren.Where(i => (i is Game))
|
||||
.SelectMany(i => i.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
progress.Report(2);
|
||||
|
||||
var numComplete = 0;
|
||||
var count = items.Count;
|
||||
|
||||
foreach (var lib in userLibraries)
|
||||
foreach (var name in items)
|
||||
{
|
||||
SetItemCounts(lib.Item1, lib.Item2, masterDictionary);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= userLibraries.Count;
|
||||
percent *= 8;
|
||||
|
||||
progress.Report(percent);
|
||||
}
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
var count = masterDictionary.Count;
|
||||
numComplete = 0;
|
||||
|
||||
foreach (var name in masterDictionary.Keys)
|
||||
{
|
||||
try
|
||||
{
|
||||
await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false);
|
||||
var itemByName = _libraryManager.GetGameGenre(name);
|
||||
|
||||
await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@@ -81,7 +66,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error updating counts for {0}", ex, name);
|
||||
_logger.ErrorException("Error refreshing {0}", ex, name);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
@@ -94,32 +79,5 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
private Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<CountType, int>> counts)
|
||||
{
|
||||
var itemByName = _libraryManager.GetGameGenre(name);
|
||||
|
||||
foreach (var libraryId in counts.Keys)
|
||||
{
|
||||
var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
|
||||
|
||||
itemByName.SetItemByNameCounts(libraryId, itemCounts);
|
||||
}
|
||||
|
||||
return itemByName.RefreshMetadata(cancellationToken);
|
||||
}
|
||||
|
||||
private void SetItemCounts(Guid userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>> masterDictionary)
|
||||
{
|
||||
foreach (var media in allItems)
|
||||
{
|
||||
var names = media
|
||||
.Genres
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
CountHelpers.SetItemCounts(userId, media, names, masterDictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -42,38 +41,24 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
/// <returns>Task.</returns>
|
||||
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
var userLibraries = _userManager.Users
|
||||
.Select(i => new Tuple<Guid, IList<BaseItem>>(i.Id, i.RootFolder.GetRecursiveChildren(i, m => !(m is IHasMusicGenres) && !(m is Game))))
|
||||
var items = _libraryManager.RootFolder.RecursiveChildren.Where(i => !(i is IHasMusicGenres) && !(i is Game))
|
||||
.SelectMany(i => i.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
progress.Report(2);
|
||||
|
||||
var numComplete = 0;
|
||||
var count = items.Count;
|
||||
|
||||
foreach (var lib in userLibraries)
|
||||
foreach (var name in items)
|
||||
{
|
||||
SetItemCounts(lib.Item1, lib.Item2, masterDictionary);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= userLibraries.Count;
|
||||
percent *= 8;
|
||||
|
||||
progress.Report(percent);
|
||||
}
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
var count = masterDictionary.Count;
|
||||
numComplete = 0;
|
||||
|
||||
foreach (var name in masterDictionary.Keys)
|
||||
{
|
||||
try
|
||||
{
|
||||
await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false);
|
||||
var itemByName = _libraryManager.GetGenre(name);
|
||||
|
||||
await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@@ -82,7 +67,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error updating counts for {0}", ex, name);
|
||||
_logger.ErrorException("Error refreshing {0}", ex, name);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
@@ -95,32 +80,5 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
private Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<CountType, int>> counts)
|
||||
{
|
||||
var itemByName = _libraryManager.GetGenre(name);
|
||||
|
||||
foreach (var libraryId in counts.Keys)
|
||||
{
|
||||
var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
|
||||
|
||||
itemByName.SetItemByNameCounts(libraryId, itemCounts);
|
||||
}
|
||||
|
||||
return itemByName.RefreshMetadata(cancellationToken);
|
||||
}
|
||||
|
||||
private void SetItemCounts(Guid userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>> masterDictionary)
|
||||
{
|
||||
foreach (var media in allItems)
|
||||
{
|
||||
var names = media
|
||||
.Genres
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
CountHelpers.SetItemCounts(userId, media, names, masterDictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -17,20 +15,14 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _logger
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public MusicGenresValidator(ILibraryManager libraryManager, IUserManager userManager, ILogger logger)
|
||||
public MusicGenresValidator(ILibraryManager libraryManager, ILogger logger)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -42,38 +34,24 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
/// <returns>Task.</returns>
|
||||
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
var userLibraries = _userManager.Users
|
||||
.Select(i => new Tuple<Guid, IList<BaseItem>>(i.Id, i.RootFolder.GetRecursiveChildren(i, m => m is IHasMusicGenres)))
|
||||
var items = _libraryManager.RootFolder.RecursiveChildren.Where(i => (i is IHasMusicGenres))
|
||||
.SelectMany(i => i.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
progress.Report(2);
|
||||
|
||||
var numComplete = 0;
|
||||
var count = items.Count;
|
||||
|
||||
foreach (var lib in userLibraries)
|
||||
foreach (var name in items)
|
||||
{
|
||||
SetItemCounts(lib.Item1, lib.Item2, masterDictionary);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= userLibraries.Count;
|
||||
percent *= 8;
|
||||
|
||||
progress.Report(percent);
|
||||
}
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
var count = masterDictionary.Count;
|
||||
numComplete = 0;
|
||||
|
||||
foreach (var name in masterDictionary.Keys)
|
||||
{
|
||||
try
|
||||
{
|
||||
await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false);
|
||||
var itemByName = _libraryManager.GetMusicGenre(name);
|
||||
|
||||
await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@@ -82,7 +60,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error updating counts for {0}", ex, name);
|
||||
_logger.ErrorException("Error refreshing {0}", ex, name);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
@@ -95,32 +73,5 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
private Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<CountType, int>> counts)
|
||||
{
|
||||
var itemByName = _libraryManager.GetMusicGenre(name);
|
||||
|
||||
foreach (var libraryId in counts.Keys)
|
||||
{
|
||||
var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
|
||||
|
||||
itemByName.SetItemByNameCounts(libraryId, itemCounts);
|
||||
}
|
||||
|
||||
return itemByName.RefreshMetadata(cancellationToken);
|
||||
}
|
||||
|
||||
private void SetItemCounts(Guid userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>> masterDictionary)
|
||||
{
|
||||
foreach (var media in allItems)
|
||||
{
|
||||
var names = media
|
||||
.Genres
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
CountHelpers.SetItemCounts(userId, media, names, masterDictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -17,20 +14,14 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _logger
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public PeoplePostScanTask(ILibraryManager libraryManager, IUserManager userManager, ILogger logger)
|
||||
public PeoplePostScanTask(ILibraryManager libraryManager, ILogger logger)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -42,94 +33,12 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
/// <returns>Task.</returns>
|
||||
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
return RunInternal(progress, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task RunInternal(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
var userLibraries = _userManager.Users
|
||||
.Select(i => new Tuple<Guid, IList<BaseItem>>(i.Id, i.RootFolder.GetRecursiveChildren(i, null)))
|
||||
.ToList();
|
||||
|
||||
var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
progress.Report(2);
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
foreach (var lib in userLibraries)
|
||||
return new PeopleValidator(_libraryManager, _logger).ValidatePeople(cancellationToken, new MetadataRefreshOptions
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ImageRefreshMode = ImageRefreshMode.ValidationOnly,
|
||||
MetadataRefreshMode = MetadataRefreshMode.None
|
||||
|
||||
SetItemCounts(lib.Item1, lib.Item2, masterDictionary);
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= userLibraries.Count;
|
||||
percent *= 8;
|
||||
|
||||
progress.Report(percent);
|
||||
}
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
var count = masterDictionary.Count;
|
||||
numComplete = 0;
|
||||
|
||||
foreach (var name in masterDictionary.Keys)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
try
|
||||
{
|
||||
var counts = masterDictionary[name];
|
||||
|
||||
var itemByName = _libraryManager.GetPerson(name);
|
||||
|
||||
// The only purpose here is to be able to react to image changes without running the people task.
|
||||
// All other metadata can wait for that.
|
||||
await itemByName.RefreshMetadata(new MetadataRefreshOptions
|
||||
{
|
||||
ImageRefreshMode = ImageRefreshMode.ValidationOnly,
|
||||
MetadataRefreshMode = MetadataRefreshMode.None
|
||||
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
foreach (var libraryId in counts.Keys)
|
||||
{
|
||||
var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
|
||||
|
||||
itemByName.SetItemByNameCounts(libraryId, itemCounts);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error updating counts for {0}", ex, name);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= count;
|
||||
percent *= 90;
|
||||
|
||||
progress.Report(percent + 10);
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
}, progress);
|
||||
}
|
||||
|
||||
private void SetItemCounts(Guid userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>> masterDictionary)
|
||||
{
|
||||
foreach (var media in allItems)
|
||||
{
|
||||
var names = media
|
||||
.People.Select(i => i.Name)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
CountHelpers.SetItemCounts(userId, media, names, masterDictionary);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MoreLinq;
|
||||
using System;
|
||||
@@ -38,9 +39,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
/// Validates the people.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
public async Task ValidatePeople(CancellationToken cancellationToken, MetadataRefreshOptions options, IProgress<double> progress)
|
||||
{
|
||||
var innerProgress = new ActionableProgress<double>();
|
||||
|
||||
@@ -61,7 +63,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
{
|
||||
var item = _libraryManager.GetPerson(person.Name);
|
||||
|
||||
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
|
||||
await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -41,38 +39,24 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
/// <returns>Task.</returns>
|
||||
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
var userLibraries = _userManager.Users
|
||||
.Select(i => new Tuple<Guid, IList<BaseItem>>(i.Id, i.RootFolder.GetRecursiveChildren(i, null)))
|
||||
var items = _libraryManager.RootFolder.RecursiveChildren
|
||||
.SelectMany(i => i.Studios)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
progress.Report(2);
|
||||
|
||||
var numComplete = 0;
|
||||
var count = items.Count;
|
||||
|
||||
foreach (var lib in userLibraries)
|
||||
foreach (var name in items)
|
||||
{
|
||||
SetItemCounts(lib.Item1, lib.Item2, masterDictionary);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= userLibraries.Count;
|
||||
percent *= 8;
|
||||
|
||||
progress.Report(percent);
|
||||
}
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
var count = masterDictionary.Count;
|
||||
numComplete = 0;
|
||||
|
||||
foreach (var name in masterDictionary.Keys)
|
||||
{
|
||||
try
|
||||
{
|
||||
await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false);
|
||||
var itemByName = _libraryManager.GetStudio(name);
|
||||
|
||||
await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@@ -81,7 +65,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error updating counts for {0}", ex, name);
|
||||
_logger.ErrorException("Error refreshing {0}", ex, name);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
@@ -94,32 +78,5 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
private Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<CountType, int>> counts)
|
||||
{
|
||||
var itemByName = _libraryManager.GetStudio(name);
|
||||
|
||||
foreach (var libraryId in counts.Keys)
|
||||
{
|
||||
var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
|
||||
|
||||
itemByName.SetItemByNameCounts(libraryId, itemCounts);
|
||||
}
|
||||
|
||||
return itemByName.RefreshMetadata(cancellationToken);
|
||||
}
|
||||
|
||||
private void SetItemCounts(Guid userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>> masterDictionary)
|
||||
{
|
||||
foreach (var media in allItems)
|
||||
{
|
||||
var names = media
|
||||
.Studios
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
CountHelpers.SetItemCounts(userId, media, names, masterDictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
|
||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
||||
{
|
||||
return !item.HasImage(ImageType.Primary) && (DateTime.UtcNow - date).TotalDays >= 1;
|
||||
var liveTvItem = item as LiveTvChannel;
|
||||
|
||||
if (liveTvItem != null)
|
||||
{
|
||||
return !liveTvItem.HasImage(ImageType.Primary) && (liveTvItem.HasProviderImage ?? true) && (DateTime.UtcNow - date).TotalHours >= 6;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
|
||||
private List<Guid> _channelIdList = new List<Guid>();
|
||||
private Dictionary<Guid, LiveTvProgram> _programs = new Dictionary<Guid, LiveTvProgram>();
|
||||
private readonly ConcurrentDictionary<Guid, bool> _refreshedPrograms = new ConcurrentDictionary<Guid, bool>();
|
||||
|
||||
private readonly SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1);
|
||||
|
||||
@@ -106,7 +107,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
_taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
|
||||
}
|
||||
|
||||
public Task<QueryResult<ChannelInfoDto>> GetChannels(ChannelQuery query, CancellationToken cancellationToken)
|
||||
public async Task<QueryResult<ChannelInfoDto>> GetChannels(ChannelQuery query, CancellationToken cancellationToken)
|
||||
{
|
||||
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(new Guid(query.UserId));
|
||||
|
||||
@@ -161,17 +162,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
allEnumerable = allEnumerable.Take(query.Limit.Value);
|
||||
}
|
||||
|
||||
var returnChannels = allEnumerable
|
||||
.Select(i => _tvDtoService.GetChannelInfoDto(i, GetCurrentProgram(i.ExternalId), user))
|
||||
.ToArray();
|
||||
var returnList = new List<ChannelInfoDto>();
|
||||
|
||||
foreach (var channel in allEnumerable)
|
||||
{
|
||||
var currentProgram = await GetCurrentProgram(channel.ExternalId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
returnList.Add(_tvDtoService.GetChannelInfoDto(channel, currentProgram, user));
|
||||
}
|
||||
|
||||
var result = new QueryResult<ChannelInfoDto>
|
||||
{
|
||||
Items = returnChannels,
|
||||
Items = returnList.ToArray(),
|
||||
TotalRecordCount = allChannels.Count
|
||||
};
|
||||
|
||||
return Task.FromResult(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public LiveTvChannel GetInternalChannel(string id)
|
||||
@@ -184,16 +190,41 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
return _libraryManager.GetItemById(id) as LiveTvChannel;
|
||||
}
|
||||
|
||||
public LiveTvProgram GetInternalProgram(string id)
|
||||
public async Task<LiveTvProgram> GetInternalProgram(string id, CancellationToken cancellationToken)
|
||||
{
|
||||
var guid = new Guid(id);
|
||||
|
||||
LiveTvProgram obj = null;
|
||||
|
||||
_programs.TryGetValue(guid, out obj);
|
||||
|
||||
if (obj != null)
|
||||
{
|
||||
await RefreshIfNeeded(obj, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
private async Task RefreshIfNeeded(IEnumerable<LiveTvProgram> programs, CancellationToken cancellationToken)
|
||||
{
|
||||
foreach (var program in programs)
|
||||
{
|
||||
await RefreshIfNeeded(program, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RefreshIfNeeded(LiveTvProgram program, CancellationToken cancellationToken)
|
||||
{
|
||||
if (_refreshedPrograms.ContainsKey(program.Id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await program.RefreshMetadata(CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
_refreshedPrograms.TryAdd(program.Id, true);
|
||||
}
|
||||
|
||||
public async Task<ILiveTvRecording> GetInternalRecording(string id, CancellationToken cancellationToken)
|
||||
{
|
||||
var service = ActiveService;
|
||||
@@ -336,10 +367,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
return item;
|
||||
}
|
||||
|
||||
private async Task<LiveTvProgram> GetProgram(ProgramInfo info, ChannelType channelType, string serviceName, CancellationToken cancellationToken)
|
||||
private LiveTvProgram GetProgram(ProgramInfo info, ChannelType channelType, string serviceName, CancellationToken cancellationToken)
|
||||
{
|
||||
var isNew = false;
|
||||
|
||||
var id = _tvDtoService.GetInternalProgramId(serviceName, info.Id);
|
||||
|
||||
var item = _itemRepo.RetrieveItem(id) as LiveTvProgram;
|
||||
@@ -353,8 +382,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
DateCreated = DateTime.UtcNow,
|
||||
DateModified = DateTime.UtcNow
|
||||
};
|
||||
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
item.ChannelType = channelType;
|
||||
@@ -386,12 +413,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
item.RunTimeTicks = (info.EndDate - info.StartDate).Ticks;
|
||||
item.StartDate = info.StartDate;
|
||||
|
||||
await item.RefreshMetadata(new MetadataRefreshOptions
|
||||
{
|
||||
ForceSave = isNew
|
||||
|
||||
}, cancellationToken);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -464,7 +485,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
|
||||
public async Task<ProgramInfoDto> GetProgram(string id, CancellationToken cancellationToken, User user = null)
|
||||
{
|
||||
var program = GetInternalProgram(id);
|
||||
var program = await GetInternalProgram(id, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var channel = GetChannel(program);
|
||||
|
||||
@@ -531,7 +552,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
programs = programs.Where(i => i.IsParentalAllowed(currentUser));
|
||||
}
|
||||
|
||||
var returnArray = programs
|
||||
var programList = programs.ToList();
|
||||
|
||||
var returnArray = programList
|
||||
.Select(i =>
|
||||
{
|
||||
var channel = GetChannel(i);
|
||||
@@ -540,6 +563,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
await RefreshIfNeeded(programList, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await AddRecordingInfo(returnArray, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var result = new QueryResult<ProgramInfoDto>
|
||||
@@ -582,7 +607,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
.Select(i => _libraryManager.GetGenre(i))
|
||||
.ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
programs = programList.OrderByDescending(i => GetRecommendationScore(i, user.Id, serviceName, genres))
|
||||
programs = programList.OrderBy(i => i.HasImage(ImageType.Primary) ? 0 : 1)
|
||||
.ThenByDescending(i => GetRecommendationScore(i, user.Id, serviceName, genres))
|
||||
.ThenBy(i => i.StartDate);
|
||||
|
||||
if (query.Limit.HasValue)
|
||||
@@ -591,7 +617,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
.OrderBy(i => i.StartDate);
|
||||
}
|
||||
|
||||
var returnArray = programs
|
||||
programList = programs.ToList();
|
||||
|
||||
await RefreshIfNeeded(programList, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var returnArray = programList
|
||||
.Select(i =>
|
||||
{
|
||||
var channel = GetChannel(i);
|
||||
@@ -790,8 +820,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
|
||||
var channelPrograms = await service.GetProgramsAsync(currentChannel.ExternalId, start, end, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var programTasks = channelPrograms.Select(program => GetProgram(program, currentChannel.ChannelType, service.Name, cancellationToken));
|
||||
var programEntities = await Task.WhenAll(programTasks).ConfigureAwait(false);
|
||||
var programEntities = channelPrograms.Select(program => GetProgram(program, currentChannel.ChannelType, service.Name, cancellationToken));
|
||||
|
||||
programs.AddRange(programEntities);
|
||||
}
|
||||
@@ -812,6 +841,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
}
|
||||
|
||||
_programs = programs.ToDictionary(i => i.Id);
|
||||
_refreshedPrograms.Clear();
|
||||
progress.Report(90);
|
||||
|
||||
// Load these now which will prefetch metadata
|
||||
@@ -955,6 +985,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
entities = entities.Where(i => i.IsParentalAllowed(currentUser));
|
||||
}
|
||||
|
||||
var entityList = entities.ToList();
|
||||
entities = entityList;
|
||||
|
||||
if (query.StartIndex.HasValue)
|
||||
{
|
||||
entities = entities.Skip(query.StartIndex.Value);
|
||||
@@ -976,7 +1009,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
return new QueryResult<RecordingInfoDto>
|
||||
{
|
||||
Items = returnArray,
|
||||
TotalRecordCount = returnArray.Length
|
||||
TotalRecordCount = entityList.Count
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1030,14 +1063,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
.Where(i => _tvDtoService.GetInternalSeriesTimerId(currentServiceName, i.SeriesTimerId) == guid);
|
||||
}
|
||||
|
||||
var returnArray = timers
|
||||
.Select(i =>
|
||||
{
|
||||
var program = string.IsNullOrEmpty(i.ProgramId) ? null : GetInternalProgram(_tvDtoService.GetInternalProgramId(service.Name, i.ProgramId).ToString("N"));
|
||||
var channel = string.IsNullOrEmpty(i.ChannelId) ? null : GetInternalChannel(_tvDtoService.GetInternalChannelId(service.Name, i.ChannelId));
|
||||
var returnList = new List<TimerInfoDto>();
|
||||
|
||||
return _tvDtoService.GetTimerInfoDto(i, service, program, channel);
|
||||
})
|
||||
foreach (var i in timers)
|
||||
{
|
||||
var program = string.IsNullOrEmpty(i.ProgramId) ?
|
||||
null :
|
||||
await GetInternalProgram(_tvDtoService.GetInternalProgramId(service.Name, i.ProgramId).ToString("N"), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var channel = string.IsNullOrEmpty(i.ChannelId) ? null : GetInternalChannel(_tvDtoService.GetInternalChannelId(service.Name, i.ChannelId));
|
||||
|
||||
returnList.Add(_tvDtoService.GetTimerInfoDto(i, service, program, channel));
|
||||
}
|
||||
|
||||
var returnArray = returnList
|
||||
.OrderBy(i => i.StartDate)
|
||||
.ToArray();
|
||||
|
||||
@@ -1162,24 +1201,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
};
|
||||
}
|
||||
|
||||
public Task<ChannelInfoDto> GetChannel(string id, CancellationToken cancellationToken, User user = null)
|
||||
public async Task<ChannelInfoDto> GetChannel(string id, CancellationToken cancellationToken, User user = null)
|
||||
{
|
||||
var channel = GetInternalChannel(id);
|
||||
|
||||
var dto = _tvDtoService.GetChannelInfoDto(channel, GetCurrentProgram(channel.ExternalId), user);
|
||||
var currentProgram = await GetCurrentProgram(channel.ExternalId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return Task.FromResult(dto);
|
||||
var dto = _tvDtoService.GetChannelInfoDto(channel, currentProgram, user);
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
private LiveTvProgram GetCurrentProgram(string externalChannelId)
|
||||
private async Task<LiveTvProgram> GetCurrentProgram(string externalChannelId, CancellationToken cancellationToken)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
return _programs.Values
|
||||
var program = _programs.Values
|
||||
.Where(i => string.Equals(externalChannelId, i.ExternalChannelId, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderBy(i => i.StartDate)
|
||||
.SkipWhile(i => now >= (i.EndDate ?? DateTime.MinValue))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (program != null)
|
||||
{
|
||||
await RefreshIfNeeded(program, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
private async Task<SeriesTimerInfo> GetNewTimerDefaultsInternal(CancellationToken cancellationToken, LiveTvProgram program = null)
|
||||
@@ -1235,7 +1283,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
|
||||
public async Task<SeriesTimerInfoDto> GetNewTimerDefaults(string programId, CancellationToken cancellationToken)
|
||||
{
|
||||
var program = GetInternalProgram(programId);
|
||||
var program = await GetInternalProgram(programId, cancellationToken).ConfigureAwait(false);
|
||||
var programDto = await GetProgram(programId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var defaults = await GetNewTimerDefaultsInternal(cancellationToken, program).ConfigureAwait(false);
|
||||
|
||||
@@ -105,7 +105,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
|
||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
||||
{
|
||||
return !item.HasImage(ImageType.Primary) && (DateTime.UtcNow - date).TotalHours >= 6;
|
||||
var liveTvItem = item as LiveTvProgram;
|
||||
|
||||
if (liveTvItem != null)
|
||||
{
|
||||
return !liveTvItem.HasImage(ImageType.Primary) && (liveTvItem.HasProviderImage ?? true) && (DateTime.UtcNow - date).TotalHours >= 6;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
|
||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
||||
{
|
||||
return !item.HasImage(ImageType.Primary) && (DateTime.UtcNow - date).TotalHours >= 3;
|
||||
var liveTvItem = item as ILiveTvRecording;
|
||||
|
||||
if (liveTvItem != null)
|
||||
{
|
||||
return !liveTvItem.HasImage(ImageType.Primary) && (liveTvItem.RecordingInfo.HasImage ?? true) && (DateTime.UtcNow - date).TotalHours >= 6;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,20 +56,18 @@
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\DvdLib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Nat">
|
||||
<HintPath>..\packages\Mono.Nat.1.1.13\lib\Net40\Mono.Nat.dll</HintPath>
|
||||
<Reference Include="Mono.Nat, Version=1.2.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Mono.Nat.1.2.3\lib\Net40\Mono.Nat.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Api.Swagger">
|
||||
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SQLite, Version=1.0.90.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=x86" Condition=" '$(ConfigurationName)' != 'Release Mono' ">
|
||||
<Reference Include="System.Data.SQLite, Version=1.0.91.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\System.Data.SQLite.x86.1.0.90.0\lib\net45\System.Data.SQLite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SQLite.Linq" Condition=" '$(ConfigurationName)' != 'Release Mono' ">
|
||||
<HintPath>..\packages\System.Data.SQLite.x86.1.0.90.0\lib\net45\System.Data.SQLite.Linq.dll</HintPath>
|
||||
<HintPath>..\packages\System.Data.SQLite.Core.1.0.91.3\lib\net45\System.Data.SQLite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
@@ -108,6 +106,8 @@
|
||||
<Link>Properties\SharedVersion.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="BdInfo\BdInfoExaminer.cs" />
|
||||
<Compile Include="Collections\CollectionManager.cs" />
|
||||
<Compile Include="Collections\CollectionsDynamicFolder.cs" />
|
||||
<Compile Include="Configuration\ServerConfigurationManager.cs" />
|
||||
<Compile Include="Drawing\ImageHeader.cs" />
|
||||
<Compile Include="Drawing\PercentPlayedDrawer.cs" />
|
||||
@@ -216,7 +216,6 @@
|
||||
<Compile Include="Sorting\AirTimeComparer.cs" />
|
||||
<Compile Include="Sorting\AlbumArtistComparer.cs" />
|
||||
<Compile Include="Sorting\AlbumComparer.cs" />
|
||||
<Compile Include="Sorting\AlbumCountComparer.cs" />
|
||||
<Compile Include="Sorting\AlphanumComparator.cs" />
|
||||
<Compile Include="Sorting\ArtistComparer.cs" />
|
||||
<Compile Include="Sorting\BudgetComparer.cs" />
|
||||
@@ -224,29 +223,26 @@
|
||||
<Compile Include="Sorting\CriticRatingComparer.cs" />
|
||||
<Compile Include="Sorting\DateCreatedComparer.cs" />
|
||||
<Compile Include="Sorting\DatePlayedComparer.cs" />
|
||||
<Compile Include="Sorting\EpisodeCountComparer.cs" />
|
||||
<Compile Include="Sorting\GameSystemComparer.cs" />
|
||||
<Compile Include="Sorting\IsFolderComparer.cs" />
|
||||
<Compile Include="Sorting\IsUnplayedComparer.cs" />
|
||||
<Compile Include="Sorting\MetascoreComparer.cs" />
|
||||
<Compile Include="Sorting\MovieCountComparer.cs" />
|
||||
<Compile Include="Sorting\MusicVideoCountComparer.cs" />
|
||||
<Compile Include="Sorting\NameComparer.cs" />
|
||||
<Compile Include="Sorting\OfficialRatingComparer.cs" />
|
||||
<Compile Include="Sorting\PlayCountComparer.cs" />
|
||||
<Compile Include="Sorting\PlayersComparer.cs" />
|
||||
<Compile Include="Sorting\PremiereDateComparer.cs" />
|
||||
<Compile Include="Sorting\ProductionYearComparer.cs" />
|
||||
<Compile Include="Sorting\RandomComparer.cs" />
|
||||
<Compile Include="Sorting\RevenueComparer.cs" />
|
||||
<Compile Include="Sorting\RuntimeComparer.cs" />
|
||||
<Compile Include="Sorting\SeriesCountComparer.cs" />
|
||||
<Compile Include="Sorting\SeriesSortNameComparer.cs" />
|
||||
<Compile Include="Sorting\SongCountComparer.cs" />
|
||||
<Compile Include="Sorting\SortNameComparer.cs" />
|
||||
<Compile Include="Persistence\SqliteDisplayPreferencesRepository.cs" />
|
||||
<Compile Include="Persistence\SqliteItemRepository.cs" />
|
||||
<Compile Include="Persistence\SqliteUserDataRepository.cs" />
|
||||
<Compile Include="Persistence\SqliteUserRepository.cs" />
|
||||
<Compile Include="Sorting\TrailerCountComparer.cs" />
|
||||
<Compile Include="Sorting\StudioComparer.cs" />
|
||||
<Compile Include="Sorting\VideoBitRateComparer.cs" />
|
||||
<Compile Include="Themes\AppThemeManager.cs" />
|
||||
<Compile Include="Udp\UdpMessageReceivedEventArgs.cs" />
|
||||
@@ -376,6 +372,12 @@
|
||||
<Link>swagger-ui\swagger-ui.min.js</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="x64\SQLite.Interop.dll" Condition=" '$(ConfigurationName)' != 'Release Mono' ">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="x86\SQLite.Interop.dll" Condition=" '$(ConfigurationName)' != 'Release Mono' ">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<EmbeddedResource Include="Localization\Ratings\be.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -69,6 +69,8 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
|
||||
private IEnumerable<ISessionControllerFactory> _sessionFactories = new List<ISessionControllerFactory>();
|
||||
|
||||
private readonly SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SessionManager" /> class.
|
||||
/// </summary>
|
||||
@@ -146,7 +148,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
var userId = user == null ? (Guid?)null : user.Id;
|
||||
var username = user == null ? null : user.Name;
|
||||
|
||||
var session = GetSessionInfo(clientType, appVersion, deviceId, deviceName, remoteEndPoint, userId, username);
|
||||
var session = await GetSessionInfo(clientType, appVersion, deviceId, deviceName, remoteEndPoint, userId, username).ConfigureAwait(false);
|
||||
|
||||
session.LastActivityDate = activityDate;
|
||||
|
||||
@@ -171,6 +173,46 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
return session;
|
||||
}
|
||||
|
||||
public async Task ReportSessionEnded(Guid sessionId)
|
||||
{
|
||||
await _sessionLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
var session = GetSession(sessionId);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
throw new ArgumentException("Session not found");
|
||||
}
|
||||
|
||||
var key = GetSessionKey(session.Client, session.ApplicationVersion, session.DeviceId);
|
||||
|
||||
SessionInfo removed;
|
||||
|
||||
if (_activeConnections.TryRemove(key, out removed))
|
||||
{
|
||||
var disposable = removed.SessionController as IDisposable;
|
||||
|
||||
if (disposable != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error disposing session controller", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_sessionLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the now playing item id.
|
||||
/// </summary>
|
||||
@@ -207,6 +249,11 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
}
|
||||
}
|
||||
|
||||
private string GetSessionKey(string clientType, string appVersion, string deviceId)
|
||||
{
|
||||
return clientType + deviceId + appVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the connection.
|
||||
/// </summary>
|
||||
@@ -218,36 +265,45 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
/// <param name="userId">The user identifier.</param>
|
||||
/// <param name="username">The username.</param>
|
||||
/// <returns>SessionInfo.</returns>
|
||||
private SessionInfo GetSessionInfo(string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint, Guid? userId, string username)
|
||||
private async Task<SessionInfo> GetSessionInfo(string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint, Guid? userId, string username)
|
||||
{
|
||||
var key = clientType + deviceId + appVersion;
|
||||
var key = GetSessionKey(clientType, appVersion, deviceId);
|
||||
|
||||
var connection = _activeConnections.GetOrAdd(key, keyName => new SessionInfo
|
||||
await _sessionLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
Client = clientType,
|
||||
DeviceId = deviceId,
|
||||
ApplicationVersion = appVersion,
|
||||
Id = Guid.NewGuid()
|
||||
});
|
||||
var connection = _activeConnections.GetOrAdd(key, keyName => new SessionInfo
|
||||
{
|
||||
Client = clientType,
|
||||
DeviceId = deviceId,
|
||||
ApplicationVersion = appVersion,
|
||||
Id = Guid.NewGuid()
|
||||
});
|
||||
|
||||
connection.DeviceName = deviceName;
|
||||
connection.UserId = userId;
|
||||
connection.UserName = username;
|
||||
connection.RemoteEndPoint = remoteEndPoint;
|
||||
connection.DeviceName = deviceName;
|
||||
connection.UserId = userId;
|
||||
connection.UserName = username;
|
||||
connection.RemoteEndPoint = remoteEndPoint;
|
||||
|
||||
if (!userId.HasValue)
|
||||
{
|
||||
connection.AdditionalUsers.Clear();
|
||||
if (!userId.HasValue)
|
||||
{
|
||||
connection.AdditionalUsers.Clear();
|
||||
}
|
||||
|
||||
if (connection.SessionController == null)
|
||||
{
|
||||
connection.SessionController = _sessionFactories
|
||||
.Select(i => i.GetSessionController(connection))
|
||||
.FirstOrDefault(i => i != null);
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
if (connection.SessionController == null)
|
||||
finally
|
||||
{
|
||||
connection.SessionController = _sessionFactories
|
||||
.Select(i => i.GetSessionController(connection))
|
||||
.FirstOrDefault(i => i != null);
|
||||
_sessionLock.Release();
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
private List<User> GetUsers(SessionInfo session)
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Sorting
|
||||
{
|
||||
class AlbumCountComparer : IUserBaseItemComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user.
|
||||
/// </summary>
|
||||
/// <value>The user.</value>
|
||||
public User User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user manager.
|
||||
/// </summary>
|
||||
/// <value>The user manager.</value>
|
||||
public IUserManager UserManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user data repository.
|
||||
/// </summary>
|
||||
/// <value>The user data repository.</value>
|
||||
public IUserDataManager UserDataRepository { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compares the specified x.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
public int Compare(BaseItem x, BaseItem y)
|
||||
{
|
||||
return GetValue(x).CompareTo(GetValue(y));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <returns>DateTime.</returns>
|
||||
private int GetValue(BaseItem x)
|
||||
{
|
||||
var itemByName = x as IItemByName;
|
||||
|
||||
if (itemByName != null)
|
||||
{
|
||||
var counts = itemByName.GetItemByNameCounts(User.Id);
|
||||
|
||||
if (counts != null)
|
||||
{
|
||||
return counts.AlbumCount;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get { return ItemSortBy.AlbumCount; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Sorting
|
||||
{
|
||||
class EpisodeCountComparer : IUserBaseItemComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user.
|
||||
/// </summary>
|
||||
/// <value>The user.</value>
|
||||
public User User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user manager.
|
||||
/// </summary>
|
||||
/// <value>The user manager.</value>
|
||||
public IUserManager UserManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user data repository.
|
||||
/// </summary>
|
||||
/// <value>The user data repository.</value>
|
||||
public IUserDataManager UserDataRepository { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compares the specified x.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
public int Compare(BaseItem x, BaseItem y)
|
||||
{
|
||||
return GetValue(x).CompareTo(GetValue(y));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <returns>DateTime.</returns>
|
||||
private int GetValue(BaseItem x)
|
||||
{
|
||||
var itemByName = x as IItemByName;
|
||||
|
||||
if (itemByName != null)
|
||||
{
|
||||
var counts = itemByName.GetItemByNameCounts(User.Id);
|
||||
|
||||
if (counts != null)
|
||||
{
|
||||
return counts.EpisodeCount;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get { return ItemSortBy.EpisodeCount; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Sorting
|
||||
{
|
||||
public class GameSystemComparer : IBaseItemComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Compares the specified x.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
public int Compare(BaseItem x, BaseItem y)
|
||||
{
|
||||
return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetValue(BaseItem x)
|
||||
{
|
||||
var game = x as Game;
|
||||
|
||||
if (game != null)
|
||||
{
|
||||
return game.GameSystem;
|
||||
}
|
||||
|
||||
var system = x as GameSystem;
|
||||
|
||||
if (system != null)
|
||||
{
|
||||
return system.GameSystemName;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get { return ItemSortBy.GameSystem; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Sorting
|
||||
{
|
||||
public class MovieCountComparer : IUserBaseItemComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user.
|
||||
/// </summary>
|
||||
/// <value>The user.</value>
|
||||
public User User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user manager.
|
||||
/// </summary>
|
||||
/// <value>The user manager.</value>
|
||||
public IUserManager UserManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user data repository.
|
||||
/// </summary>
|
||||
/// <value>The user data repository.</value>
|
||||
public IUserDataManager UserDataRepository { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compares the specified x.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
public int Compare(BaseItem x, BaseItem y)
|
||||
{
|
||||
return GetValue(x).CompareTo(GetValue(y));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <returns>DateTime.</returns>
|
||||
private int GetValue(BaseItem x)
|
||||
{
|
||||
var itemByName = x as IItemByName;
|
||||
|
||||
if (itemByName != null)
|
||||
{
|
||||
var counts = itemByName.GetItemByNameCounts(User.Id);
|
||||
|
||||
if (counts != null)
|
||||
{
|
||||
return counts.MovieCount;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get { return ItemSortBy.MovieCount; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Sorting
|
||||
{
|
||||
class MusicVideoCountComparer : IUserBaseItemComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user.
|
||||
/// </summary>
|
||||
/// <value>The user.</value>
|
||||
public User User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user manager.
|
||||
/// </summary>
|
||||
/// <value>The user manager.</value>
|
||||
public IUserManager UserManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user data repository.
|
||||
/// </summary>
|
||||
/// <value>The user data repository.</value>
|
||||
public IUserDataManager UserDataRepository { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compares the specified x.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
public int Compare(BaseItem x, BaseItem y)
|
||||
{
|
||||
return GetValue(x).CompareTo(GetValue(y));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <returns>DateTime.</returns>
|
||||
private int GetValue(BaseItem x)
|
||||
{
|
||||
var itemByName = x as IItemByName;
|
||||
|
||||
if (itemByName != null)
|
||||
{
|
||||
var counts = itemByName.GetItemByNameCounts(User.Id);
|
||||
|
||||
if (counts != null)
|
||||
{
|
||||
return counts.MusicVideoCount;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get { return ItemSortBy.MusicVideoCount; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Sorting
|
||||
{
|
||||
public class PlayersComparer : IBaseItemComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Compares the specified x.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
public int Compare(BaseItem x, BaseItem y)
|
||||
{
|
||||
return GetValue(x).CompareTo(GetValue(y));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private int GetValue(BaseItem x)
|
||||
{
|
||||
var game = x as Game;
|
||||
|
||||
if (game != null)
|
||||
{
|
||||
return game.PlayersSupported ?? 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get { return ItemSortBy.Players; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Sorting
|
||||
{
|
||||
class SeriesCountComparer : IUserBaseItemComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user.
|
||||
/// </summary>
|
||||
/// <value>The user.</value>
|
||||
public User User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user manager.
|
||||
/// </summary>
|
||||
/// <value>The user manager.</value>
|
||||
public IUserManager UserManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user data repository.
|
||||
/// </summary>
|
||||
/// <value>The user data repository.</value>
|
||||
public IUserDataManager UserDataRepository { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compares the specified x.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
public int Compare(BaseItem x, BaseItem y)
|
||||
{
|
||||
return GetValue(x).CompareTo(GetValue(y));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <returns>DateTime.</returns>
|
||||
private int GetValue(BaseItem x)
|
||||
{
|
||||
var itemByName = x as IItemByName;
|
||||
|
||||
if (itemByName != null)
|
||||
{
|
||||
var counts = itemByName.GetItemByNameCounts(User.Id);
|
||||
|
||||
if (counts != null)
|
||||
{
|
||||
return counts.SeriesCount;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get { return ItemSortBy.SeriesCount; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Sorting
|
||||
{
|
||||
class SongCountComparer : IUserBaseItemComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user.
|
||||
/// </summary>
|
||||
/// <value>The user.</value>
|
||||
public User User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user manager.
|
||||
/// </summary>
|
||||
/// <value>The user manager.</value>
|
||||
public IUserManager UserManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user data repository.
|
||||
/// </summary>
|
||||
/// <value>The user data repository.</value>
|
||||
public IUserDataManager UserDataRepository { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compares the specified x.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
public int Compare(BaseItem x, BaseItem y)
|
||||
{
|
||||
return GetValue(x).CompareTo(GetValue(y));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <returns>DateTime.</returns>
|
||||
private int GetValue(BaseItem x)
|
||||
{
|
||||
var itemByName = x as IItemByName;
|
||||
|
||||
if (itemByName != null)
|
||||
{
|
||||
var counts = itemByName.GetItemByNameCounts(User.Id);
|
||||
|
||||
if (counts != null)
|
||||
{
|
||||
return counts.SongCount;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get { return ItemSortBy.SongCount; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Sorting
|
||||
{
|
||||
public class StudioComparer : IBaseItemComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Compares the specified x.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
public int Compare(BaseItem x, BaseItem y)
|
||||
{
|
||||
return AlphanumComparator.CompareValues(x.Studios.FirstOrDefault() ?? string.Empty, y.Studios.FirstOrDefault() ?? string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get { return ItemSortBy.Studio; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Sorting
|
||||
{
|
||||
public class TrailerCountComparer : IUserBaseItemComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user.
|
||||
/// </summary>
|
||||
/// <value>The user.</value>
|
||||
public User User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user manager.
|
||||
/// </summary>
|
||||
/// <value>The user manager.</value>
|
||||
public IUserManager UserManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user data repository.
|
||||
/// </summary>
|
||||
/// <value>The user data repository.</value>
|
||||
public IUserDataManager UserDataRepository { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compares the specified x.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
public int Compare(BaseItem x, BaseItem y)
|
||||
{
|
||||
return GetValue(x).CompareTo(GetValue(y));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <returns>DateTime.</returns>
|
||||
private int GetValue(BaseItem x)
|
||||
{
|
||||
var itemByName = x as IItemByName;
|
||||
|
||||
if (itemByName != null)
|
||||
{
|
||||
var counts = itemByName.GetItemByNameCounts(User.Id);
|
||||
|
||||
if (counts != null)
|
||||
{
|
||||
return counts.TrailerCount;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get { return ItemSortBy.TrailerCount; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
<packages>
|
||||
<package id="Alchemy" version="2.2.1" targetFramework="net45" />
|
||||
<package id="MediaBrowser.BdInfo" version="1.0.0.10" targetFramework="net45" />
|
||||
<package id="Mono.Nat" version="1.1.13" targetFramework="net45" />
|
||||
<package id="Mono.Nat" version="1.2.3" targetFramework="net45" />
|
||||
<package id="morelinq" version="1.0.16006" targetFramework="net45" />
|
||||
<package id="System.Data.SQLite.x86" version="1.0.90.0" targetFramework="net45" />
|
||||
<package id="System.Data.SQLite.Core" version="1.0.91.3" targetFramework="net45" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user