aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Server.Implementations')
-rw-r--r--MediaBrowser.Server.Implementations/Activity/ActivityManager.cs56
-rw-r--r--MediaBrowser.Server.Implementations/Dto/DtoService.cs1609
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs831
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/Extensions.cs33
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationNotifier.cs80
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs283
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/NameUtils.cs96
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs101
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs210
-rw-r--r--MediaBrowser.Server.Implementations/IO/FileRefresher.cs22
-rw-r--r--MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs9
-rw-r--r--MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs148
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs3067
-rw-r--r--MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs102
-rw-r--r--MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs648
-rw-r--r--MediaBrowser.Server.Implementations/Library/MusicManager.cs157
-rw-r--r--MediaBrowser.Server.Implementations/Library/PathExtensions.cs45
-rw-r--r--MediaBrowser.Server.Implementations/Library/ResolverHelper.cs183
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs68
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs173
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs94
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs297
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs56
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/ItemResolver.cs62
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs77
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs541
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs56
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs103
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/PlaylistResolver.cs42
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs85
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs75
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs62
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs251
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/VideoResolver.cs45
-rw-r--r--MediaBrowser.Server.Implementations/Library/SearchEngine.cs280
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserViewManager.cs292
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs44
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs84
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs45
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs74
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs42
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs75
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs45
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs75
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs172
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs45
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs74
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs55
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs45
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj79
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs360
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs96
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs71
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs160
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs47
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs46
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs99
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs51
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/BudgetComparer.cs39
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs29
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/CriticRatingComparer.cs37
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs33
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs69
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs69
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/GameSystemComparer.cs54
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs58
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/IsFolderComparer.cs39
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/IsPlayedComparer.cs58
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/IsUnplayedComparer.cs58
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/MetascoreComparer.cs41
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/NameComparer.cs33
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/OfficialRatingComparer.cs40
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs63
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/PlayersComparer.cs46
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs59
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs52
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs33
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/RevenueComparer.cs39
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs32
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/SeriesSortNameComparer.cs37
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs33
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/StartDateComparer.cs47
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/StudioComparer.cs30
83 files changed, 39 insertions, 13312 deletions
diff --git a/MediaBrowser.Server.Implementations/Activity/ActivityManager.cs b/MediaBrowser.Server.Implementations/Activity/ActivityManager.cs
deleted file mode 100644
index 2af9395c3..000000000
--- a/MediaBrowser.Server.Implementations/Activity/ActivityManager.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using MediaBrowser.Common.Events;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Activity;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Querying;
-using System;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Activity
-{
- public class ActivityManager : IActivityManager
- {
- public event EventHandler<GenericEventArgs<ActivityLogEntry>> EntryCreated;
-
- private readonly IActivityRepository _repo;
- private readonly ILogger _logger;
- private readonly IUserManager _userManager;
-
- public ActivityManager(ILogger logger, IActivityRepository repo, IUserManager userManager)
- {
- _logger = logger;
- _repo = repo;
- _userManager = userManager;
- }
-
- public async Task Create(ActivityLogEntry entry)
- {
- entry.Id = Guid.NewGuid().ToString("N");
- entry.Date = DateTime.UtcNow;
-
- await _repo.Create(entry).ConfigureAwait(false);
-
- EventHelper.FireEventIfNotNull(EntryCreated, this, new GenericEventArgs<ActivityLogEntry>(entry), _logger);
- }
-
- public QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, int? startIndex, int? limit)
- {
- var result = _repo.GetActivityLogEntries(minDate, startIndex, limit);
-
- foreach (var item in result.Items.Where(i => !string.IsNullOrWhiteSpace(i.UserId)))
- {
- var user = _userManager.GetUserById(item.UserId);
-
- if (user != null)
- {
- var dto = _userManager.GetUserDto(user);
- item.UserPrimaryImageTag = dto.PrimaryImageTag;
- }
- }
-
- return result;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
deleted file mode 100644
index a06656b21..000000000
--- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs
+++ /dev/null
@@ -1,1609 +0,0 @@
-using MediaBrowser.Common;
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Sync;
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Sync;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Extensions;
-
-namespace MediaBrowser.Server.Implementations.Dto
-{
- public class DtoService : IDtoService
- {
- private readonly ILogger _logger;
- private readonly ILibraryManager _libraryManager;
- private readonly IUserDataManager _userDataRepository;
- private readonly IItemRepository _itemRepo;
-
- private readonly IImageProcessor _imageProcessor;
- private readonly IServerConfigurationManager _config;
- private readonly IFileSystem _fileSystem;
- private readonly IProviderManager _providerManager;
-
- private readonly Func<IChannelManager> _channelManagerFactory;
- private readonly ISyncManager _syncManager;
- private readonly IApplicationHost _appHost;
- private readonly Func<IDeviceManager> _deviceManager;
- private readonly Func<IMediaSourceManager> _mediaSourceManager;
- private readonly Func<ILiveTvManager> _livetvManager;
-
- public DtoService(ILogger logger, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepo, IImageProcessor imageProcessor, IServerConfigurationManager config, IFileSystem fileSystem, IProviderManager providerManager, Func<IChannelManager> channelManagerFactory, ISyncManager syncManager, IApplicationHost appHost, Func<IDeviceManager> deviceManager, Func<IMediaSourceManager> mediaSourceManager, Func<ILiveTvManager> livetvManager)
- {
- _logger = logger;
- _libraryManager = libraryManager;
- _userDataRepository = userDataRepository;
- _itemRepo = itemRepo;
- _imageProcessor = imageProcessor;
- _config = config;
- _fileSystem = fileSystem;
- _providerManager = providerManager;
- _channelManagerFactory = channelManagerFactory;
- _syncManager = syncManager;
- _appHost = appHost;
- _deviceManager = deviceManager;
- _mediaSourceManager = mediaSourceManager;
- _livetvManager = livetvManager;
- }
-
- /// <summary>
- /// Converts a BaseItem to a DTOBaseItem
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="fields">The fields.</param>
- /// <param name="user">The user.</param>
- /// <param name="owner">The owner.</param>
- /// <returns>Task{DtoBaseItem}.</returns>
- /// <exception cref="System.ArgumentNullException">item</exception>
- public BaseItemDto GetBaseItemDto(BaseItem item, List<ItemFields> fields, User user = null, BaseItem owner = null)
- {
- var options = new DtoOptions
- {
- Fields = fields
- };
-
- return GetBaseItemDto(item, options, user, owner);
- }
-
- public async Task<List<BaseItemDto>> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null)
- {
- if (items == null)
- {
- throw new ArgumentNullException("items");
- }
-
- if (options == null)
- {
- throw new ArgumentNullException("options");
- }
-
- var syncDictionary = GetSyncedItemProgress(options);
-
- var list = new List<BaseItemDto>();
- var programTuples = new List<Tuple<BaseItem, BaseItemDto>>();
- var channelTuples = new List<Tuple<BaseItemDto, LiveTvChannel>>();
-
- foreach (var item in items)
- {
- var dto = await GetBaseItemDtoInternal(item, options, user, owner).ConfigureAwait(false);
-
- var tvChannel = item as LiveTvChannel;
- if (tvChannel != null)
- {
- channelTuples.Add(new Tuple<BaseItemDto, LiveTvChannel>(dto, tvChannel));
- }
- else if (item is LiveTvProgram)
- {
- programTuples.Add(new Tuple<BaseItem, BaseItemDto>(item, dto));
- }
-
- var byName = item as IItemByName;
-
- if (byName != null)
- {
- if (options.Fields.Contains(ItemFields.ItemCounts))
- {
- var libraryItems = byName.GetTaggedItems(new InternalItemsQuery(user)
- {
- Recursive = true
- });
-
- SetItemByNameInfo(item, dto, libraryItems.ToList(), user);
- }
- }
-
- FillSyncInfo(dto, item, options, user, syncDictionary);
-
- list.Add(dto);
- }
-
- if (programTuples.Count > 0)
- {
- await _livetvManager().AddInfoToProgramDto(programTuples, options.Fields, user).ConfigureAwait(false);
- }
-
- if (channelTuples.Count > 0)
- {
- _livetvManager().AddChannelInfo(channelTuples, options, user);
- }
-
- return list;
- }
-
- public BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null)
- {
- var syncDictionary = GetSyncedItemProgress(options);
-
- var dto = GetBaseItemDtoInternal(item, options, user, owner).Result;
- var tvChannel = item as LiveTvChannel;
- if (tvChannel != null)
- {
- var list = new List<Tuple<BaseItemDto, LiveTvChannel>> { new Tuple<BaseItemDto, LiveTvChannel>(dto, tvChannel) };
- _livetvManager().AddChannelInfo(list, options, user);
- }
- else if (item is LiveTvProgram)
- {
- var list = new List<Tuple<BaseItem, BaseItemDto>> { new Tuple<BaseItem, BaseItemDto>(item, dto) };
- var task = _livetvManager().AddInfoToProgramDto(list, options.Fields, user);
- Task.WaitAll(task);
- }
-
- var byName = item as IItemByName;
-
- if (byName != null)
- {
- if (options.Fields.Contains(ItemFields.ItemCounts))
- {
- SetItemByNameInfo(item, dto, GetTaggedItems(byName, user), user);
- }
-
- FillSyncInfo(dto, item, options, user, syncDictionary);
- return dto;
- }
-
- FillSyncInfo(dto, item, options, user, syncDictionary);
-
- return dto;
- }
-
- private List<BaseItem> GetTaggedItems(IItemByName byName, User user)
- {
- var items = byName.GetTaggedItems(new InternalItemsQuery(user)
- {
- Recursive = true
-
- }).ToList();
-
- return items;
- }
-
- public Dictionary<string, SyncedItemProgress> GetSyncedItemProgress(DtoOptions options)
- {
- if (!options.Fields.Contains(ItemFields.BasicSyncInfo) &&
- !options.Fields.Contains(ItemFields.SyncInfo))
- {
- return new Dictionary<string, SyncedItemProgress>();
- }
-
- var deviceId = options.DeviceId;
- if (string.IsNullOrWhiteSpace(deviceId))
- {
- return new Dictionary<string, SyncedItemProgress>();
- }
-
- var caps = _deviceManager().GetCapabilities(deviceId);
- if (caps == null || !caps.SupportsSync)
- {
- return new Dictionary<string, SyncedItemProgress>();
- }
-
- return _syncManager.GetSyncedItemProgresses(new SyncJobItemQuery
- {
- TargetId = deviceId,
- Statuses = new[]
- {
- SyncJobItemStatus.Converting,
- SyncJobItemStatus.Queued,
- SyncJobItemStatus.Transferring,
- SyncJobItemStatus.ReadyToTransfer,
- SyncJobItemStatus.Synced
- }
- });
- }
-
- public void FillSyncInfo(IEnumerable<Tuple<BaseItem, BaseItemDto>> tuples, DtoOptions options, User user)
- {
- if (options.Fields.Contains(ItemFields.BasicSyncInfo) ||
- options.Fields.Contains(ItemFields.SyncInfo))
- {
- var syncProgress = GetSyncedItemProgress(options);
-
- foreach (var tuple in tuples)
- {
- var item = tuple.Item1;
-
- FillSyncInfo(tuple.Item2, item, options, user, syncProgress);
- }
- }
- }
-
- private void FillSyncInfo(IHasSyncInfo dto, BaseItem item, DtoOptions options, User user, Dictionary<string, SyncedItemProgress> syncProgress)
- {
- var hasFullSyncInfo = options.Fields.Contains(ItemFields.SyncInfo);
-
- if (!options.Fields.Contains(ItemFields.BasicSyncInfo) &&
- !hasFullSyncInfo)
- {
- return;
- }
-
- if (dto.SupportsSync ?? false)
- {
- SyncedItemProgress syncStatus;
- if (syncProgress.TryGetValue(dto.Id, out syncStatus))
- {
- if (syncStatus.Status == SyncJobItemStatus.Synced)
- {
- dto.SyncPercent = 100;
- }
- else
- {
- dto.SyncPercent = syncStatus.Progress;
- }
-
- if (hasFullSyncInfo)
- {
- dto.HasSyncJob = true;
- dto.SyncStatus = syncStatus.Status;
- }
- }
- }
- }
-
- private async Task<BaseItemDto> GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null)
- {
- var fields = options.Fields;
-
- if (item == null)
- {
- throw new ArgumentNullException("item");
- }
-
- if (fields == null)
- {
- throw new ArgumentNullException("fields");
- }
-
- var dto = new BaseItemDto
- {
- ServerId = _appHost.SystemId
- };
-
- if (item.SourceType == SourceType.Channel)
- {
- dto.SourceType = item.SourceType.ToString();
- }
-
- if (fields.Contains(ItemFields.People))
- {
- AttachPeople(dto, item);
- }
-
- if (fields.Contains(ItemFields.PrimaryImageAspectRatio))
- {
- try
- {
- AttachPrimaryImageAspectRatio(dto, item);
- }
- catch (Exception ex)
- {
- // Have to use a catch-all unfortunately because some .net image methods throw plain Exceptions
- _logger.ErrorException("Error generating PrimaryImageAspectRatio for {0}", ex, item.Name);
- }
- }
-
- if (fields.Contains(ItemFields.DisplayPreferencesId))
- {
- dto.DisplayPreferencesId = item.DisplayPreferencesId.ToString("N");
- }
-
- if (user != null)
- {
- await AttachUserSpecificInfo(dto, item, user, options).ConfigureAwait(false);
- }
-
- var hasMediaSources = item as IHasMediaSources;
- if (hasMediaSources != null)
- {
- if (fields.Contains(ItemFields.MediaSources))
- {
- if (user == null)
- {
- dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true).ToList();
- }
- else
- {
- dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true, user).ToList();
- }
- }
- }
-
- if (fields.Contains(ItemFields.Studios))
- {
- AttachStudios(dto, item);
- }
-
- AttachBasicFields(dto, item, owner, options);
-
- var collectionFolder = item as ICollectionFolder;
- if (collectionFolder != null)
- {
- dto.OriginalCollectionType = collectionFolder.CollectionType;
-
- dto.CollectionType = user == null ?
- collectionFolder.CollectionType :
- collectionFolder.GetViewType(user);
- }
-
- if (fields.Contains(ItemFields.CanDelete))
- {
- dto.CanDelete = user == null
- ? item.CanDelete()
- : item.CanDelete(user);
- }
-
- if (fields.Contains(ItemFields.CanDownload))
- {
- dto.CanDownload = user == null
- ? item.CanDownload()
- : item.CanDownload(user);
- }
-
- if (fields.Contains(ItemFields.Etag))
- {
- dto.Etag = item.GetEtag(user);
- }
-
- if (item is ILiveTvRecording)
- {
- _livetvManager().AddInfoToRecordingDto(item, dto, user);
- }
-
- return dto;
- }
-
- public BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List<BaseItem> taggedItems, Dictionary<string, SyncedItemProgress> syncProgress, User user = null)
- {
- var dto = GetBaseItemDtoInternal(item, options, user).Result;
-
- if (taggedItems != null && options.Fields.Contains(ItemFields.ItemCounts))
- {
- SetItemByNameInfo(item, dto, taggedItems, user);
- }
-
- FillSyncInfo(dto, item, options, user, syncProgress);
-
- return dto;
- }
-
- private void SetItemByNameInfo(BaseItem item, BaseItemDto dto, List<BaseItem> taggedItems, User user = null)
- {
- if (item is MusicArtist)
- {
- 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 MusicGenre)
- {
- dto.ArtistCount = taggedItems.Count(i => i is MusicArtist);
- 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.ArtistCount = taggedItems.Count(i => i is MusicArtist);
- 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.TrailerCount = taggedItems.Count(i => i is Trailer);
- dto.MusicVideoCount = taggedItems.Count(i => i is MusicVideo);
- dto.SeriesCount = taggedItems.Count(i => i is Series);
- dto.ProgramCount = taggedItems.Count(i => i is LiveTvProgram);
- dto.SongCount = taggedItems.Count(i => i is Audio);
- }
-
- dto.ChildCount = taggedItems.Count;
- }
-
- /// <summary>
- /// Attaches the user specific info.
- /// </summary>
- private async Task AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, DtoOptions dtoOptions)
- {
- var fields = dtoOptions.Fields;
-
- if (item.IsFolder)
- {
- var folder = (Folder)item;
-
- if (dtoOptions.EnableUserData)
- {
- dto.UserData = await _userDataRepository.GetUserDataDto(item, dto, user).ConfigureAwait(false);
- }
-
- if (!dto.ChildCount.HasValue && item.SourceType == SourceType.Library)
- {
- dto.ChildCount = GetChildCount(folder, user);
- }
-
- if (fields.Contains(ItemFields.CumulativeRunTimeTicks))
- {
- dto.CumulativeRunTimeTicks = item.RunTimeTicks;
- }
-
- if (fields.Contains(ItemFields.DateLastMediaAdded))
- {
- dto.DateLastMediaAdded = folder.DateLastMediaAdded;
- }
- }
-
- else
- {
- if (dtoOptions.EnableUserData)
- {
- dto.UserData = _userDataRepository.GetUserDataDto(item, user).Result;
- }
- }
-
- dto.PlayAccess = item.GetPlayAccess(user);
-
- if (fields.Contains(ItemFields.BasicSyncInfo) || fields.Contains(ItemFields.SyncInfo))
- {
- var userCanSync = user != null && user.Policy.EnableSync;
- if (userCanSync && _syncManager.SupportsSync(item))
- {
- dto.SupportsSync = true;
- }
- }
-
- if (fields.Contains(ItemFields.SeasonUserData))
- {
- var episode = item as Episode;
-
- if (episode != null)
- {
- var season = episode.Season;
-
- if (season != null)
- {
- dto.SeasonUserData = await _userDataRepository.GetUserDataDto(season, user).ConfigureAwait(false);
- }
- }
- }
-
- var userView = item as UserView;
- if (userView != null)
- {
- dto.HasDynamicCategories = userView.ContainsDynamicCategories(user);
- }
-
- var collectionFolder = item as ICollectionFolder;
- if (collectionFolder != null)
- {
- dto.HasDynamicCategories = false;
- }
- }
-
- private int GetChildCount(Folder folder, User user)
- {
- // Right now this is too slow to calculate for top level folders on a per-user basis
- // Just return something so that apps that are expecting a value won't think the folders are empty
- if (folder is ICollectionFolder || folder is UserView)
- {
- return new Random().Next(1, 10);
- }
-
- return folder.GetChildCount(user);
- }
-
- /// <summary>
- /// Gets client-side Id of a server-side BaseItem
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="System.ArgumentNullException">item</exception>
- public string GetDtoId(BaseItem item)
- {
- if (item == null)
- {
- throw new ArgumentNullException("item");
- }
-
- return item.Id.ToString("N");
- }
-
- /// <summary>
- /// Converts a UserItemData to a DTOUserItemData
- /// </summary>
- /// <param name="data">The data.</param>
- /// <returns>DtoUserItemData.</returns>
- /// <exception cref="System.ArgumentNullException"></exception>
- public UserItemDataDto GetUserItemDataDto(UserItemData data)
- {
- if (data == null)
- {
- throw new ArgumentNullException("data");
- }
-
- return new UserItemDataDto
- {
- IsFavorite = data.IsFavorite,
- Likes = data.Likes,
- PlaybackPositionTicks = data.PlaybackPositionTicks,
- PlayCount = data.PlayCount,
- Rating = data.Rating,
- Played = data.Played,
- LastPlayedDate = data.LastPlayedDate,
- Key = data.Key
- };
- }
- private void SetBookProperties(BaseItemDto dto, Book item)
- {
- dto.SeriesName = item.SeriesName;
- }
- private void SetPhotoProperties(BaseItemDto dto, Photo item)
- {
- dto.Width = item.Width;
- dto.Height = item.Height;
- dto.CameraMake = item.CameraMake;
- dto.CameraModel = item.CameraModel;
- dto.Software = item.Software;
- dto.ExposureTime = item.ExposureTime;
- dto.FocalLength = item.FocalLength;
- dto.ImageOrientation = item.Orientation;
- dto.Aperture = item.Aperture;
- dto.ShutterSpeed = item.ShutterSpeed;
-
- dto.Latitude = item.Latitude;
- dto.Longitude = item.Longitude;
- dto.Altitude = item.Altitude;
- dto.IsoSpeedRating = item.IsoSpeedRating;
-
- var album = item.AlbumEntity;
-
- if (album != null)
- {
- dto.Album = album.Name;
- dto.AlbumId = album.Id.ToString("N");
- }
- }
-
- private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item)
- {
- if (!string.IsNullOrEmpty(item.Album))
- {
- var parentAlbum = _libraryManager.GetItemList(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(MusicAlbum).Name },
- Name = item.Album
-
- }).FirstOrDefault();
-
- if (parentAlbum != null)
- {
- dto.AlbumId = GetDtoId(parentAlbum);
- }
- }
-
- dto.Album = item.Album;
- }
-
- private void SetGameProperties(BaseItemDto dto, Game item)
- {
- dto.Players = item.PlayersSupported;
- dto.GameSystem = item.GameSystem;
- dto.MultiPartGameFiles = item.MultiPartGameFiles;
- }
-
- private void SetGameSystemProperties(BaseItemDto dto, GameSystem item)
- {
- dto.GameSystem = item.GameSystemName;
- }
-
- private List<string> GetImageTags(BaseItem item, List<ItemImageInfo> images)
- {
- return images
- .Select(p => GetImageCacheTag(item, p))
- .Where(i => i != null)
- .ToList();
- }
-
- private string GetImageCacheTag(BaseItem item, ImageType type)
- {
- try
- {
- return _imageProcessor.GetImageCacheTag(item, type);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting {0} image info", ex, type);
- return null;
- }
- }
-
- private string GetImageCacheTag(BaseItem item, ItemImageInfo image)
- {
- try
- {
- return _imageProcessor.GetImageCacheTag(item, image);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting {0} image info for {1}", ex, image.Type, image.Path);
- return null;
- }
- }
-
- /// <summary>
- /// Attaches People DTO's to a DTOBaseItem
- /// </summary>
- /// <param name="dto">The dto.</param>
- /// <param name="item">The item.</param>
- /// <returns>Task.</returns>
- private void AttachPeople(BaseItemDto dto, BaseItem item)
- {
- // Ordering by person type to ensure actors and artists are at the front.
- // This is taking advantage of the fact that they both begin with A
- // This should be improved in the future
- var people = _libraryManager.GetPeople(item).OrderBy(i => i.SortOrder ?? int.MaxValue)
- .ThenBy(i =>
- {
- if (i.IsType(PersonType.Actor))
- {
- return 0;
- }
- if (i.IsType(PersonType.GuestStar))
- {
- return 1;
- }
- if (i.IsType(PersonType.Director))
- {
- return 2;
- }
- if (i.IsType(PersonType.Writer))
- {
- return 3;
- }
- if (i.IsType(PersonType.Producer))
- {
- return 4;
- }
- if (i.IsType(PersonType.Composer))
- {
- return 4;
- }
-
- return 10;
- })
- .ToList();
-
- var list = new List<BaseItemPerson>();
-
- var dictionary = people.Select(p => p.Name)
- .Distinct(StringComparer.OrdinalIgnoreCase).Select(c =>
- {
- try
- {
- return _libraryManager.GetPerson(c);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting person {0}", ex, c);
- return null;
- }
-
- }).Where(i => i != null)
- .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
- .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
-
- for (var i = 0; i < people.Count; i++)
- {
- var person = people[i];
-
- var baseItemPerson = new BaseItemPerson
- {
- Name = person.Name,
- Role = person.Role,
- Type = person.Type
- };
-
- Person entity;
-
- if (dictionary.TryGetValue(person.Name, out entity))
- {
- baseItemPerson.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary);
- baseItemPerson.Id = entity.Id.ToString("N");
- list.Add(baseItemPerson);
- }
- }
-
- dto.People = list.ToArray();
- }
-
- /// <summary>
- /// Attaches the studios.
- /// </summary>
- /// <param name="dto">The dto.</param>
- /// <param name="item">The item.</param>
- /// <returns>Task.</returns>
- private void AttachStudios(BaseItemDto dto, BaseItem item)
- {
- var studios = item.Studios.ToList();
-
- dto.Studios = new StudioDto[studios.Count];
-
- var dictionary = studios.Distinct(StringComparer.OrdinalIgnoreCase).Select(name =>
- {
- try
- {
- return _libraryManager.GetStudio(name);
- }
- catch (IOException ex)
- {
- _logger.ErrorException("Error getting studio {0}", ex, name);
- return null;
- }
- })
- .Where(i => i != null)
- .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
- .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
-
- for (var i = 0; i < studios.Count; i++)
- {
- var studio = studios[i];
-
- var studioDto = new StudioDto
- {
- Name = studio
- };
-
- Studio entity;
-
- if (dictionary.TryGetValue(studio, out entity))
- {
- studioDto.Id = entity.Id.ToString("N");
- studioDto.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary);
- }
-
- dto.Studios[i] = studioDto;
- }
- }
-
- /// <summary>
- /// Gets the chapter info dto.
- /// </summary>
- /// <param name="chapterInfo">The chapter info.</param>
- /// <param name="item">The item.</param>
- /// <returns>ChapterInfoDto.</returns>
- private ChapterInfoDto GetChapterInfoDto(ChapterInfo chapterInfo, BaseItem item)
- {
- var dto = new ChapterInfoDto
- {
- Name = chapterInfo.Name,
- StartPositionTicks = chapterInfo.StartPositionTicks
- };
-
- if (!string.IsNullOrEmpty(chapterInfo.ImagePath))
- {
- dto.ImageTag = GetImageCacheTag(item, new ItemImageInfo
- {
- Path = chapterInfo.ImagePath,
- Type = ImageType.Chapter,
- DateModified = chapterInfo.ImageDateModified
- });
- }
-
- return dto;
- }
-
- public List<ChapterInfoDto> GetChapterInfoDtos(BaseItem item)
- {
- return _itemRepo.GetChapters(item.Id)
- .Select(c => GetChapterInfoDto(c, item))
- .ToList();
- }
-
- /// <summary>
- /// Sets simple property values on a DTOBaseItem
- /// </summary>
- /// <param name="dto">The dto.</param>
- /// <param name="item">The item.</param>
- /// <param name="owner">The owner.</param>
- /// <param name="options">The options.</param>
- private void AttachBasicFields(BaseItemDto dto, BaseItem item, BaseItem owner, DtoOptions options)
- {
- var fields = options.Fields;
-
- if (fields.Contains(ItemFields.DateCreated))
- {
- dto.DateCreated = item.DateCreated;
- }
-
- if (fields.Contains(ItemFields.DisplayMediaType))
- {
- dto.DisplayMediaType = item.DisplayMediaType;
- }
-
- if (fields.Contains(ItemFields.Settings))
- {
- dto.LockedFields = item.LockedFields;
- dto.LockData = item.IsLocked;
- dto.ForcedSortName = item.ForcedSortName;
- }
- dto.Container = item.Container;
-
- var hasBudget = item as IHasBudget;
- if (hasBudget != null)
- {
- if (fields.Contains(ItemFields.Budget))
- {
- dto.Budget = hasBudget.Budget;
- }
-
- if (fields.Contains(ItemFields.Revenue))
- {
- dto.Revenue = hasBudget.Revenue;
- }
- }
-
- dto.EndDate = item.EndDate;
-
- if (fields.Contains(ItemFields.HomePageUrl))
- {
- dto.HomePageUrl = item.HomePageUrl;
- }
-
- if (fields.Contains(ItemFields.ExternalUrls))
- {
- dto.ExternalUrls = _providerManager.GetExternalUrls(item).ToArray();
- }
-
- if (fields.Contains(ItemFields.Tags))
- {
- dto.Tags = item.Tags;
- }
-
- if (fields.Contains(ItemFields.Keywords))
- {
- dto.Keywords = item.Keywords;
- }
-
- var hasAspectRatio = item as IHasAspectRatio;
- if (hasAspectRatio != null)
- {
- dto.AspectRatio = hasAspectRatio.AspectRatio;
- }
-
- if (fields.Contains(ItemFields.Metascore))
- {
- var hasMetascore = item as IHasMetascore;
- if (hasMetascore != null)
- {
- dto.Metascore = hasMetascore.Metascore;
- }
- }
-
- if (fields.Contains(ItemFields.AwardSummary))
- {
- var hasAwards = item as IHasAwards;
- if (hasAwards != null)
- {
- dto.AwardSummary = hasAwards.AwardSummary;
- }
- }
-
- var backdropLimit = options.GetImageLimit(ImageType.Backdrop);
- if (backdropLimit > 0)
- {
- dto.BackdropImageTags = GetImageTags(item, item.GetImages(ImageType.Backdrop).Take(backdropLimit).ToList());
- }
-
- if (fields.Contains(ItemFields.ScreenshotImageTags))
- {
- var screenshotLimit = options.GetImageLimit(ImageType.Screenshot);
- if (screenshotLimit > 0)
- {
- dto.ScreenshotImageTags = GetImageTags(item, item.GetImages(ImageType.Screenshot).Take(screenshotLimit).ToList());
- }
- }
-
- if (fields.Contains(ItemFields.Genres))
- {
- dto.Genres = item.Genres;
- }
-
- if (options.EnableImages)
- {
- dto.ImageTags = new Dictionary<ImageType, string>();
-
- // Prevent implicitly captured closure
- var currentItem = item;
- foreach (var image in currentItem.ImageInfos.Where(i => !currentItem.AllowsMultipleImages(i.Type))
- .ToList())
- {
- if (options.GetImageLimit(image.Type) > 0)
- {
- var tag = GetImageCacheTag(item, image);
-
- if (tag != null)
- {
- dto.ImageTags[image.Type] = tag;
- }
- }
- }
- }
-
- dto.Id = GetDtoId(item);
- dto.IndexNumber = item.IndexNumber;
- dto.ParentIndexNumber = item.ParentIndexNumber;
-
- if (item.IsFolder)
- {
- dto.IsFolder = true;
- }
- else if (item is IHasMediaSources)
- {
- dto.IsFolder = false;
- }
-
- dto.MediaType = item.MediaType;
- dto.LocationType = item.LocationType;
- if (item.IsHD.HasValue && item.IsHD.Value)
- {
- dto.IsHD = item.IsHD;
- }
- dto.Audio = item.Audio;
-
- if (fields.Contains(ItemFields.Settings))
- {
- dto.PreferredMetadataCountryCode = item.PreferredMetadataCountryCode;
- dto.PreferredMetadataLanguage = item.PreferredMetadataLanguage;
- }
-
- dto.CriticRating = item.CriticRating;
-
- if (fields.Contains(ItemFields.CriticRatingSummary))
- {
- dto.CriticRatingSummary = item.CriticRatingSummary;
- }
-
- var hasTrailers = item as IHasTrailers;
- if (hasTrailers != null)
- {
- dto.LocalTrailerCount = hasTrailers.GetTrailerIds().Count;
- }
-
- var hasDisplayOrder = item as IHasDisplayOrder;
- if (hasDisplayOrder != null)
- {
- dto.DisplayOrder = hasDisplayOrder.DisplayOrder;
- }
-
- var userView = item as UserView;
- if (userView != null)
- {
- dto.CollectionType = userView.ViewType;
- }
-
- if (fields.Contains(ItemFields.RemoteTrailers))
- {
- dto.RemoteTrailers = hasTrailers != null ?
- hasTrailers.RemoteTrailers :
- new List<MediaUrl>();
- }
-
- dto.Name = item.Name;
- dto.OfficialRating = item.OfficialRating;
-
- if (fields.Contains(ItemFields.Overview))
- {
- dto.Overview = item.Overview;
- }
-
- if (fields.Contains(ItemFields.OriginalTitle))
- {
- dto.OriginalTitle = item.OriginalTitle;
- }
-
- if (fields.Contains(ItemFields.ShortOverview))
- {
- dto.ShortOverview = item.ShortOverview;
- }
-
- if (fields.Contains(ItemFields.ParentId))
- {
- var displayParentId = item.DisplayParentId;
- if (displayParentId.HasValue)
- {
- dto.ParentId = displayParentId.Value.ToString("N");
- }
- }
-
- AddInheritedImages(dto, item, options, owner);
-
- if (fields.Contains(ItemFields.Path))
- {
- dto.Path = GetMappedPath(item);
- }
-
- dto.PremiereDate = item.PremiereDate;
- dto.ProductionYear = item.ProductionYear;
-
- if (fields.Contains(ItemFields.ProviderIds))
- {
- dto.ProviderIds = item.ProviderIds;
- }
-
- dto.RunTimeTicks = item.RunTimeTicks;
-
- if (fields.Contains(ItemFields.SortName))
- {
- dto.SortName = item.SortName;
- }
-
- if (fields.Contains(ItemFields.CustomRating))
- {
- dto.CustomRating = item.CustomRating;
- }
-
- if (fields.Contains(ItemFields.Taglines))
- {
- if (!string.IsNullOrWhiteSpace(item.Tagline))
- {
- dto.Taglines = new List<string> { item.Tagline };
- }
-
- if (dto.Taglines == null)
- {
- dto.Taglines = new List<string>();
- }
- }
-
- dto.Type = item.GetClientTypeName();
- dto.CommunityRating = item.CommunityRating;
-
- if (fields.Contains(ItemFields.VoteCount))
- {
- dto.VoteCount = item.VoteCount;
- }
-
- //if (item.IsFolder)
- //{
- // var folder = (Folder)item;
-
- // if (fields.Contains(ItemFields.IndexOptions))
- // {
- // dto.IndexOptions = folder.IndexByOptionStrings.ToArray();
- // }
- //}
-
- var supportsPlaceHolders = item as ISupportsPlaceHolders;
- if (supportsPlaceHolders != null)
- {
- dto.IsPlaceHolder = supportsPlaceHolders.IsPlaceHolder;
- }
-
- // Add audio info
- var audio = item as Audio;
- if (audio != null)
- {
- dto.Album = audio.Album;
- dto.ExtraType = audio.ExtraType;
-
- var albumParent = audio.AlbumEntity;
-
- if (albumParent != null)
- {
- dto.AlbumId = GetDtoId(albumParent);
-
- dto.AlbumPrimaryImageTag = GetImageCacheTag(albumParent, ImageType.Primary);
- }
-
- //if (fields.Contains(ItemFields.MediaSourceCount))
- //{
- // Songs always have one
- //}
- }
-
- var hasArtist = item as IHasArtist;
- if (hasArtist != null)
- {
- dto.Artists = hasArtist.Artists;
-
- var artistItems = _libraryManager.GetArtists(new InternalItemsQuery
- {
- EnableTotalRecordCount = false,
- ItemIds = new[] { item.Id.ToString("N") }
- });
-
- dto.ArtistItems = artistItems.Items
- .Select(i =>
- {
- var artist = i.Item1;
- return new NameIdPair
- {
- Name = artist.Name,
- Id = artist.Id.ToString("N")
- };
- })
- .ToList();
-
- // Include artists that are not in the database yet, e.g., just added via metadata editor
- var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
- dto.ArtistItems.AddRange(hasArtist.Artists
- .Except(foundArtists, new DistinctNameComparer())
- .Select(i =>
- {
- // This should not be necessary but we're seeing some cases of it
- if (string.IsNullOrWhiteSpace(i))
- {
- return null;
- }
-
- var artist = _libraryManager.GetArtist(i);
- if (artist != null)
- {
- return new NameIdPair
- {
- Name = artist.Name,
- Id = artist.Id.ToString("N")
- };
- }
-
- return null;
-
- }).Where(i => i != null));
- }
-
- var hasAlbumArtist = item as IHasAlbumArtist;
- if (hasAlbumArtist != null)
- {
- dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault();
-
- var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery
- {
- EnableTotalRecordCount = false,
- ItemIds = new[] { item.Id.ToString("N") }
- });
-
- dto.AlbumArtists = artistItems.Items
- .Select(i =>
- {
- var artist = i.Item1;
- return new NameIdPair
- {
- Name = artist.Name,
- Id = artist.Id.ToString("N")
- };
- })
- .ToList();
- }
-
- // Add video info
- var video = item as Video;
- if (video != null)
- {
- dto.VideoType = video.VideoType;
- dto.Video3DFormat = video.Video3DFormat;
- dto.IsoType = video.IsoType;
-
- if (video.HasSubtitles)
- {
- dto.HasSubtitles = video.HasSubtitles;
- }
-
- if (video.AdditionalParts.Count != 0)
- {
- dto.PartCount = video.AdditionalParts.Count + 1;
- }
-
- if (fields.Contains(ItemFields.MediaSourceCount))
- {
- var mediaSourceCount = video.MediaSourceCount;
- if (mediaSourceCount != 1)
- {
- dto.MediaSourceCount = mediaSourceCount;
- }
- }
-
- if (fields.Contains(ItemFields.Chapters))
- {
- dto.Chapters = GetChapterInfoDtos(item);
- }
-
- dto.ExtraType = video.ExtraType;
- }
-
- if (fields.Contains(ItemFields.MediaStreams))
- {
- // Add VideoInfo
- var iHasMediaSources = item as IHasMediaSources;
-
- if (iHasMediaSources != null)
- {
- List<MediaStream> mediaStreams;
-
- if (dto.MediaSources != null && dto.MediaSources.Count > 0)
- {
- mediaStreams = dto.MediaSources.Where(i => new Guid(i.Id) == item.Id)
- .SelectMany(i => i.MediaStreams)
- .ToList();
- }
- else
- {
- mediaStreams = _mediaSourceManager().GetStaticMediaSources(iHasMediaSources, true).First().MediaStreams;
- }
-
- dto.MediaStreams = mediaStreams;
- }
- }
-
- var hasSpecialFeatures = item as IHasSpecialFeatures;
- if (hasSpecialFeatures != null)
- {
- var specialFeatureCount = hasSpecialFeatures.SpecialFeatureIds.Count;
-
- if (specialFeatureCount > 0)
- {
- dto.SpecialFeatureCount = specialFeatureCount;
- }
- }
-
- // Add EpisodeInfo
- var episode = item as Episode;
- if (episode != null)
- {
- dto.IndexNumberEnd = episode.IndexNumberEnd;
- dto.SeriesName = episode.SeriesName;
-
- if (fields.Contains(ItemFields.AlternateEpisodeNumbers))
- {
- dto.DvdSeasonNumber = episode.DvdSeasonNumber;
- dto.DvdEpisodeNumber = episode.DvdEpisodeNumber;
- dto.AbsoluteEpisodeNumber = episode.AbsoluteEpisodeNumber;
- }
-
- if (fields.Contains(ItemFields.SpecialEpisodeNumbers))
- {
- dto.AirsAfterSeasonNumber = episode.AirsAfterSeasonNumber;
- dto.AirsBeforeEpisodeNumber = episode.AirsBeforeEpisodeNumber;
- dto.AirsBeforeSeasonNumber = episode.AirsBeforeSeasonNumber;
- }
-
- var seasonId = episode.SeasonId;
- if (seasonId.HasValue)
- {
- dto.SeasonId = seasonId.Value.ToString("N");
- }
-
- dto.SeasonName = episode.SeasonName;
-
- var seriesId = episode.SeriesId;
- if (seriesId.HasValue)
- {
- dto.SeriesId = seriesId.Value.ToString("N");
- }
-
- Series episodeSeries = null;
-
- if (fields.Contains(ItemFields.SeriesGenres))
- {
- episodeSeries = episodeSeries ?? episode.Series;
- if (episodeSeries != null)
- {
- dto.SeriesGenres = episodeSeries.Genres.ToList();
- }
- }
-
- //if (fields.Contains(ItemFields.SeriesPrimaryImage))
- {
- episodeSeries = episodeSeries ?? episode.Series;
- if (episodeSeries != null)
- {
- dto.SeriesPrimaryImageTag = GetImageCacheTag(episodeSeries, ImageType.Primary);
- }
- }
-
- if (fields.Contains(ItemFields.SeriesStudio))
- {
- episodeSeries = episodeSeries ?? episode.Series;
- if (episodeSeries != null)
- {
- dto.SeriesStudio = episodeSeries.Studios.FirstOrDefault();
- }
- }
- }
-
- // Add SeriesInfo
- var series = item as Series;
- if (series != null)
- {
- dto.AirDays = series.AirDays;
- dto.AirTime = series.AirTime;
- dto.SeriesStatus = series.Status;
-
- dto.AnimeSeriesIndex = series.AnimeSeriesIndex;
- }
-
- // Add SeasonInfo
- var season = item as Season;
- if (season != null)
- {
- dto.SeriesName = season.SeriesName;
-
- var seriesId = season.SeriesId;
- if (seriesId.HasValue)
- {
- dto.SeriesId = seriesId.Value.ToString("N");
- }
-
- series = null;
-
- if (fields.Contains(ItemFields.SeriesStudio))
- {
- series = series ?? season.Series;
- if (series != null)
- {
- dto.SeriesStudio = series.Studios.FirstOrDefault();
- }
- }
-
- if (fields.Contains(ItemFields.SeriesPrimaryImage))
- {
- series = series ?? season.Series;
- if (series != null)
- {
- dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary);
- }
- }
- }
-
- var game = item as Game;
-
- if (game != null)
- {
- SetGameProperties(dto, game);
- }
-
- var gameSystem = item as GameSystem;
-
- if (gameSystem != null)
- {
- SetGameSystemProperties(dto, gameSystem);
- }
-
- var musicVideo = item as MusicVideo;
- if (musicVideo != null)
- {
- SetMusicVideoProperties(dto, musicVideo);
- }
-
- var book = item as Book;
- if (book != null)
- {
- SetBookProperties(dto, book);
- }
-
- if (item.ProductionLocations.Count > 0 || item is Movie)
- {
- dto.ProductionLocations = item.ProductionLocations.ToArray();
- }
-
- var photo = item as Photo;
- if (photo != null)
- {
- SetPhotoProperties(dto, photo);
- }
-
- dto.ChannelId = item.ChannelId;
-
- if (item.SourceType == SourceType.Channel && !string.IsNullOrWhiteSpace(item.ChannelId))
- {
- var channel = _libraryManager.GetItemById(item.ChannelId);
- if (channel != null)
- {
- dto.ChannelName = channel.Name;
- }
- }
- }
-
- private void AddInheritedImages(BaseItemDto dto, BaseItem item, DtoOptions options, BaseItem owner)
- {
- var logoLimit = options.GetImageLimit(ImageType.Logo);
- var artLimit = options.GetImageLimit(ImageType.Art);
- var thumbLimit = options.GetImageLimit(ImageType.Thumb);
- var backdropLimit = options.GetImageLimit(ImageType.Backdrop);
-
- if (logoLimit == 0 && artLimit == 0 && thumbLimit == 0 && backdropLimit == 0)
- {
- return;
- }
-
- BaseItem parent = null;
- var isFirst = true;
-
- while (((!dto.HasLogo && logoLimit > 0) || (!dto.HasArtImage && artLimit > 0) || (!dto.HasThumb && thumbLimit > 0) || parent is Series) &&
- (parent = parent ?? (isFirst ? item.GetParent() ?? owner : parent)) != null)
- {
- if (parent == null)
- {
- break;
- }
-
- var allImages = parent.ImageInfos;
-
- if (logoLimit > 0 && !dto.HasLogo && dto.ParentLogoItemId == null)
- {
- var image = allImages.FirstOrDefault(i => i.Type == ImageType.Logo);
-
- if (image != null)
- {
- dto.ParentLogoItemId = GetDtoId(parent);
- dto.ParentLogoImageTag = GetImageCacheTag(parent, image);
- }
- }
- if (artLimit > 0 && !dto.HasArtImage && dto.ParentArtItemId == null)
- {
- var image = allImages.FirstOrDefault(i => i.Type == ImageType.Art);
-
- if (image != null)
- {
- dto.ParentArtItemId = GetDtoId(parent);
- dto.ParentArtImageTag = GetImageCacheTag(parent, image);
- }
- }
- if (thumbLimit > 0 && !dto.HasThumb && (dto.ParentThumbItemId == null || parent is Series))
- {
- var image = allImages.FirstOrDefault(i => i.Type == ImageType.Thumb);
-
- if (image != null)
- {
- dto.ParentThumbItemId = GetDtoId(parent);
- dto.ParentThumbImageTag = GetImageCacheTag(parent, image);
- }
- }
- if (backdropLimit > 0 && !dto.HasBackdrop)
- {
- var images = allImages.Where(i => i.Type == ImageType.Backdrop).Take(backdropLimit).ToList();
-
- if (images.Count > 0)
- {
- dto.ParentBackdropItemId = GetDtoId(parent);
- dto.ParentBackdropImageTags = GetImageTags(parent, images);
- }
- }
-
- isFirst = false;
- parent = parent.GetParent();
- }
- }
-
- private string GetMappedPath(BaseItem item)
- {
- var path = item.Path;
-
- var locationType = item.LocationType;
-
- if (locationType == LocationType.FileSystem || locationType == LocationType.Offline)
- {
- path = _libraryManager.GetPathAfterNetworkSubstitution(path, item);
- }
-
- return path;
- }
-
- /// <summary>
- /// Attaches the primary image aspect ratio.
- /// </summary>
- /// <param name="dto">The dto.</param>
- /// <param name="item">The item.</param>
- /// <returns>Task.</returns>
- public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item)
- {
- dto.PrimaryImageAspectRatio = GetPrimaryImageAspectRatio(item);
- }
-
- public double? GetPrimaryImageAspectRatio(IHasImages item)
- {
- var imageInfo = item.GetImageInfo(ImageType.Primary, 0);
-
- if (imageInfo == null || !imageInfo.IsLocalFile)
- {
- return null;
- }
-
- ImageSize size;
-
- try
- {
- size = _imageProcessor.GetImageSize(imageInfo);
- }
- catch
- {
- //_logger.ErrorException("Failed to determine primary image aspect ratio for {0}", ex, path);
- return null;
- }
-
- var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToList();
-
- foreach (var enhancer in supportedEnhancers)
- {
- try
- {
- size = enhancer.GetEnhancedImageSize(item, ImageType.Primary, 0, size);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in image enhancer: {0}", ex, enhancer.GetType().Name);
- }
- }
-
- var width = size.Width;
- var height = size.Height;
-
- if (width == 0 || height == 0)
- {
- return null;
- }
-
- var photo = item as Photo;
- if (photo != null && photo.Orientation.HasValue)
- {
- switch (photo.Orientation.Value)
- {
- case ImageOrientation.LeftBottom:
- case ImageOrientation.LeftTop:
- case ImageOrientation.RightBottom:
- case ImageOrientation.RightTop:
- var temp = height;
- height = width;
- width = temp;
- break;
- }
- }
-
- return width / height;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
deleted file mode 100644
index 19592bc4e..000000000
--- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
+++ /dev/null
@@ -1,831 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.FileOrganization;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.FileOrganization;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Server.Implementations.Library;
-using MediaBrowser.Server.Implementations.Logging;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Server.Implementations.FileOrganization
-{
- public class EpisodeFileOrganizer
- {
- private readonly ILibraryMonitor _libraryMonitor;
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
- private readonly IFileOrganizationService _organizationService;
- private readonly IServerConfigurationManager _config;
- private readonly IProviderManager _providerManager;
-
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
- public EpisodeFileOrganizer(IFileOrganizationService organizationService, IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager)
- {
- _organizationService = organizationService;
- _config = config;
- _fileSystem = fileSystem;
- _logger = logger;
- _libraryManager = libraryManager;
- _libraryMonitor = libraryMonitor;
- _providerManager = providerManager;
- }
-
- public async Task<FileOrganizationResult> OrganizeEpisodeFile(string path, AutoOrganizeOptions options, bool overwriteExisting, CancellationToken cancellationToken)
- {
- _logger.Info("Sorting file {0}", path);
-
- var result = new FileOrganizationResult
- {
- Date = DateTime.UtcNow,
- OriginalPath = path,
- OriginalFileName = Path.GetFileName(path),
- Type = FileOrganizerType.Episode,
- FileSize = new FileInfo(path).Length
- };
-
- try
- {
- if (_libraryMonitor.IsPathLocked(path))
- {
- result.Status = FileSortingStatus.Failure;
- result.StatusMessage = "Path is locked by other processes. Please try again later.";
- return result;
- }
-
- var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions();
- var resolver = new Naming.TV.EpisodeResolver(namingOptions, new PatternsLogger());
-
- var episodeInfo = resolver.Resolve(path, false) ??
- new Naming.TV.EpisodeInfo();
-
- var seriesName = episodeInfo.SeriesName;
-
- if (!string.IsNullOrEmpty(seriesName))
- {
- var seasonNumber = episodeInfo.SeasonNumber;
-
- result.ExtractedSeasonNumber = seasonNumber;
-
- // Passing in true will include a few extra regex's
- var episodeNumber = episodeInfo.EpisodeNumber;
-
- result.ExtractedEpisodeNumber = episodeNumber;
-
- var premiereDate = episodeInfo.IsByDate ?
- new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value) :
- (DateTime?)null;
-
- if (episodeInfo.IsByDate || (seasonNumber.HasValue && episodeNumber.HasValue))
- {
- if (episodeInfo.IsByDate)
- {
- _logger.Debug("Extracted information from {0}. Series name {1}, Date {2}", path, seriesName, premiereDate.Value);
- }
- else
- {
- _logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, seasonNumber, episodeNumber);
- }
-
- var endingEpisodeNumber = episodeInfo.EndingEpsiodeNumber;
-
- result.ExtractedEndingEpisodeNumber = endingEpisodeNumber;
-
- await OrganizeEpisode(path,
- seriesName,
- seasonNumber,
- episodeNumber,
- endingEpisodeNumber,
- premiereDate,
- options,
- overwriteExisting,
- false,
- result,
- cancellationToken).ConfigureAwait(false);
- }
- else
- {
- var msg = string.Format("Unable to determine episode number from {0}", path);
- result.Status = FileSortingStatus.Failure;
- result.StatusMessage = msg;
- _logger.Warn(msg);
- }
- }
- else
- {
- var msg = string.Format("Unable to determine series name from {0}", path);
- result.Status = FileSortingStatus.Failure;
- result.StatusMessage = msg;
- _logger.Warn(msg);
- }
-
- var previousResult = _organizationService.GetResultBySourcePath(path);
-
- if (previousResult != null)
- {
- // Don't keep saving the same result over and over if nothing has changed
- if (previousResult.Status == result.Status && previousResult.StatusMessage == result.StatusMessage && result.Status != FileSortingStatus.Success)
- {
- return previousResult;
- }
- }
-
- await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- result.Status = FileSortingStatus.Failure;
- result.StatusMessage = ex.Message;
- }
-
- return result;
- }
-
- public async Task<FileOrganizationResult> OrganizeWithCorrection(EpisodeFileOrganizationRequest request, AutoOrganizeOptions options, CancellationToken cancellationToken)
- {
- var result = _organizationService.GetResult(request.ResultId);
-
- try
- {
- Series series = null;
-
- if (request.NewSeriesProviderIds.Count > 0)
- {
- // We're having a new series here
- SeriesInfo seriesRequest = new SeriesInfo();
- seriesRequest.ProviderIds = request.NewSeriesProviderIds;
-
- var refreshOptions = new MetadataRefreshOptions(_fileSystem);
- series = new Series();
- series.Id = Guid.NewGuid();
- series.Name = request.NewSeriesName;
-
- int year;
- if (int.TryParse(request.NewSeriesYear, out year))
- {
- series.ProductionYear = year;
- }
-
- var seriesFolderName = series.Name;
- if (series.ProductionYear.HasValue)
- {
- seriesFolderName = string.Format("{0} ({1})", seriesFolderName, series.ProductionYear);
- }
-
- series.Path = Path.Combine(request.TargetFolder, seriesFolderName);
-
- series.ProviderIds = request.NewSeriesProviderIds;
-
- await series.RefreshMetadata(refreshOptions, cancellationToken);
- }
-
- if (series == null)
- {
- // Existing Series
- series = (Series)_libraryManager.GetItemById(new Guid(request.SeriesId));
- }
-
- await OrganizeEpisode(result.OriginalPath,
- series,
- request.SeasonNumber,
- request.EpisodeNumber,
- request.EndingEpisodeNumber,
- null,
- options,
- true,
- request.RememberCorrection,
- result,
- cancellationToken).ConfigureAwait(false);
-
- await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- result.Status = FileSortingStatus.Failure;
- result.StatusMessage = ex.Message;
- }
-
- return result;
- }
-
- private Task OrganizeEpisode(string sourcePath,
- string seriesName,
- int? seasonNumber,
- int? episodeNumber,
- int? endingEpiosdeNumber,
- DateTime? premiereDate,
- AutoOrganizeOptions options,
- bool overwriteExisting,
- bool rememberCorrection,
- FileOrganizationResult result,
- CancellationToken cancellationToken)
- {
- var series = GetMatchingSeries(seriesName, result, options);
-
- if (series == null)
- {
- var msg = string.Format("Unable to find series in library matching name {0}", seriesName);
- result.Status = FileSortingStatus.Failure;
- result.StatusMessage = msg;
- _logger.Warn(msg);
- return Task.FromResult(true);
- }
-
- return OrganizeEpisode(sourcePath,
- series,
- seasonNumber,
- episodeNumber,
- endingEpiosdeNumber,
- premiereDate,
- options,
- overwriteExisting,
- rememberCorrection,
- result,
- cancellationToken);
- }
-
- private async Task OrganizeEpisode(string sourcePath,
- Series series,
- int? seasonNumber,
- int? episodeNumber,
- int? endingEpiosdeNumber,
- DateTime? premiereDate,
- AutoOrganizeOptions options,
- bool overwriteExisting,
- bool rememberCorrection,
- FileOrganizationResult result,
- CancellationToken cancellationToken)
- {
- _logger.Info("Sorting file {0} into series {1}", sourcePath, series.Path);
-
- var originalExtractedSeriesString = result.ExtractedName;
-
- bool isNew = string.IsNullOrWhiteSpace(result.Id);
-
- if (isNew)
- {
- await _organizationService.SaveResult(result, cancellationToken);
- }
-
- if (!_organizationService.AddToInProgressList(result, isNew))
- {
- throw new Exception("File is currently processed otherwise. Please try again later.");
- }
-
- try
- {
- // Proceed to sort the file
- var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, premiereDate, options.TvOptions, cancellationToken).ConfigureAwait(false);
-
- if (string.IsNullOrEmpty(newPath))
- {
- var msg = string.Format("Unable to sort {0} because target path could not be determined.", sourcePath);
- throw new Exception(msg);
- }
-
- _logger.Info("Sorting file {0} to new path {1}", sourcePath, newPath);
- result.TargetPath = newPath;
-
- var fileExists = _fileSystem.FileExists(result.TargetPath);
- var otherDuplicatePaths = GetOtherDuplicatePaths(result.TargetPath, series, seasonNumber, episodeNumber, endingEpiosdeNumber);
-
- if (!overwriteExisting)
- {
- if (options.TvOptions.CopyOriginalFile && fileExists && IsSameEpisode(sourcePath, newPath))
- {
- var msg = string.Format("File '{0}' already copied to new path '{1}', stopping organization", sourcePath, newPath);
- _logger.Info(msg);
- result.Status = FileSortingStatus.SkippedExisting;
- result.StatusMessage = msg;
- return;
- }
-
- if (fileExists)
- {
- var msg = string.Format("File '{0}' already exists as '{1}', stopping organization", sourcePath, newPath);
- _logger.Info(msg);
- result.Status = FileSortingStatus.SkippedExisting;
- result.StatusMessage = msg;
- result.TargetPath = newPath;
- return;
- }
-
- if (otherDuplicatePaths.Count > 0)
- {
- var msg = string.Format("File '{0}' already exists as these:'{1}'. Stopping organization", sourcePath, string.Join("', '", otherDuplicatePaths));
- _logger.Info(msg);
- result.Status = FileSortingStatus.SkippedExisting;
- result.StatusMessage = msg;
- result.DuplicatePaths = otherDuplicatePaths;
- return;
- }
- }
-
- PerformFileSorting(options.TvOptions, result);
-
- if (overwriteExisting)
- {
- var hasRenamedFiles = false;
-
- foreach (var path in otherDuplicatePaths)
- {
- _logger.Debug("Removing duplicate episode {0}", path);
-
- _libraryMonitor.ReportFileSystemChangeBeginning(path);
-
- var renameRelatedFiles = !hasRenamedFiles &&
- string.Equals(Path.GetDirectoryName(path), Path.GetDirectoryName(result.TargetPath), StringComparison.OrdinalIgnoreCase);
-
- if (renameRelatedFiles)
- {
- hasRenamedFiles = true;
- }
-
- try
- {
- DeleteLibraryFile(path, renameRelatedFiles, result.TargetPath);
- }
- catch (IOException ex)
- {
- _logger.ErrorException("Error removing duplicate episode", ex, path);
- }
- finally
- {
- _libraryMonitor.ReportFileSystemChangeComplete(path, true);
- }
- }
- }
- }
- catch (Exception ex)
- {
- result.Status = FileSortingStatus.Failure;
- result.StatusMessage = ex.Message;
- _logger.Warn(ex.Message);
- return;
- }
- finally
- {
- _organizationService.RemoveFromInprogressList(result);
- }
-
- if (rememberCorrection)
- {
- SaveSmartMatchString(originalExtractedSeriesString, series, options);
- }
- }
-
- private void SaveSmartMatchString(string matchString, Series series, AutoOrganizeOptions options)
- {
- if (string.IsNullOrEmpty(matchString) || matchString.Length < 3)
- {
- return;
- }
-
- SmartMatchInfo info = options.SmartMatchInfos.FirstOrDefault(i => string.Equals(i.ItemName, series.Name, StringComparison.OrdinalIgnoreCase));
-
- if (info == null)
- {
- info = new SmartMatchInfo();
- info.ItemName = series.Name;
- info.OrganizerType = FileOrganizerType.Episode;
- info.DisplayName = series.Name;
- var list = options.SmartMatchInfos.ToList();
- list.Add(info);
- options.SmartMatchInfos = list.ToArray();
- }
-
- if (!info.MatchStrings.Contains(matchString, StringComparer.OrdinalIgnoreCase))
- {
- var list = info.MatchStrings.ToList();
- list.Add(matchString);
- info.MatchStrings = list.ToArray();
- _config.SaveAutoOrganizeOptions(options);
- }
- }
-
- private void DeleteLibraryFile(string path, bool renameRelatedFiles, string targetPath)
- {
- _fileSystem.DeleteFile(path);
-
- if (!renameRelatedFiles)
- {
- return;
- }
-
- // Now find other files
- var originalFilenameWithoutExtension = Path.GetFileNameWithoutExtension(path);
- var directory = Path.GetDirectoryName(path);
-
- if (!string.IsNullOrWhiteSpace(originalFilenameWithoutExtension) && !string.IsNullOrWhiteSpace(directory))
- {
- // Get all related files, e.g. metadata, images, etc
- var files = _fileSystem.GetFilePaths(directory)
- .Where(i => (Path.GetFileNameWithoutExtension(i) ?? string.Empty).StartsWith(originalFilenameWithoutExtension, StringComparison.OrdinalIgnoreCase))
- .ToList();
-
- var targetFilenameWithoutExtension = Path.GetFileNameWithoutExtension(targetPath);
-
- foreach (var file in files)
- {
- directory = Path.GetDirectoryName(file);
- var filename = Path.GetFileName(file);
-
- filename = filename.Replace(originalFilenameWithoutExtension, targetFilenameWithoutExtension,
- StringComparison.OrdinalIgnoreCase);
-
- var destination = Path.Combine(directory, filename);
-
- _fileSystem.MoveFile(file, destination);
- }
- }
- }
-
- private List<string> GetOtherDuplicatePaths(string targetPath,
- Series series,
- int? seasonNumber,
- int? episodeNumber,
- int? endingEpisodeNumber)
- {
- // TODO: Support date-naming?
- if (!seasonNumber.HasValue || !episodeNumber.HasValue)
- {
- return new List<string>();
- }
-
- var episodePaths = series.GetRecursiveChildren()
- .OfType<Episode>()
- .Where(i =>
- {
- var locationType = i.LocationType;
-
- // Must be file system based and match exactly
- if (locationType != LocationType.Remote &&
- locationType != LocationType.Virtual &&
- i.ParentIndexNumber.HasValue &&
- i.ParentIndexNumber.Value == seasonNumber &&
- i.IndexNumber.HasValue &&
- i.IndexNumber.Value == episodeNumber)
- {
-
- if (endingEpisodeNumber.HasValue || i.IndexNumberEnd.HasValue)
- {
- return endingEpisodeNumber.HasValue && i.IndexNumberEnd.HasValue &&
- endingEpisodeNumber.Value == i.IndexNumberEnd.Value;
- }
-
- return true;
- }
-
- return false;
- })
- .Select(i => i.Path)
- .ToList();
-
- var folder = Path.GetDirectoryName(targetPath);
- var targetFileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(targetPath);
-
- try
- {
- var filesOfOtherExtensions = _fileSystem.GetFilePaths(folder)
- .Where(i => _libraryManager.IsVideoFile(i) && string.Equals(_fileSystem.GetFileNameWithoutExtension(i), targetFileNameWithoutExtension, StringComparison.OrdinalIgnoreCase));
-
- episodePaths.AddRange(filesOfOtherExtensions);
- }
- catch (DirectoryNotFoundException)
- {
- // No big deal. Maybe the season folder doesn't already exist.
- }
-
- return episodePaths.Where(i => !string.Equals(i, targetPath, StringComparison.OrdinalIgnoreCase))
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
- }
-
- private void PerformFileSorting(TvFileOrganizationOptions options, FileOrganizationResult result)
- {
- _libraryMonitor.ReportFileSystemChangeBeginning(result.TargetPath);
-
- _fileSystem.CreateDirectory(Path.GetDirectoryName(result.TargetPath));
-
- var targetAlreadyExists = _fileSystem.FileExists(result.TargetPath);
-
- try
- {
- if (targetAlreadyExists || options.CopyOriginalFile)
- {
- _fileSystem.CopyFile(result.OriginalPath, result.TargetPath, true);
- }
- else
- {
- _fileSystem.MoveFile(result.OriginalPath, result.TargetPath);
- }
-
- result.Status = FileSortingStatus.Success;
- result.StatusMessage = string.Empty;
- }
- catch (Exception ex)
- {
- var errorMsg = string.Format("Failed to move file from {0} to {1}: {2}", result.OriginalPath, result.TargetPath, ex.Message);
-
- result.Status = FileSortingStatus.Failure;
- result.StatusMessage = errorMsg;
- _logger.ErrorException(errorMsg, ex);
-
- return;
- }
- finally
- {
- _libraryMonitor.ReportFileSystemChangeComplete(result.TargetPath, true);
- }
-
- if (targetAlreadyExists && !options.CopyOriginalFile)
- {
- try
- {
- _fileSystem.DeleteFile(result.OriginalPath);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error deleting {0}", ex, result.OriginalPath);
- }
- }
- }
-
- private Series GetMatchingSeries(string seriesName, FileOrganizationResult result, AutoOrganizeOptions options)
- {
- var parsedName = _libraryManager.ParseName(seriesName);
-
- var yearInName = parsedName.Year;
- var nameWithoutYear = parsedName.Name;
-
- result.ExtractedName = nameWithoutYear;
- result.ExtractedYear = yearInName;
-
- var series = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(Series).Name },
- Recursive = true
- })
- .Cast<Series>()
- .Select(i => NameUtils.GetMatchScore(nameWithoutYear, yearInName, i))
- .Where(i => i.Item2 > 0)
- .OrderByDescending(i => i.Item2)
- .Select(i => i.Item1)
- .FirstOrDefault();
-
- if (series == null)
- {
- SmartMatchInfo info = options.SmartMatchInfos.FirstOrDefault(e => e.MatchStrings.Contains(nameWithoutYear, StringComparer.OrdinalIgnoreCase));
-
- if (info != null)
- {
- series = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(Series).Name },
- Recursive = true,
- Name = info.ItemName
-
- }).Cast<Series>().FirstOrDefault();
- }
- }
-
- return series;
- }
-
- /// <summary>
- /// Gets the new path.
- /// </summary>
- /// <param name="sourcePath">The source path.</param>
- /// <param name="series">The series.</param>
- /// <param name="seasonNumber">The season number.</param>
- /// <param name="episodeNumber">The episode number.</param>
- /// <param name="endingEpisodeNumber">The ending episode number.</param>
- /// <param name="premiereDate">The premiere date.</param>
- /// <param name="options">The options.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>System.String.</returns>
- private async Task<string> GetNewPath(string sourcePath,
- Series series,
- int? seasonNumber,
- int? episodeNumber,
- int? endingEpisodeNumber,
- DateTime? premiereDate,
- TvFileOrganizationOptions options,
- CancellationToken cancellationToken)
- {
- var episodeInfo = new EpisodeInfo
- {
- IndexNumber = episodeNumber,
- IndexNumberEnd = endingEpisodeNumber,
- MetadataCountryCode = series.GetPreferredMetadataCountryCode(),
- MetadataLanguage = series.GetPreferredMetadataLanguage(),
- ParentIndexNumber = seasonNumber,
- SeriesProviderIds = series.ProviderIds,
- PremiereDate = premiereDate
- };
-
- var searchResults = await _providerManager.GetRemoteSearchResults<Episode, EpisodeInfo>(new RemoteSearchQuery<EpisodeInfo>
- {
- SearchInfo = episodeInfo
-
- }, cancellationToken).ConfigureAwait(false);
-
- var episode = searchResults.FirstOrDefault();
-
- if (episode == null)
- {
- var msg = string.Format("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber);
- _logger.Warn(msg);
- throw new Exception(msg);
- }
-
- var episodeName = episode.Name;
-
- //if (string.IsNullOrWhiteSpace(episodeName))
- //{
- // var msg = string.Format("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber);
- // _logger.Warn(msg);
- // return null;
- //}
-
- seasonNumber = seasonNumber ?? episode.ParentIndexNumber;
- episodeNumber = episodeNumber ?? episode.IndexNumber;
-
- var newPath = GetSeasonFolderPath(series, seasonNumber.Value, options);
-
- // MAX_PATH - trailing <NULL> charachter - drive component: 260 - 1 - 3 = 256
- // Usually newPath would include the drive component, but use 256 to be sure
- var maxFilenameLength = 256 - newPath.Length;
-
- if (!newPath.EndsWith(@"\"))
- {
- // Remove 1 for missing backslash combining path and filename
- maxFilenameLength--;
- }
-
- // Remove additional 4 chars to prevent PathTooLongException for downloaded subtitles (eg. filename.ext.eng.srt)
- maxFilenameLength -= 4;
-
- var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber.Value, episodeNumber.Value, endingEpisodeNumber, episodeName, options, maxFilenameLength);
-
- if (string.IsNullOrEmpty(episodeFileName))
- {
- // cause failure
- return string.Empty;
- }
-
- newPath = Path.Combine(newPath, episodeFileName);
-
- return newPath;
- }
-
- /// <summary>
- /// Gets the season folder path.
- /// </summary>
- /// <param name="series">The series.</param>
- /// <param name="seasonNumber">The season number.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- private string GetSeasonFolderPath(Series series, int seasonNumber, TvFileOrganizationOptions options)
- {
- // If there's already a season folder, use that
- var season = series
- .GetRecursiveChildren(i => i is Season && i.LocationType == LocationType.FileSystem && i.IndexNumber.HasValue && i.IndexNumber.Value == seasonNumber)
- .FirstOrDefault();
-
- if (season != null)
- {
- return season.Path;
- }
-
- var path = series.Path;
-
- if (series.ContainsEpisodesWithoutSeasonFolders)
- {
- return path;
- }
-
- if (seasonNumber == 0)
- {
- return Path.Combine(path, _fileSystem.GetValidFilename(options.SeasonZeroFolderName));
- }
-
- var seasonFolderName = options.SeasonFolderPattern
- .Replace("%s", seasonNumber.ToString(_usCulture))
- .Replace("%0s", seasonNumber.ToString("00", _usCulture))
- .Replace("%00s", seasonNumber.ToString("000", _usCulture));
-
- return Path.Combine(path, _fileSystem.GetValidFilename(seasonFolderName));
- }
-
- private string GetEpisodeFileName(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, string episodeTitle, TvFileOrganizationOptions options, int? maxLength)
- {
- seriesName = _fileSystem.GetValidFilename(seriesName).Trim();
-
- if (string.IsNullOrWhiteSpace(episodeTitle))
- {
- episodeTitle = string.Empty;
- }
- else
- {
- episodeTitle = _fileSystem.GetValidFilename(episodeTitle).Trim();
- }
-
- var sourceExtension = (Path.GetExtension(sourcePath) ?? string.Empty).TrimStart('.');
-
- var pattern = endingEpisodeNumber.HasValue ? options.MultiEpisodeNamePattern : options.EpisodeNamePattern;
-
- if (string.IsNullOrWhiteSpace(pattern))
- {
- throw new Exception("GetEpisodeFileName: Configured episode name pattern is empty!");
- }
-
- var result = pattern.Replace("%sn", seriesName)
- .Replace("%s.n", seriesName.Replace(" ", "."))
- .Replace("%s_n", seriesName.Replace(" ", "_"))
- .Replace("%s", seasonNumber.ToString(_usCulture))
- .Replace("%0s", seasonNumber.ToString("00", _usCulture))
- .Replace("%00s", seasonNumber.ToString("000", _usCulture))
- .Replace("%ext", sourceExtension)
- .Replace("%en", "%#1")
- .Replace("%e.n", "%#2")
- .Replace("%e_n", "%#3");
-
- if (endingEpisodeNumber.HasValue)
- {
- result = result.Replace("%ed", endingEpisodeNumber.Value.ToString(_usCulture))
- .Replace("%0ed", endingEpisodeNumber.Value.ToString("00", _usCulture))
- .Replace("%00ed", endingEpisodeNumber.Value.ToString("000", _usCulture));
- }
-
- result = result.Replace("%e", episodeNumber.ToString(_usCulture))
- .Replace("%0e", episodeNumber.ToString("00", _usCulture))
- .Replace("%00e", episodeNumber.ToString("000", _usCulture));
-
- if (maxLength.HasValue && result.Contains("%#"))
- {
- // Substract 3 for the temp token length (%#1, %#2 or %#3)
- int maxRemainingTitleLength = maxLength.Value - result.Length + 3;
- string shortenedEpisodeTitle = string.Empty;
-
- if (maxRemainingTitleLength > 5)
- {
- // A title with fewer than 5 letters wouldn't be of much value
- shortenedEpisodeTitle = episodeTitle.Substring(0, Math.Min(maxRemainingTitleLength, episodeTitle.Length));
- }
-
- result = result.Replace("%#1", shortenedEpisodeTitle)
- .Replace("%#2", shortenedEpisodeTitle.Replace(" ", "."))
- .Replace("%#3", shortenedEpisodeTitle.Replace(" ", "_"));
- }
-
- if (maxLength.HasValue && result.Length > maxLength.Value)
- {
- // There may be cases where reducing the title length may still not be sufficient to
- // stay below maxLength
- var msg = string.Format("Unable to generate an episode file name shorter than {0} characters to constrain to the max path limit", maxLength);
- throw new Exception(msg);
- }
-
- return result;
- }
-
- private bool IsSameEpisode(string sourcePath, string newPath)
- {
- try
- {
- var sourceFileInfo = new FileInfo(sourcePath);
- var destinationFileInfo = new FileInfo(newPath);
-
- if (sourceFileInfo.Length == destinationFileInfo.Length)
- {
- return true;
- }
- }
- catch (FileNotFoundException)
- {
- return false;
- }
- catch (DirectoryNotFoundException)
- {
- return false;
- }
-
- return false;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/Extensions.cs b/MediaBrowser.Server.Implementations/FileOrganization/Extensions.cs
deleted file mode 100644
index c560152db..000000000
--- a/MediaBrowser.Server.Implementations/FileOrganization/Extensions.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Model.FileOrganization;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Server.Implementations.FileOrganization
-{
- public static class ConfigurationExtension
- {
- public static AutoOrganizeOptions GetAutoOrganizeOptions(this IConfigurationManager manager)
- {
- return manager.GetConfiguration<AutoOrganizeOptions>("autoorganize");
- }
- public static void SaveAutoOrganizeOptions(this IConfigurationManager manager, AutoOrganizeOptions options)
- {
- manager.SaveConfiguration("autoorganize", options);
- }
- }
-
- public class AutoOrganizeOptionsFactory : IConfigurationFactory
- {
- public IEnumerable<ConfigurationStore> GetConfigurations()
- {
- return new List<ConfigurationStore>
- {
- new ConfigurationStore
- {
- Key = "autoorganize",
- ConfigurationType = typeof (AutoOrganizeOptions)
- }
- };
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationNotifier.cs b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationNotifier.cs
deleted file mode 100644
index 141dcf9b4..000000000
--- a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationNotifier.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using MediaBrowser.Controller.FileOrganization;
-using MediaBrowser.Controller.Plugins;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.FileOrganization;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Server.Implementations.FileOrganization
-{
- /// <summary>
- /// Class SessionInfoWebSocketListener
- /// </summary>
- class FileOrganizationNotifier : IServerEntryPoint
- {
- private readonly IFileOrganizationService _organizationService;
- private readonly ISessionManager _sessionManager;
- private readonly ITaskManager _taskManager;
-
- public FileOrganizationNotifier(ILogger logger, IFileOrganizationService organizationService, ISessionManager sessionManager, ITaskManager taskManager)
- {
- _organizationService = organizationService;
- _sessionManager = sessionManager;
- _taskManager = taskManager;
- }
-
- public void Run()
- {
- _organizationService.ItemAdded += _organizationService_ItemAdded;
- _organizationService.ItemRemoved += _organizationService_ItemRemoved;
- _organizationService.ItemUpdated += _organizationService_ItemUpdated;
- _organizationService.LogReset += _organizationService_LogReset;
-
- //_taskManager.TaskCompleted += _taskManager_TaskCompleted;
- }
-
- private void _organizationService_LogReset(object sender, EventArgs e)
- {
- _sessionManager.SendMessageToAdminSessions("AutoOrganize_LogReset", (FileOrganizationResult)null, CancellationToken.None);
- }
-
- private void _organizationService_ItemUpdated(object sender, GenericEventArgs<FileOrganizationResult> e)
- {
- _sessionManager.SendMessageToAdminSessions("AutoOrganize_ItemUpdated", e.Argument, CancellationToken.None);
- }
-
- private void _organizationService_ItemRemoved(object sender, GenericEventArgs<FileOrganizationResult> e)
- {
- _sessionManager.SendMessageToAdminSessions("AutoOrganize_ItemRemoved", e.Argument, CancellationToken.None);
- }
-
- private void _organizationService_ItemAdded(object sender, GenericEventArgs<FileOrganizationResult> e)
- {
- _sessionManager.SendMessageToAdminSessions("AutoOrganize_ItemAdded", e.Argument, CancellationToken.None);
- }
-
- //private void _taskManager_TaskCompleted(object sender, TaskCompletionEventArgs e)
- //{
- // var taskWithKey = e.Task.ScheduledTask as IHasKey;
- // if (taskWithKey != null && taskWithKey.Key == "AutoOrganize")
- // {
- // _sessionManager.SendMessageToAdminSessions("AutoOrganize_TaskCompleted", (FileOrganizationResult)null, CancellationToken.None);
- // }
- //}
-
- public void Dispose()
- {
- _organizationService.ItemAdded -= _organizationService_ItemAdded;
- _organizationService.ItemRemoved -= _organizationService_ItemRemoved;
- _organizationService.ItemUpdated -= _organizationService_ItemUpdated;
- _organizationService.LogReset -= _organizationService_LogReset;
-
- //_taskManager.TaskCompleted -= _taskManager_TaskCompleted;
- }
-
-
- }
-}
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs
deleted file mode 100644
index de33c39e6..000000000
--- a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs
+++ /dev/null
@@ -1,283 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.FileOrganization;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.FileOrganization;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Querying;
-using System;
-using System.Collections.Concurrent;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Common.Events;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Server.Implementations.FileOrganization
-{
- public class FileOrganizationService : IFileOrganizationService
- {
- private readonly ITaskManager _taskManager;
- private readonly IFileOrganizationRepository _repo;
- private readonly ILogger _logger;
- private readonly ILibraryMonitor _libraryMonitor;
- private readonly ILibraryManager _libraryManager;
- private readonly IServerConfigurationManager _config;
- private readonly IFileSystem _fileSystem;
- private readonly IProviderManager _providerManager;
- private readonly ConcurrentDictionary<string, bool> _inProgressItemIds = new ConcurrentDictionary<string, bool>();
-
- public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemAdded;
- public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemUpdated;
- public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemRemoved;
- public event EventHandler LogReset;
-
- public FileOrganizationService(ITaskManager taskManager, IFileOrganizationRepository repo, ILogger logger, ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, IServerConfigurationManager config, IFileSystem fileSystem, IProviderManager providerManager)
- {
- _taskManager = taskManager;
- _repo = repo;
- _logger = logger;
- _libraryMonitor = libraryMonitor;
- _libraryManager = libraryManager;
- _config = config;
- _fileSystem = fileSystem;
- _providerManager = providerManager;
- }
-
- public void BeginProcessNewFiles()
- {
- _taskManager.CancelIfRunningAndQueue<OrganizerScheduledTask>();
- }
-
- public Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken)
- {
- if (result == null || string.IsNullOrEmpty(result.OriginalPath))
- {
- throw new ArgumentNullException("result");
- }
-
- result.Id = result.OriginalPath.GetMD5().ToString("N");
-
- return _repo.SaveResult(result, cancellationToken);
- }
-
- public QueryResult<FileOrganizationResult> GetResults(FileOrganizationResultQuery query)
- {
- var results = _repo.GetResults(query);
-
- foreach (var result in results.Items)
- {
- result.IsInProgress = _inProgressItemIds.ContainsKey(result.Id);
- }
-
- return results;
- }
-
- public FileOrganizationResult GetResult(string id)
- {
- var result = _repo.GetResult(id);
-
- if (result != null)
- {
- result.IsInProgress = _inProgressItemIds.ContainsKey(result.Id);
- }
-
- return result;
- }
-
- public FileOrganizationResult GetResultBySourcePath(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var id = path.GetMD5().ToString("N");
-
- return GetResult(id);
- }
-
- public async Task DeleteOriginalFile(string resultId)
- {
- var result = _repo.GetResult(resultId);
-
- _logger.Info("Requested to delete {0}", result.OriginalPath);
-
- if (!AddToInProgressList(result, false))
- {
- throw new Exception("Path is currently processed otherwise. Please try again later.");
- }
-
- try
- {
- _fileSystem.DeleteFile(result.OriginalPath);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error deleting {0}", ex, result.OriginalPath);
- }
- finally
- {
- RemoveFromInprogressList(result);
- }
-
- await _repo.Delete(resultId);
-
- EventHelper.FireEventIfNotNull(ItemRemoved, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
- }
-
- private AutoOrganizeOptions GetAutoOrganizeOptions()
- {
- return _config.GetAutoOrganizeOptions();
- }
-
- public async Task PerformOrganization(string resultId)
- {
- var result = _repo.GetResult(resultId);
-
- if (string.IsNullOrEmpty(result.TargetPath))
- {
- throw new ArgumentException("No target path available.");
- }
-
- var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
- _libraryMonitor, _providerManager);
-
- var organizeResult = await organizer.OrganizeEpisodeFile(result.OriginalPath, GetAutoOrganizeOptions(), true, CancellationToken.None)
- .ConfigureAwait(false);
-
- if (organizeResult.Status != FileSortingStatus.Success)
- {
- throw new Exception(result.StatusMessage);
- }
- }
-
- public async Task ClearLog()
- {
- await _repo.DeleteAll();
- EventHelper.FireEventIfNotNull(LogReset, this, EventArgs.Empty, _logger);
- }
-
- public async Task PerformEpisodeOrganization(EpisodeFileOrganizationRequest request)
- {
- var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
- _libraryMonitor, _providerManager);
-
- var result = await organizer.OrganizeWithCorrection(request, GetAutoOrganizeOptions(), CancellationToken.None).ConfigureAwait(false);
-
- if (result.Status != FileSortingStatus.Success)
- {
- throw new Exception(result.StatusMessage);
- }
- }
-
- public QueryResult<SmartMatchInfo> GetSmartMatchInfos(FileOrganizationResultQuery query)
- {
- if (query == null)
- {
- throw new ArgumentNullException("query");
- }
-
- var options = GetAutoOrganizeOptions();
-
- var items = options.SmartMatchInfos.Skip(query.StartIndex ?? 0).Take(query.Limit ?? Int32.MaxValue).ToArray();
-
- return new QueryResult<SmartMatchInfo>()
- {
- Items = items,
- TotalRecordCount = options.SmartMatchInfos.Length
- };
- }
-
- public void DeleteSmartMatchEntry(string itemName, string matchString)
- {
- if (string.IsNullOrEmpty(itemName))
- {
- throw new ArgumentNullException("itemName");
- }
-
- if (string.IsNullOrEmpty(matchString))
- {
- throw new ArgumentNullException("matchString");
- }
-
- var options = GetAutoOrganizeOptions();
-
- SmartMatchInfo info = options.SmartMatchInfos.FirstOrDefault(i => string.Equals(i.ItemName, itemName));
-
- if (info != null && info.MatchStrings.Contains(matchString))
- {
- var list = info.MatchStrings.ToList();
- list.Remove(matchString);
- info.MatchStrings = list.ToArray();
-
- if (info.MatchStrings.Length == 0)
- {
- var infos = options.SmartMatchInfos.ToList();
- infos.Remove(info);
- options.SmartMatchInfos = infos.ToArray();
- }
-
- _config.SaveAutoOrganizeOptions(options);
- }
- }
-
- /// <summary>
- /// Attempts to add a an item to the list of currently processed items.
- /// </summary>
- /// <param name="result">The result item.</param>
- /// <param name="isNewItem">Passing true will notify the client to reload all items, otherwise only a single item will be refreshed.</param>
- /// <returns>True if the item was added, False if the item is already contained in the list.</returns>
- public bool AddToInProgressList(FileOrganizationResult result, bool isNewItem)
- {
- if (string.IsNullOrWhiteSpace(result.Id))
- {
- result.Id = result.OriginalPath.GetMD5().ToString("N");
- }
-
- if (!_inProgressItemIds.TryAdd(result.Id, false))
- {
- return false;
- }
-
- result.IsInProgress = true;
-
- if (isNewItem)
- {
- EventHelper.FireEventIfNotNull(ItemAdded, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
- }
- else
- {
- EventHelper.FireEventIfNotNull(ItemUpdated, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
- }
-
- return true;
- }
-
- /// <summary>
- /// Removes an item from the list of currently processed items.
- /// </summary>
- /// <param name="result">The result item.</param>
- /// <returns>True if the item was removed, False if the item was not contained in the list.</returns>
- public bool RemoveFromInprogressList(FileOrganizationResult result)
- {
- bool itemValue;
- var retval = _inProgressItemIds.TryRemove(result.Id, out itemValue);
-
- result.IsInProgress = false;
-
- EventHelper.FireEventIfNotNull(ItemUpdated, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
-
- return retval;
- }
-
- }
-}
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/NameUtils.cs b/MediaBrowser.Server.Implementations/FileOrganization/NameUtils.cs
deleted file mode 100644
index 624133d4f..000000000
--- a/MediaBrowser.Server.Implementations/FileOrganization/NameUtils.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Controller.Entities;
-using System;
-using System.Globalization;
-using System.Linq;
-using System.Text;
-
-namespace MediaBrowser.Server.Implementations.FileOrganization
-{
- public static class NameUtils
- {
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- internal static Tuple<T, int> GetMatchScore<T>(string sortedName, int? year, T series)
- where T : BaseItem
- {
- var score = 0;
-
- var seriesNameWithoutYear = series.Name;
- if (series.ProductionYear.HasValue)
- {
- seriesNameWithoutYear = seriesNameWithoutYear.Replace(series.ProductionYear.Value.ToString(UsCulture), String.Empty);
- }
-
- if (IsNameMatch(sortedName, seriesNameWithoutYear))
- {
- score++;
-
- if (year.HasValue && series.ProductionYear.HasValue)
- {
- if (year.Value == series.ProductionYear.Value)
- {
- score++;
- }
- else
- {
- // Regardless of name, return a 0 score if the years don't match
- return new Tuple<T, int>(series, 0);
- }
- }
- }
-
- return new Tuple<T, int>(series, score);
- }
-
-
- private static bool IsNameMatch(string name1, string name2)
- {
- name1 = GetComparableName(name1);
- name2 = GetComparableName(name2);
-
- return String.Equals(name1, name2, StringComparison.OrdinalIgnoreCase);
- }
-
- private static string GetComparableName(string name)
- {
- name = RemoveDiacritics(name);
-
- name = " " + name + " ";
-
- name = name.Replace(".", " ")
- .Replace("_", " ")
- .Replace(" and ", " ")
- .Replace(".and.", " ")
- .Replace("&", " ")
- .Replace("!", " ")
- .Replace("(", " ")
- .Replace(")", " ")
- .Replace(":", " ")
- .Replace(",", " ")
- .Replace("-", " ")
- .Replace("'", " ")
- .Replace("[", " ")
- .Replace("]", " ")
- .Replace(" a ", String.Empty, StringComparison.OrdinalIgnoreCase)
- .Replace(" the ", String.Empty, StringComparison.OrdinalIgnoreCase)
- .Replace(" ", String.Empty);
-
- return name.Trim();
- }
-
- /// <summary>
- /// Removes the diacritics.
- /// </summary>
- /// <param name="text">The text.</param>
- /// <returns>System.String.</returns>
- private static string RemoveDiacritics(string text)
- {
- return String.Concat(
- text.Normalize(NormalizationForm.FormD)
- .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) !=
- UnicodeCategory.NonSpacingMark)
- ).Normalize(NormalizationForm.FormC);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs b/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs
deleted file mode 100644
index ca41db80c..000000000
--- a/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.FileOrganization;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.FileOrganization;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Server.Implementations.FileOrganization
-{
- public class OrganizerScheduledTask : IScheduledTask, IConfigurableScheduledTask
- {
- private readonly ILibraryMonitor _libraryMonitor;
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
- private readonly IServerConfigurationManager _config;
- private readonly IFileOrganizationService _organizationService;
- private readonly IProviderManager _providerManager;
-
- public OrganizerScheduledTask(ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, IServerConfigurationManager config, IFileOrganizationService organizationService, IProviderManager providerManager)
- {
- _libraryMonitor = libraryMonitor;
- _libraryManager = libraryManager;
- _logger = logger;
- _fileSystem = fileSystem;
- _config = config;
- _organizationService = organizationService;
- _providerManager = providerManager;
- }
-
- public string Name
- {
- get { return "Organize new media files"; }
- }
-
- public string Description
- {
- get { return "Processes new files available in the configured watch folder."; }
- }
-
- public string Category
- {
- get { return "Library"; }
- }
-
- private AutoOrganizeOptions GetAutoOrganizeOptions()
- {
- return _config.GetAutoOrganizeOptions();
- }
-
- public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
- {
- if (GetAutoOrganizeOptions().TvOptions.IsEnabled)
- {
- await new TvFolderOrganizer(_libraryManager, _logger, _fileSystem, _libraryMonitor, _organizationService, _config, _providerManager)
- .Organize(GetAutoOrganizeOptions(), cancellationToken, progress).ConfigureAwait(false);
- }
- }
-
- /// <summary>
- /// Creates the triggers that define when the task will run
- /// </summary>
- /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
- public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
- {
- return new[] {
-
- // Every so often
- new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromMinutes(5).Ticks}
- };
- }
-
- public bool IsHidden
- {
- get { return !GetAutoOrganizeOptions().TvOptions.IsEnabled; }
- }
-
- public bool IsEnabled
- {
- get { return GetAutoOrganizeOptions().TvOptions.IsEnabled; }
- }
-
- public bool IsLogged
- {
- get { return false; }
- }
-
- public string Key
- {
- get { return "AutoOrganize"; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
deleted file mode 100644
index d83aee25b..000000000
--- a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
+++ /dev/null
@@ -1,210 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.FileOrganization;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.FileOrganization;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Server.Implementations.FileOrganization
-{
- public class TvFolderOrganizer
- {
- private readonly ILibraryMonitor _libraryMonitor;
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
- private readonly IFileOrganizationService _organizationService;
- private readonly IServerConfigurationManager _config;
- private readonly IProviderManager _providerManager;
-
- public TvFolderOrganizer(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IFileOrganizationService organizationService, IServerConfigurationManager config, IProviderManager providerManager)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _fileSystem = fileSystem;
- _libraryMonitor = libraryMonitor;
- _organizationService = organizationService;
- _config = config;
- _providerManager = providerManager;
- }
-
- private bool EnableOrganization(FileSystemMetadata fileInfo, TvFileOrganizationOptions options)
- {
- var minFileBytes = options.MinFileSizeMb * 1024 * 1024;
-
- try
- {
- return _libraryManager.IsVideoFile(fileInfo.FullName) && fileInfo.Length >= minFileBytes;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error organizing file {0}", ex, fileInfo.Name);
- }
-
- return false;
- }
-
- public async Task Organize(AutoOrganizeOptions options, CancellationToken cancellationToken, IProgress<double> progress)
- {
- var watchLocations = options.TvOptions.WatchLocations.ToList();
-
- var eligibleFiles = watchLocations.SelectMany(GetFilesToOrganize)
- .OrderBy(_fileSystem.GetCreationTimeUtc)
- .Where(i => EnableOrganization(i, options.TvOptions))
- .ToList();
-
- var processedFolders = new HashSet<string>();
-
- progress.Report(10);
-
- if (eligibleFiles.Count > 0)
- {
- var numComplete = 0;
-
- foreach (var file in eligibleFiles)
- {
- var organizer = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager,
- _libraryMonitor, _providerManager);
-
- try
- {
- var result = await organizer.OrganizeEpisodeFile(file.FullName, options, options.TvOptions.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false);
- if (result.Status == FileSortingStatus.Success && !processedFolders.Contains(file.DirectoryName, StringComparer.OrdinalIgnoreCase))
- {
- processedFolders.Add(file.DirectoryName);
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error organizing episode {0}", ex, file.FullName);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= eligibleFiles.Count;
-
- progress.Report(10 + 89 * percent);
- }
- }
-
- cancellationToken.ThrowIfCancellationRequested();
- progress.Report(99);
-
- foreach (var path in processedFolders)
- {
- var deleteExtensions = options.TvOptions.LeftOverFileExtensionsToDelete
- .Select(i => i.Trim().TrimStart('.'))
- .Where(i => !string.IsNullOrEmpty(i))
- .Select(i => "." + i)
- .ToList();
-
- if (deleteExtensions.Count > 0)
- {
- DeleteLeftOverFiles(path, deleteExtensions);
- }
-
- if (options.TvOptions.DeleteEmptyFolders)
- {
- if (!IsWatchFolder(path, watchLocations))
- {
- DeleteEmptyFolders(path);
- }
- }
- }
-
- progress.Report(100);
- }
-
- /// <summary>
- /// Gets the files to organize.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>IEnumerable{FileInfo}.</returns>
- private List<FileSystemMetadata> GetFilesToOrganize(string path)
- {
- try
- {
- return _fileSystem.GetFiles(path, true)
- .ToList();
- }
- catch (IOException ex)
- {
- _logger.ErrorException("Error getting files from {0}", ex, path);
-
- return new List<FileSystemMetadata>();
- }
- }
-
- /// <summary>
- /// Deletes the left over files.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="extensions">The extensions.</param>
- private void DeleteLeftOverFiles(string path, IEnumerable<string> extensions)
- {
- var eligibleFiles = _fileSystem.GetFiles(path, true)
- .Where(i => extensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase))
- .ToList();
-
- foreach (var file in eligibleFiles)
- {
- try
- {
- _fileSystem.DeleteFile(file.FullName);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error deleting file {0}", ex, file.FullName);
- }
- }
- }
-
- /// <summary>
- /// Deletes the empty folders.
- /// </summary>
- /// <param name="path">The path.</param>
- private void DeleteEmptyFolders(string path)
- {
- try
- {
- foreach (var d in _fileSystem.GetDirectoryPaths(path))
- {
- DeleteEmptyFolders(d);
- }
-
- var entries = _fileSystem.GetFileSystemEntryPaths(path);
-
- if (!entries.Any())
- {
- try
- {
- _logger.Debug("Deleting empty directory {0}", path);
- _fileSystem.DeleteDirectory(path, false);
- }
- catch (UnauthorizedAccessException) { }
- catch (DirectoryNotFoundException) { }
- }
- }
- catch (UnauthorizedAccessException) { }
- }
-
- /// <summary>
- /// Determines if a given folder path is contained in a folder list
- /// </summary>
- /// <param name="path">The folder path to check.</param>
- /// <param name="watchLocations">A list of folders.</param>
- private bool IsWatchFolder(string path, IEnumerable<string> watchLocations)
- {
- return watchLocations.Contains(path, StringComparer.OrdinalIgnoreCase);
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/IO/FileRefresher.cs b/MediaBrowser.Server.Implementations/IO/FileRefresher.cs
index eeefdd65a..2742e1a26 100644
--- a/MediaBrowser.Server.Implementations/IO/FileRefresher.cs
+++ b/MediaBrowser.Server.Implementations/IO/FileRefresher.cs
@@ -14,7 +14,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks;
-using MediaBrowser.Server.Implementations.ScheduledTasks;
+using MediaBrowser.Model.Threading;
namespace MediaBrowser.Server.Implementations.IO
{
@@ -26,13 +26,14 @@ namespace MediaBrowser.Server.Implementations.IO
private IServerConfigurationManager ConfigurationManager { get; set; }
private readonly IFileSystem _fileSystem;
private readonly List<string> _affectedPaths = new List<string>();
- private Timer _timer;
+ private ITimer _timer;
+ private readonly ITimerFactory _timerFactory;
private readonly object _timerLock = new object();
public string Path { get; private set; }
public event EventHandler<EventArgs> Completed;
- public FileRefresher(string path, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ITaskManager taskManager, ILogger logger)
+ public FileRefresher(string path, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ITaskManager taskManager, ILogger logger, ITimerFactory timerFactory)
{
logger.Debug("New file refresher created for {0}", path);
Path = path;
@@ -42,6 +43,7 @@ namespace MediaBrowser.Server.Implementations.IO
LibraryManager = libraryManager;
TaskManager = taskManager;
Logger = logger;
+ _timerFactory = timerFactory;
AddPath(path);
}
@@ -88,7 +90,7 @@ namespace MediaBrowser.Server.Implementations.IO
if (_timer == null)
{
- _timer = new Timer(OnTimerCallback, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
+ _timer = _timerFactory.Create(OnTimerCallback, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
}
else
{
@@ -163,7 +165,7 @@ namespace MediaBrowser.Server.Implementations.IO
// If the root folder changed, run the library task so the user can see it
if (itemsToRefresh.Any(i => i is AggregateFolder))
{
- TaskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
+ LibraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
return;
}
@@ -268,11 +270,11 @@ namespace MediaBrowser.Server.Implementations.IO
return false;
}
}
- catch (DirectoryNotFoundException)
- {
- // File may have been deleted
- return false;
- }
+ //catch (DirectoryNotFoundException)
+ //{
+ // // File may have been deleted
+ // return false;
+ //}
catch (FileNotFoundException)
{
// File may have been deleted
diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
index 77981b528..1f2a6255e 100644
--- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
+++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
@@ -16,6 +16,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Controller;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Tasks;
+using MediaBrowser.Model.Threading;
namespace MediaBrowser.Server.Implementations.IO
{
@@ -136,12 +137,12 @@ namespace MediaBrowser.Server.Implementations.IO
private IServerConfigurationManager ConfigurationManager { get; set; }
private readonly IFileSystem _fileSystem;
- private readonly IServerApplicationHost _appHost;
+ private readonly ITimerFactory _timerFactory;
/// <summary>
/// Initializes a new instance of the <see cref="LibraryMonitor" /> class.
/// </summary>
- public LibraryMonitor(ILogManager logManager, ITaskManager taskManager, ILibraryManager libraryManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IServerApplicationHost appHost)
+ public LibraryMonitor(ILogManager logManager, ITaskManager taskManager, ILibraryManager libraryManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ITimerFactory timerFactory)
{
if (taskManager == null)
{
@@ -153,7 +154,7 @@ namespace MediaBrowser.Server.Implementations.IO
Logger = logManager.GetLogger(GetType().Name);
ConfigurationManager = configurationManager;
_fileSystem = fileSystem;
- _appHost = appHost;
+ _timerFactory = timerFactory;
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
}
@@ -528,7 +529,7 @@ namespace MediaBrowser.Server.Implementations.IO
}
}
- var newRefresher = new FileRefresher(path, _fileSystem, ConfigurationManager, LibraryManager, TaskManager, Logger);
+ var newRefresher = new FileRefresher(path, _fileSystem, ConfigurationManager, LibraryManager, TaskManager, Logger, _timerFactory);
newRefresher.Completed += NewRefresher_Completed;
_activeRefreshers.Add(newRefresher);
}
diff --git a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
deleted file mode 100644
index f20d87c4b..000000000
--- a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
+++ /dev/null
@@ -1,148 +0,0 @@
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- /// <summary>
- /// Provides the core resolver ignore rules
- /// </summary>
- public class CoreResolutionIgnoreRule : IResolverIgnoreRule
- {
- private readonly IFileSystem _fileSystem;
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// Any folder named in this list will be ignored - can be added to at runtime for extensibility
- /// </summary>
- public static readonly List<string> IgnoreFolders = new List<string>
- {
- "metadata",
- "ps3_update",
- "ps3_vprm",
- "extrafanart",
- "extrathumbs",
- ".actors",
- ".wd_tv",
-
- // Synology
- "@eaDir",
- "eaDir",
- "#recycle"
-
- };
-
- public CoreResolutionIgnoreRule(IFileSystem fileSystem, ILibraryManager libraryManager)
- {
- _fileSystem = fileSystem;
- _libraryManager = libraryManager;
- }
-
- /// <summary>
- /// Shoulds the ignore.
- /// </summary>
- /// <param name="fileInfo">The file information.</param>
- /// <param name="parent">The parent.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent)
- {
- var filename = fileInfo.Name;
- var isHidden = fileInfo.IsHidden;
- var path = fileInfo.FullName;
-
- // Handle mac .DS_Store
- // https://github.com/MediaBrowser/MediaBrowser/issues/427
- if (filename.IndexOf("._", StringComparison.OrdinalIgnoreCase) == 0)
- {
- return true;
- }
-
- // Ignore hidden files and folders
- if (isHidden)
- {
- if (parent == null)
- {
- var parentFolderName = Path.GetFileName(Path.GetDirectoryName(path));
-
- if (string.Equals(parentFolderName, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- if (string.Equals(parentFolderName, BaseItem.ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- }
-
- // Sometimes these are marked hidden
- if (_fileSystem.IsRootPath(path))
- {
- return false;
- }
-
- return true;
- }
-
- if (fileInfo.IsDirectory)
- {
- // Ignore any folders in our list
- if (IgnoreFolders.Contains(filename, StringComparer.OrdinalIgnoreCase))
- {
- return true;
- }
-
- if (parent != null)
- {
- // Ignore trailer folders but allow it at the collection level
- if (string.Equals(filename, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase) &&
- !(parent is AggregateFolder) && !(parent is UserRootFolder))
- {
- return true;
- }
-
- if (string.Equals(filename, BaseItem.ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- if (string.Equals(filename, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
- }
- else
- {
- if (parent != null)
- {
- // Don't resolve these into audio files
- if (string.Equals(_fileSystem.GetFileNameWithoutExtension(filename), BaseItem.ThemeSongFilename) && _libraryManager.IsAudioFile(filename))
- {
- return true;
- }
- }
-
- // Ignore samples
- var sampleFilename = " " + filename.Replace(".", " ", StringComparison.OrdinalIgnoreCase)
- .Replace("-", " ", StringComparison.OrdinalIgnoreCase)
- .Replace("_", " ", StringComparison.OrdinalIgnoreCase)
- .Replace("!", " ", StringComparison.OrdinalIgnoreCase);
-
- if (sampleFilename.IndexOf(" sample ", StringComparison.OrdinalIgnoreCase) != -1)
- {
- return true;
- }
- }
-
- return false;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
deleted file mode 100644
index 18feaa849..000000000
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ /dev/null
@@ -1,3067 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Progress;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Querying;
-using MediaBrowser.Naming.Audio;
-using MediaBrowser.Naming.Common;
-using MediaBrowser.Naming.TV;
-using MediaBrowser.Naming.Video;
-using MediaBrowser.Server.Implementations.Library.Validators;
-using MediaBrowser.Server.Implementations.Logging;
-using MediaBrowser.Server.Implementations.ScheduledTasks;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Model.Channels;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.Library;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Server.Implementations.Library.Resolvers;
-using SortOrder = MediaBrowser.Model.Entities.SortOrder;
-using VideoResolver = MediaBrowser.Naming.Video.VideoResolver;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- /// <summary>
- /// Class LibraryManager
- /// </summary>
- public class LibraryManager : ILibraryManager
- {
- /// <summary>
- /// Gets or sets the postscan tasks.
- /// </summary>
- /// <value>The postscan tasks.</value>
- private ILibraryPostScanTask[] PostscanTasks { get; set; }
-
- /// <summary>
- /// Gets the intro providers.
- /// </summary>
- /// <value>The intro providers.</value>
- private IIntroProvider[] IntroProviders { get; set; }
-
- /// <summary>
- /// Gets the list of entity resolution ignore rules
- /// </summary>
- /// <value>The entity resolution ignore rules.</value>
- private IResolverIgnoreRule[] EntityResolutionIgnoreRules { get; set; }
-
- /// <summary>
- /// Gets the list of BasePluginFolders added by plugins
- /// </summary>
- /// <value>The plugin folders.</value>
- private IVirtualFolderCreator[] PluginFolderCreators { get; set; }
-
- /// <summary>
- /// Gets the list of currently registered entity resolvers
- /// </summary>
- /// <value>The entity resolvers enumerable.</value>
- private IItemResolver[] EntityResolvers { get; set; }
- private IMultiItemResolver[] MultiItemResolvers { get; set; }
-
- /// <summary>
- /// Gets or sets the comparers.
- /// </summary>
- /// <value>The comparers.</value>
- private IBaseItemComparer[] Comparers { get; set; }
-
- /// <summary>
- /// Gets the active item repository
- /// </summary>
- /// <value>The item repository.</value>
- public IItemRepository ItemRepository { get; set; }
-
- /// <summary>
- /// Occurs when [item added].
- /// </summary>
- public event EventHandler<ItemChangeEventArgs> ItemAdded;
-
- /// <summary>
- /// Occurs when [item updated].
- /// </summary>
- public event EventHandler<ItemChangeEventArgs> ItemUpdated;
-
- /// <summary>
- /// Occurs when [item removed].
- /// </summary>
- public event EventHandler<ItemChangeEventArgs> ItemRemoved;
-
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
-
- /// <summary>
- /// The _task manager
- /// </summary>
- private readonly ITaskManager _taskManager;
-
- /// <summary>
- /// The _user manager
- /// </summary>
- private readonly IUserManager _userManager;
-
- /// <summary>
- /// The _user data repository
- /// </summary>
- private readonly IUserDataManager _userDataRepository;
-
- /// <summary>
- /// Gets or sets the configuration manager.
- /// </summary>
- /// <value>The configuration manager.</value>
- private IServerConfigurationManager ConfigurationManager { get; set; }
-
- /// <summary>
- /// A collection of items that may be referenced from multiple physical places in the library
- /// (typically, multiple user roots). We store them here and be sure they all reference a
- /// single instance.
- /// </summary>
- /// <value>The by reference items.</value>
- private ConcurrentDictionary<Guid, BaseItem> ByReferenceItems { get; set; }
-
- private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
- private readonly Func<IProviderManager> _providerManagerFactory;
- private readonly Func<IUserViewManager> _userviewManager;
- public bool IsScanRunning { get; private set; }
-
- /// <summary>
- /// The _library items cache
- /// </summary>
- private readonly ConcurrentDictionary<Guid, BaseItem> _libraryItemsCache;
- /// <summary>
- /// Gets the library items cache.
- /// </summary>
- /// <value>The library items cache.</value>
- private ConcurrentDictionary<Guid, BaseItem> LibraryItemsCache
- {
- get
- {
- return _libraryItemsCache;
- }
- }
-
- private readonly IFileSystem _fileSystem;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="LibraryManager" /> class.
- /// </summary>
- /// <param name="logger">The logger.</param>
- /// <param name="taskManager">The task manager.</param>
- /// <param name="userManager">The user manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="userDataRepository">The user data repository.</param>
- public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager, IUserDataManager userDataRepository, Func<ILibraryMonitor> libraryMonitorFactory, IFileSystem fileSystem, Func<IProviderManager> providerManagerFactory, Func<IUserViewManager> userviewManager)
- {
- _logger = logger;
- _taskManager = taskManager;
- _userManager = userManager;
- ConfigurationManager = configurationManager;
- _userDataRepository = userDataRepository;
- _libraryMonitorFactory = libraryMonitorFactory;
- _fileSystem = fileSystem;
- _providerManagerFactory = providerManagerFactory;
- _userviewManager = userviewManager;
- ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>();
- _libraryItemsCache = new ConcurrentDictionary<Guid, BaseItem>();
-
- ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated;
-
- RecordConfigurationValues(configurationManager.Configuration);
- }
-
- /// <summary>
- /// Adds the parts.
- /// </summary>
- /// <param name="rules">The rules.</param>
- /// <param name="pluginFolders">The plugin folders.</param>
- /// <param name="resolvers">The resolvers.</param>
- /// <param name="introProviders">The intro providers.</param>
- /// <param name="itemComparers">The item comparers.</param>
- /// <param name="postscanTasks">The postscan tasks.</param>
- public void AddParts(IEnumerable<IResolverIgnoreRule> rules,
- IEnumerable<IVirtualFolderCreator> pluginFolders,
- IEnumerable<IItemResolver> resolvers,
- IEnumerable<IIntroProvider> introProviders,
- IEnumerable<IBaseItemComparer> itemComparers,
- IEnumerable<ILibraryPostScanTask> postscanTasks)
- {
- EntityResolutionIgnoreRules = rules.ToArray();
- PluginFolderCreators = pluginFolders.ToArray();
- EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray();
- MultiItemResolvers = EntityResolvers.OfType<IMultiItemResolver>().ToArray();
- IntroProviders = introProviders.ToArray();
- Comparers = itemComparers.ToArray();
-
- PostscanTasks = postscanTasks.OrderBy(i =>
- {
- var hasOrder = i as IHasOrder;
-
- return hasOrder == null ? 0 : hasOrder.Order;
-
- }).ToArray();
- }
-
- /// <summary>
- /// The _root folder
- /// </summary>
- private volatile AggregateFolder _rootFolder;
- /// <summary>
- /// The _root folder sync lock
- /// </summary>
- private readonly object _rootFolderSyncLock = new object();
- /// <summary>
- /// Gets the root folder.
- /// </summary>
- /// <value>The root folder.</value>
- public AggregateFolder RootFolder
- {
- get
- {
- if (_rootFolder == null)
- {
- lock (_rootFolderSyncLock)
- {
- if (_rootFolder == null)
- {
- _rootFolder = CreateRootFolder();
- }
- }
- }
- return _rootFolder;
- }
- }
-
- /// <summary>
- /// The _season zero display name
- /// </summary>
- private string _seasonZeroDisplayName;
-
- private bool _wizardCompleted;
- /// <summary>
- /// Records the configuration values.
- /// </summary>
- /// <param name="configuration">The configuration.</param>
- private void RecordConfigurationValues(ServerConfiguration configuration)
- {
- _seasonZeroDisplayName = configuration.SeasonZeroDisplayName;
- _wizardCompleted = configuration.IsStartupWizardCompleted;
- }
-
- /// <summary>
- /// Configurations the updated.
- /// </summary>
- /// <param name="sender">The sender.</param>
- /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
- void ConfigurationUpdated(object sender, EventArgs e)
- {
- var config = ConfigurationManager.Configuration;
-
- var newSeasonZeroName = ConfigurationManager.Configuration.SeasonZeroDisplayName;
- var seasonZeroNameChanged = !string.Equals(_seasonZeroDisplayName, newSeasonZeroName, StringComparison.Ordinal);
- var wizardChanged = config.IsStartupWizardCompleted != _wizardCompleted;
-
- RecordConfigurationValues(config);
-
- if (seasonZeroNameChanged || wizardChanged)
- {
- _taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
- }
-
- if (seasonZeroNameChanged)
- {
- Task.Run(async () =>
- {
- await UpdateSeasonZeroNames(newSeasonZeroName, CancellationToken.None).ConfigureAwait(false);
-
- });
- }
- }
-
- /// <summary>
- /// Updates the season zero names.
- /// </summary>
- /// <param name="newName">The new name.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task UpdateSeasonZeroNames(string newName, CancellationToken cancellationToken)
- {
- var seasons = GetItemList(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(Season).Name },
- Recursive = true,
- IndexNumber = 0
-
- }).Cast<Season>()
- .Where(i => !string.Equals(i.Name, newName, StringComparison.Ordinal))
- .ToList();
-
- foreach (var season in seasons)
- {
- season.Name = newName;
-
- try
- {
- await UpdateItem(season, ItemUpdateType.MetadataDownload, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving {0}", ex, season.Path);
- }
- }
- }
-
- public void RegisterItem(BaseItem item)
- {
- if (item == null)
- {
- throw new ArgumentNullException("item");
- }
- RegisterItem(item.Id, item);
- }
-
- private void RegisterItem(Guid id, BaseItem item)
- {
- if (item is IItemByName)
- {
- if (!(item is MusicArtist))
- {
- return;
- }
- }
-
- if (item.IsFolder)
- {
- if (!(item is ICollectionFolder) && !(item is UserView) && !(item is Channel) && !(item is AggregateFolder))
- {
- if (item.SourceType != SourceType.Library)
- {
- return;
- }
- }
- }
- else
- {
- if (item is Photo)
- {
- return;
- }
- }
-
- LibraryItemsCache.AddOrUpdate(id, item, delegate { return item; });
- }
-
- public async Task DeleteItem(BaseItem item, DeleteOptions options)
- {
- if (item == null)
- {
- throw new ArgumentNullException("item");
- }
-
- _logger.Debug("Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}",
- item.GetType().Name,
- item.Name ?? "Unknown name",
- item.Path ?? string.Empty,
- item.Id);
-
- var parent = item.Parent;
-
- var locationType = item.LocationType;
-
- var children = item.IsFolder
- ? ((Folder)item).GetRecursiveChildren(false).ToList()
- : new List<BaseItem>();
-
- foreach (var metadataPath in GetMetadataPaths(item, children))
- {
- _logger.Debug("Deleting path {0}", metadataPath);
-
- try
- {
- _fileSystem.DeleteDirectory(metadataPath, true);
- }
- catch (DirectoryNotFoundException)
- {
-
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error deleting {0}", ex, metadataPath);
- }
- }
-
- if (options.DeleteFileLocation && locationType != LocationType.Remote && locationType != LocationType.Virtual)
- {
- foreach (var path in item.GetDeletePaths().ToList())
- {
- if (_fileSystem.DirectoryExists(path))
- {
- _logger.Debug("Deleting path {0}", path);
- _fileSystem.DeleteDirectory(path, true);
- }
- else if (_fileSystem.FileExists(path))
- {
- _logger.Debug("Deleting path {0}", path);
- _fileSystem.DeleteFile(path);
- }
- }
-
- if (parent != null)
- {
- await parent.ValidateChildren(new Progress<double>(), CancellationToken.None)
- .ConfigureAwait(false);
- }
- }
- else if (parent != null)
- {
- parent.RemoveChild(item);
- }
-
- await ItemRepository.DeleteItem(item.Id, CancellationToken.None).ConfigureAwait(false);
- foreach (var child in children)
- {
- await ItemRepository.DeleteItem(child.Id, CancellationToken.None).ConfigureAwait(false);
- }
-
- BaseItem removed;
- _libraryItemsCache.TryRemove(item.Id, out removed);
-
- ReportItemRemoved(item);
- }
-
- private IEnumerable<string> GetMetadataPaths(BaseItem item, IEnumerable<BaseItem> children)
- {
- var list = new List<string>
- {
- item.GetInternalMetadataPath()
- };
-
- list.AddRange(children.Select(i => i.GetInternalMetadataPath()));
-
- return list;
- }
-
- /// <summary>
- /// Resolves the item.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <param name="resolvers">The resolvers.</param>
- /// <returns>BaseItem.</returns>
- private BaseItem ResolveItem(ItemResolveArgs args, IItemResolver[] resolvers)
- {
- var item = (resolvers ?? EntityResolvers).Select(r => Resolve(args, r))
- .FirstOrDefault(i => i != null);
-
- if (item != null)
- {
- ResolverHelper.SetInitialItemValues(item, args, _fileSystem, this);
- }
-
- return item;
- }
-
- private BaseItem Resolve(ItemResolveArgs args, IItemResolver resolver)
- {
- try
- {
- return resolver.ResolvePath(args);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in {0} resolving {1}", ex, resolver.GetType().Name, args.Path);
- return null;
- }
- }
-
- public Guid GetNewItemId(string key, Type type)
- {
- if (string.IsNullOrWhiteSpace(key))
- {
- throw new ArgumentNullException("key");
- }
- if (type == null)
- {
- throw new ArgumentNullException("type");
- }
-
- if (ConfigurationManager.Configuration.EnableLocalizedGuids && key.StartsWith(ConfigurationManager.ApplicationPaths.ProgramDataPath))
- {
- // Try to normalize paths located underneath program-data in an attempt to make them more portable
- key = key.Substring(ConfigurationManager.ApplicationPaths.ProgramDataPath.Length)
- .TrimStart(new[] { '/', '\\' })
- .Replace("/", "\\");
- }
-
- if (!ConfigurationManager.Configuration.EnableCaseSensitiveItemIds)
- {
- key = key.ToLower();
- }
-
- key = type.FullName + key;
-
- return key.GetMD5();
- }
-
- /// <summary>
- /// Ensure supplied item has only one instance throughout
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>The proper instance to the item</returns>
- public BaseItem GetOrAddByReferenceItem(BaseItem item)
- {
- // Add this item to our list if not there already
- if (!ByReferenceItems.TryAdd(item.Id, item))
- {
- // Already there - return the existing reference
- item = ByReferenceItems[item.Id];
- }
- return item;
- }
-
- public BaseItem ResolvePath(FileSystemMetadata fileInfo,
- Folder parent = null)
- {
- return ResolvePath(fileInfo, new DirectoryService(_logger, _fileSystem), null, parent);
- }
-
- private BaseItem ResolvePath(FileSystemMetadata fileInfo,
- IDirectoryService directoryService,
- IItemResolver[] resolvers,
- Folder parent = null,
- string collectionType = null,
- LibraryOptions libraryOptions = null)
- {
- if (fileInfo == null)
- {
- throw new ArgumentNullException("fileInfo");
- }
-
- var fullPath = fileInfo.FullName;
-
- if (string.IsNullOrWhiteSpace(collectionType) && parent != null)
- {
- collectionType = GetContentTypeOverride(fullPath, true);
- }
-
- var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
- {
- Parent = parent,
- Path = fullPath,
- FileInfo = fileInfo,
- CollectionType = collectionType,
- LibraryOptions = libraryOptions
- };
-
- // Return null if ignore rules deem that we should do so
- if (IgnoreFile(args.FileInfo, args.Parent))
- {
- return null;
- }
-
- // Gather child folder and files
- if (args.IsDirectory)
- {
- var isPhysicalRoot = args.IsPhysicalRoot;
-
- // When resolving the root, we need it's grandchildren (children of user views)
- var flattenFolderDepth = isPhysicalRoot ? 2 : 0;
-
- var fileSystemDictionary = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, _fileSystem, _logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
-
- // Need to remove subpaths that may have been resolved from shortcuts
- // Example: if \\server\movies exists, then strip out \\server\movies\action
- if (isPhysicalRoot)
- {
- var paths = NormalizeRootPathList(fileSystemDictionary.Values);
-
- fileSystemDictionary = paths.ToDictionary(i => i.FullName);
- }
-
- args.FileSystemDictionary = fileSystemDictionary;
- }
-
- // Check to see if we should resolve based on our contents
- if (args.IsDirectory && !ShouldResolvePathContents(args))
- {
- return null;
- }
-
- return ResolveItem(args, resolvers);
- }
-
- private readonly List<string> _ignoredPaths = new List<string>();
-
- public void RegisterIgnoredPath(string path)
- {
- lock (_ignoredPaths)
- {
- _ignoredPaths.Add(path);
- }
- }
- public void UnRegisterIgnoredPath(string path)
- {
- lock (_ignoredPaths)
- {
- _ignoredPaths.Remove(path);
- }
- }
-
- public bool IgnoreFile(FileSystemMetadata file, BaseItem parent)
- {
- if (EntityResolutionIgnoreRules.Any(r => r.ShouldIgnore(file, parent)))
- {
- return true;
- }
-
- //lock (_ignoredPaths)
- {
- if (_ignoredPaths.Contains(file.FullName, StringComparer.OrdinalIgnoreCase))
- {
- return true;
- }
- }
- return false;
- }
-
- public IEnumerable<FileSystemMetadata> NormalizeRootPathList(IEnumerable<FileSystemMetadata> paths)
- {
- var originalList = paths.ToList();
-
- var list = originalList.Where(i => i.IsDirectory)
- .Select(i => _fileSystem.NormalizePath(i.FullName))
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
-
- var dupes = list.Where(subPath => !subPath.EndsWith(":\\", StringComparison.OrdinalIgnoreCase) && list.Any(i => _fileSystem.ContainsSubPath(i, subPath)))
- .ToList();
-
- foreach (var dupe in dupes)
- {
- _logger.Info("Found duplicate path: {0}", dupe);
- }
-
- var newList = list.Except(dupes, StringComparer.OrdinalIgnoreCase).Select(_fileSystem.GetDirectoryInfo).ToList();
- newList.AddRange(originalList.Where(i => !i.IsDirectory));
- return newList;
- }
-
- /// <summary>
- /// Determines whether a path should be ignored based on its contents - called after the contents have been read
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private static bool ShouldResolvePathContents(ItemResolveArgs args)
- {
- // Ignore any folders containing a file called .ignore
- return !args.ContainsFileSystemEntryByName(".ignore");
- }
-
- public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files, IDirectoryService directoryService, Folder parent, LibraryOptions libraryOptions, string collectionType)
- {
- return ResolvePaths(files, directoryService, parent, libraryOptions, collectionType, EntityResolvers);
- }
-
- public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files,
- IDirectoryService directoryService,
- Folder parent,
- LibraryOptions libraryOptions,
- string collectionType,
- IItemResolver[] resolvers)
- {
- var fileList = files.Where(i => !IgnoreFile(i, parent)).ToList();
-
- if (parent != null)
- {
- var multiItemResolvers = resolvers == null ? MultiItemResolvers : resolvers.OfType<IMultiItemResolver>().ToArray();
-
- foreach (var resolver in multiItemResolvers)
- {
- var result = resolver.ResolveMultiple(parent, fileList, collectionType, directoryService);
-
- if (result != null && result.Items.Count > 0)
- {
- var items = new List<BaseItem>();
- items.AddRange(result.Items);
-
- foreach (var item in items)
- {
- ResolverHelper.SetInitialItemValues(item, parent, _fileSystem, this, directoryService);
- }
- items.AddRange(ResolveFileList(result.ExtraFiles, directoryService, parent, collectionType, resolvers, libraryOptions));
- return items;
- }
- }
- }
-
- return ResolveFileList(fileList, directoryService, parent, collectionType, resolvers, libraryOptions);
- }
-
- private IEnumerable<BaseItem> ResolveFileList(IEnumerable<FileSystemMetadata> fileList,
- IDirectoryService directoryService,
- Folder parent,
- string collectionType,
- IItemResolver[] resolvers,
- LibraryOptions libraryOptions)
- {
- return fileList.Select(f =>
- {
- try
- {
- return ResolvePath(f, directoryService, resolvers, parent, collectionType, libraryOptions);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error resolving path {0}", ex, f.FullName);
- return null;
- }
- }).Where(i => i != null);
- }
-
- /// <summary>
- /// Creates the root media folder
- /// </summary>
- /// <returns>AggregateFolder.</returns>
- /// <exception cref="System.InvalidOperationException">Cannot create the root folder until plugins have loaded</exception>
- public AggregateFolder CreateRootFolder()
- {
- var rootFolderPath = ConfigurationManager.ApplicationPaths.RootFolderPath;
-
- _fileSystem.CreateDirectory(rootFolderPath);
-
- var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath));
-
- // Add in the plug-in folders
- foreach (var child in PluginFolderCreators)
- {
- var folder = child.GetFolder();
-
- if (folder != null)
- {
- if (folder.Id == Guid.Empty)
- {
- if (string.IsNullOrWhiteSpace(folder.Path))
- {
- folder.Id = GetNewItemId(folder.GetType().Name, folder.GetType());
- }
- else
- {
- folder.Id = GetNewItemId(folder.Path, folder.GetType());
- }
- }
-
- var dbItem = GetItemById(folder.Id) as BasePluginFolder;
-
- if (dbItem != null && string.Equals(dbItem.Path, folder.Path, StringComparison.OrdinalIgnoreCase))
- {
- folder = dbItem;
- }
-
- if (folder.ParentId != rootFolder.Id)
- {
- folder.ParentId = rootFolder.Id;
- var task = folder.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None);
- Task.WaitAll(task);
- }
-
- rootFolder.AddVirtualChild(folder);
-
- RegisterItem(folder);
- }
- }
-
- return rootFolder;
- }
-
- private volatile UserRootFolder _userRootFolder;
- private readonly object _syncLock = new object();
- public Folder GetUserRootFolder()
- {
- if (_userRootFolder == null)
- {
- lock (_syncLock)
- {
- if (_userRootFolder == null)
- {
- var userRootPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
-
- _fileSystem.CreateDirectory(userRootPath);
-
- var tmpItem = GetItemById(GetNewItemId(userRootPath, typeof(UserRootFolder))) as UserRootFolder;
-
- if (tmpItem == null)
- {
- tmpItem = (UserRootFolder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath));
- }
-
- _userRootFolder = tmpItem;
- }
- }
- }
-
- return _userRootFolder;
- }
-
- public BaseItem FindByPath(string path, bool? isFolder)
- {
- // If this returns multiple items it could be tricky figuring out which one is correct.
- // In most cases, the newest one will be and the others obsolete but not yet cleaned up
-
- var query = new InternalItemsQuery
- {
- Path = path,
- IsFolder = isFolder,
- SortBy = new[] { ItemSortBy.DateCreated },
- SortOrder = SortOrder.Descending,
- Limit = 1
- };
-
- return GetItemList(query)
- .FirstOrDefault();
- }
-
- /// <summary>
- /// Gets a Person
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{Person}.</returns>
- public Person GetPerson(string name)
- {
- return CreateItemByName<Person>(Person.GetPath(name), name);
- }
-
- /// <summary>
- /// Gets a Studio
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{Studio}.</returns>
- public Studio GetStudio(string name)
- {
- return CreateItemByName<Studio>(Studio.GetPath(name), name);
- }
-
- /// <summary>
- /// Gets a Genre
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{Genre}.</returns>
- public Genre GetGenre(string name)
- {
- return CreateItemByName<Genre>(Genre.GetPath(name), name);
- }
-
- /// <summary>
- /// Gets the genre.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{MusicGenre}.</returns>
- public MusicGenre GetMusicGenre(string name)
- {
- return CreateItemByName<MusicGenre>(MusicGenre.GetPath(name), name);
- }
-
- /// <summary>
- /// Gets the game genre.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{GameGenre}.</returns>
- public GameGenre GetGameGenre(string name)
- {
- return CreateItemByName<GameGenre>(GameGenre.GetPath(name), name);
- }
-
- /// <summary>
- /// Gets a Year
- /// </summary>
- /// <param name="value">The value.</param>
- /// <returns>Task{Year}.</returns>
- /// <exception cref="System.ArgumentOutOfRangeException"></exception>
- public Year GetYear(int value)
- {
- if (value <= 0)
- {
- throw new ArgumentOutOfRangeException("Years less than or equal to 0 are invalid.");
- }
-
- var name = value.ToString(CultureInfo.InvariantCulture);
-
- return CreateItemByName<Year>(Year.GetPath(name), name);
- }
-
- /// <summary>
- /// Gets a Genre
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{Genre}.</returns>
- public MusicArtist GetArtist(string name)
- {
- return CreateItemByName<MusicArtist>(MusicArtist.GetPath(name), name);
- }
-
- private T CreateItemByName<T>(string path, string name)
- where T : BaseItem, new()
- {
- if (typeof(T) == typeof(MusicArtist))
- {
- var existing = GetItemList(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(T).Name },
- Name = name
-
- }).Cast<MusicArtist>()
- .OrderBy(i => i.IsAccessedByName ? 1 : 0)
- .Cast<T>()
- .FirstOrDefault();
-
- if (existing != null)
- {
- return existing;
- }
- }
-
- var id = GetNewItemId(path, typeof(T));
-
- var item = GetItemById(id) as T;
-
- if (item == null)
- {
- item = new T
- {
- Name = name,
- Id = id,
- DateCreated = DateTime.UtcNow,
- DateModified = DateTime.UtcNow,
- Path = path
- };
-
- var task = CreateItem(item, CancellationToken.None);
- Task.WaitAll(task);
- }
-
- return item;
- }
-
- public IEnumerable<MusicArtist> GetAlbumArtists(IEnumerable<IHasAlbumArtist> items)
- {
- var names = items
- .SelectMany(i => i.AlbumArtists)
- .DistinctNames()
- .Select(i =>
- {
- try
- {
- var artist = GetArtist(i);
-
- return artist;
- }
- catch
- {
- // Already logged at lower levels
- return null;
- }
- })
- .Where(i => i != null);
-
- return names;
- }
-
- public IEnumerable<MusicArtist> GetArtists(IEnumerable<IHasArtist> items)
- {
- var names = items
- .SelectMany(i => i.AllArtists)
- .DistinctNames()
- .Select(i =>
- {
- try
- {
- var artist = GetArtist(i);
-
- return artist;
- }
- catch
- {
- // Already logged at lower levels
- return null;
- }
- })
- .Where(i => i != null);
-
- return names;
- }
-
- /// <summary>
- /// Validate and refresh the People sub-set of the IBN.
- /// The items are stored in the db but not loaded into memory until actually requested by an operation.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
- {
- // Ensure the location is available.
- _fileSystem.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath);
-
- return new PeopleValidator(this, _logger, ConfigurationManager, _fileSystem).ValidatePeople(cancellationToken, progress);
- }
-
- /// <summary>
- /// Reloads the root media folder
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task ValidateMediaLibrary(IProgress<double> progress, CancellationToken cancellationToken)
- {
- // Just run the scheduled task so that the user can see it
- _taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
-
- return Task.FromResult(true);
- }
-
- /// <summary>
- /// Queues the library scan.
- /// </summary>
- public void QueueLibraryScan()
- {
- // Just run the scheduled task so that the user can see it
- _taskManager.QueueScheduledTask<RefreshMediaLibraryTask>();
- }
-
- /// <summary>
- /// Validates the media library internal.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task ValidateMediaLibraryInternal(IProgress<double> progress, CancellationToken cancellationToken)
- {
- IsScanRunning = true;
- _libraryMonitorFactory().Stop();
-
- try
- {
- await PerformLibraryValidation(progress, cancellationToken).ConfigureAwait(false);
- }
- finally
- {
- _libraryMonitorFactory().Start();
- IsScanRunning = false;
- }
- }
-
- private async Task PerformLibraryValidation(IProgress<double> progress, CancellationToken cancellationToken)
- {
- _logger.Info("Validating media library");
-
- await RootFolder.RefreshMetadata(cancellationToken).ConfigureAwait(false);
-
- progress.Report(.5);
-
- // Start by just validating the children of the root, but go no further
- await RootFolder.ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false);
-
- progress.Report(1);
-
- var userRoot = GetUserRootFolder();
-
- await userRoot.RefreshMetadata(cancellationToken).ConfigureAwait(false);
-
- await userRoot.ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false).ConfigureAwait(false);
- progress.Report(2);
-
- var innerProgress = new ActionableProgress<double>();
-
- innerProgress.RegisterAction(pct => progress.Report(2 + pct * .73));
-
- // Now validate the entire media library
- await RootFolder.ValidateChildren(innerProgress, cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: true).ConfigureAwait(false);
-
- progress.Report(75);
-
- innerProgress = new ActionableProgress<double>();
-
- innerProgress.RegisterAction(pct => progress.Report(75 + pct * .25));
-
- // Run post-scan tasks
- await RunPostScanTasks(innerProgress, cancellationToken).ConfigureAwait(false);
-
- progress.Report(100);
- }
-
- /// <summary>
- /// Runs the post scan tasks.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task RunPostScanTasks(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var tasks = PostscanTasks.ToList();
-
- var numComplete = 0;
- var numTasks = tasks.Count;
-
- foreach (var task in tasks)
- {
- var innerProgress = new ActionableProgress<double>();
-
- // Prevent access to modified closure
- var currentNumComplete = numComplete;
-
- innerProgress.RegisterAction(pct =>
- {
- double innerPercent = currentNumComplete * 100 + pct;
- innerPercent /= numTasks;
- progress.Report(innerPercent);
- });
-
- _logger.Debug("Running post-scan task {0}", task.GetType().Name);
-
- try
- {
- await task.Run(innerProgress, cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- _logger.Info("Post-scan task cancelled: {0}", task.GetType().Name);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error running postscan task", ex);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= numTasks;
- progress.Report(percent * 100);
- }
-
- progress.Report(100);
- }
-
- /// <summary>
- /// Gets the default view.
- /// </summary>
- /// <returns>IEnumerable{VirtualFolderInfo}.</returns>
- public IEnumerable<VirtualFolderInfo> GetVirtualFolders()
- {
- return GetView(ConfigurationManager.ApplicationPaths.DefaultUserViewsPath);
- }
-
- /// <summary>
- /// Gets the view.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>IEnumerable{VirtualFolderInfo}.</returns>
- private IEnumerable<VirtualFolderInfo> GetView(string path)
- {
- var topLibraryFolders = GetUserRootFolder().Children.ToList();
-
- return _fileSystem.GetDirectoryPaths(path)
- .Select(dir => GetVirtualFolderInfo(dir, topLibraryFolders));
- }
-
- private VirtualFolderInfo GetVirtualFolderInfo(string dir, List<BaseItem> allCollectionFolders)
- {
- var info = new VirtualFolderInfo
- {
- Name = Path.GetFileName(dir),
-
- Locations = Directory.EnumerateFiles(dir, "*.mblink", SearchOption.TopDirectoryOnly)
- .Select(_fileSystem.ResolveShortcut)
- .OrderBy(i => i)
- .ToList(),
-
- CollectionType = GetCollectionType(dir)
- };
-
- var libraryFolder = allCollectionFolders.FirstOrDefault(i => string.Equals(i.Path, dir, StringComparison.OrdinalIgnoreCase));
-
- if (libraryFolder != null && libraryFolder.HasImage(ImageType.Primary))
- {
- info.PrimaryImageItemId = libraryFolder.Id.ToString("N");
- }
-
- if (libraryFolder != null)
- {
- info.ItemId = libraryFolder.Id.ToString("N");
- info.LibraryOptions = GetLibraryOptions(libraryFolder);
- }
-
- return info;
- }
-
- private string GetCollectionType(string path)
- {
- return _fileSystem.GetFiles(path, false)
- .Where(i => string.Equals(i.Extension, ".collection", StringComparison.OrdinalIgnoreCase))
- .Select(i => _fileSystem.GetFileNameWithoutExtension(i))
- .FirstOrDefault();
- }
-
- /// <summary>
- /// Gets the item by id.
- /// </summary>
- /// <param name="id">The id.</param>
- /// <returns>BaseItem.</returns>
- /// <exception cref="System.ArgumentNullException">id</exception>
- public BaseItem GetItemById(Guid id)
- {
- if (id == Guid.Empty)
- {
- throw new ArgumentNullException("id");
- }
-
- BaseItem item;
-
- if (LibraryItemsCache.TryGetValue(id, out item))
- {
- return item;
- }
-
- item = RetrieveItem(id);
-
- //_logger.Debug("GetitemById {0}", id);
-
- if (item != null)
- {
- RegisterItem(item);
- }
-
- return item;
- }
-
- public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
- {
- if (query.Recursive && query.ParentId.HasValue)
- {
- var parent = GetItemById(query.ParentId.Value);
- if (parent != null)
- {
- SetTopParentIdsOrAncestors(query, new List<BaseItem> { parent });
- query.ParentId = null;
- }
- }
-
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- return ItemRepository.GetItemList(query);
- }
-
- public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, IEnumerable<string> parentIds)
- {
- var parents = parentIds.Select(i => GetItemById(new Guid(i))).Where(i => i != null).ToList();
-
- SetTopParentIdsOrAncestors(query, parents);
-
- if (query.AncestorIds.Length == 0 && query.TopParentIds.Length == 0)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
- }
-
- return ItemRepository.GetItemList(query);
- }
-
- public QueryResult<BaseItem> QueryItems(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- if (query.EnableTotalRecordCount)
- {
- return ItemRepository.GetItems(query);
- }
-
- return new QueryResult<BaseItem>
- {
- Items = ItemRepository.GetItemList(query).ToArray()
- };
- }
-
- public List<Guid> GetItemIds(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- return ItemRepository.GetItemIdsList(query);
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetStudios(query);
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetGenres(query);
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetGameGenres(query);
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetMusicGenres(query);
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetAllArtists(query);
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetArtists(query);
- }
-
- private void SetTopParentOrAncestorIds(InternalItemsQuery query)
- {
- if (query.AncestorIds.Length == 0)
- {
- return;
- }
-
- var parents = query.AncestorIds.Select(i => GetItemById(new Guid(i))).ToList();
-
- if (parents.All(i =>
- {
- if (i is ICollectionFolder || i is UserView)
- {
- return true;
- }
-
- //_logger.Debug("Query requires ancestor query due to type: " + i.GetType().Name);
- return false;
-
- }))
- {
- // Optimize by querying against top level views
- query.TopParentIds = parents.SelectMany(i => GetTopParentsForQuery(i, query.User)).Select(i => i.Id.ToString("N")).ToArray();
- query.AncestorIds = new string[] { };
- }
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetAlbumArtists(query);
- }
-
- public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query)
- {
- if (query.Recursive && query.ParentId.HasValue)
- {
- var parent = GetItemById(query.ParentId.Value);
- if (parent != null)
- {
- SetTopParentIdsOrAncestors(query, new List<BaseItem> { parent });
- query.ParentId = null;
- }
- }
-
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- if (query.EnableTotalRecordCount)
- {
- return ItemRepository.GetItems(query);
- }
-
- return new QueryResult<BaseItem>
- {
- Items = ItemRepository.GetItemList(query).ToArray()
- };
- }
-
- private void SetTopParentIdsOrAncestors(InternalItemsQuery query, List<BaseItem> parents)
- {
- if (parents.All(i =>
- {
- if (i is ICollectionFolder || i is UserView)
- {
- return true;
- }
-
- //_logger.Debug("Query requires ancestor query due to type: " + i.GetType().Name);
- return false;
-
- }))
- {
- // Optimize by querying against top level views
- query.TopParentIds = parents.SelectMany(i => GetTopParentsForQuery(i, query.User)).Select(i => i.Id.ToString("N")).ToArray();
- }
- else
- {
- // We need to be able to query from any arbitrary ancestor up the tree
- query.AncestorIds = parents.SelectMany(i => i.GetIdsForAncestorQuery()).Select(i => i.ToString("N")).ToArray();
- }
- }
-
- private void AddUserToQuery(InternalItemsQuery query, User user)
- {
- if (query.AncestorIds.Length == 0 &&
- !query.ParentId.HasValue &&
- query.ChannelIds.Length == 0 &&
- query.TopParentIds.Length == 0 &&
- string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey)
- && query.ItemIds.Length == 0)
- {
- var userViews = _userviewManager().GetUserViews(new UserViewQuery
- {
- UserId = user.Id.ToString("N"),
- IncludeHidden = true
-
- }, CancellationToken.None).Result.ToList();
-
- query.TopParentIds = userViews.SelectMany(i => GetTopParentsForQuery(i, user)).Select(i => i.Id.ToString("N")).ToArray();
- }
- }
-
- private IEnumerable<BaseItem> GetTopParentsForQuery(BaseItem item, User user)
- {
- var view = item as UserView;
-
- if (view != null)
- {
- if (string.Equals(view.ViewType, CollectionType.LiveTv))
- {
- return new[] { view };
- }
- if (string.Equals(view.ViewType, CollectionType.Channels))
- {
- var channelResult = BaseItem.ChannelManager.GetChannelsInternal(new ChannelQuery
- {
- UserId = user.Id.ToString("N")
-
- }, CancellationToken.None).Result;
-
- return channelResult.Items;
- }
-
- // Translate view into folders
- if (view.DisplayParentId != Guid.Empty)
- {
- var displayParent = GetItemById(view.DisplayParentId);
- if (displayParent != null)
- {
- return GetTopParentsForQuery(displayParent, user);
- }
- return new BaseItem[] { };
- }
- if (view.ParentId != Guid.Empty)
- {
- var displayParent = GetItemById(view.ParentId);
- if (displayParent != null)
- {
- return GetTopParentsForQuery(displayParent, user);
- }
- return new BaseItem[] { };
- }
-
- // Handle grouping
- if (user != null && !string.IsNullOrWhiteSpace(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType))
- {
- 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[] { };
- }
-
- var collectionFolder = item as CollectionFolder;
- if (collectionFolder != null)
- {
- return collectionFolder.GetPhysicalParents();
- }
-
- var topParent = item.GetTopParent();
- if (topParent != null)
- {
- return new[] { topParent };
- }
- return new BaseItem[] { };
- }
-
- /// <summary>
- /// Gets the intros.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="user">The user.</param>
- /// <returns>IEnumerable{System.String}.</returns>
- public async Task<IEnumerable<Video>> GetIntros(BaseItem item, User user)
- {
- var tasks = IntroProviders
- .OrderBy(i => i.GetType().Name.IndexOf("Default", StringComparison.OrdinalIgnoreCase) == -1 ? 0 : 1)
- .Take(1)
- .Select(i => GetIntros(i, item, user));
-
- var items = await Task.WhenAll(tasks).ConfigureAwait(false);
-
- return items
- .SelectMany(i => i.ToArray())
- .Select(ResolveIntro)
- .Where(i => i != null);
- }
-
- /// <summary>
- /// Gets the intros.
- /// </summary>
- /// <param name="provider">The provider.</param>
- /// <param name="item">The item.</param>
- /// <param name="user">The user.</param>
- /// <returns>Task&lt;IEnumerable&lt;IntroInfo&gt;&gt;.</returns>
- private async Task<IEnumerable<IntroInfo>> GetIntros(IIntroProvider provider, BaseItem item, User user)
- {
- try
- {
- return await provider.GetIntros(item, user).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting intros", ex);
-
- return new List<IntroInfo>();
- }
- }
-
- /// <summary>
- /// Gets all intro files.
- /// </summary>
- /// <returns>IEnumerable{System.String}.</returns>
- public IEnumerable<string> GetAllIntroFiles()
- {
- return IntroProviders.SelectMany(i =>
- {
- try
- {
- return i.GetAllIntroFiles().ToList();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting intro files", ex);
-
- return new List<string>();
- }
- });
- }
-
- /// <summary>
- /// Resolves the intro.
- /// </summary>
- /// <param name="info">The info.</param>
- /// <returns>Video.</returns>
- private Video ResolveIntro(IntroInfo info)
- {
- Video video = null;
-
- if (info.ItemId.HasValue)
- {
- // Get an existing item by Id
- video = GetItemById(info.ItemId.Value) as Video;
-
- if (video == null)
- {
- _logger.Error("Unable to locate item with Id {0}.", info.ItemId.Value);
- }
- }
- else if (!string.IsNullOrEmpty(info.Path))
- {
- try
- {
- // Try to resolve the path into a video
- video = ResolvePath(_fileSystem.GetFileSystemInfo(info.Path)) as Video;
-
- if (video == null)
- {
- _logger.Error("Intro resolver returned null for {0}.", info.Path);
- }
- else
- {
- // Pull the saved db item that will include metadata
- var dbItem = GetItemById(video.Id) as Video;
-
- if (dbItem != null)
- {
- video = dbItem;
- }
- else
- {
- return null;
- }
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error resolving path {0}.", ex, info.Path);
- }
- }
- else
- {
- _logger.Error("IntroProvider returned an IntroInfo with null Path and ItemId.");
- }
-
- return video;
- }
-
- /// <summary>
- /// Sorts the specified sort by.
- /// </summary>
- /// <param name="items">The items.</param>
- /// <param name="user">The user.</param>
- /// <param name="sortBy">The sort by.</param>
- /// <param name="sortOrder">The sort order.</param>
- /// <returns>IEnumerable{BaseItem}.</returns>
- public IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<string> sortBy, SortOrder sortOrder)
- {
- var isFirst = true;
-
- IOrderedEnumerable<BaseItem> orderedItems = null;
-
- foreach (var orderBy in sortBy.Select(o => GetComparer(o, user)).Where(c => c != null))
- {
- if (isFirst)
- {
- orderedItems = sortOrder == SortOrder.Descending ? items.OrderByDescending(i => i, orderBy) : items.OrderBy(i => i, orderBy);
- }
- else
- {
- orderedItems = sortOrder == SortOrder.Descending ? orderedItems.ThenByDescending(i => i, orderBy) : orderedItems.ThenBy(i => i, orderBy);
- }
-
- isFirst = false;
- }
-
- return orderedItems ?? items;
- }
-
- /// <summary>
- /// Gets the comparer.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="user">The user.</param>
- /// <returns>IBaseItemComparer.</returns>
- private IBaseItemComparer GetComparer(string name, User user)
- {
- var comparer = Comparers.FirstOrDefault(c => string.Equals(name, c.Name, StringComparison.OrdinalIgnoreCase));
-
- if (comparer != null)
- {
- // If it requires a user, create a new one, and assign the user
- if (comparer is IUserBaseItemComparer)
- {
- var userComparer = (IUserBaseItemComparer)Activator.CreateInstance(comparer.GetType());
-
- userComparer.User = user;
- userComparer.UserManager = _userManager;
- userComparer.UserDataRepository = _userDataRepository;
-
- return userComparer;
- }
- }
-
- return comparer;
- }
-
- /// <summary>
- /// Creates the item.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task CreateItem(BaseItem item, CancellationToken cancellationToken)
- {
- return CreateItems(new[] { item }, cancellationToken);
- }
-
- /// <summary>
- /// Creates the items.
- /// </summary>
- /// <param name="items">The items.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task CreateItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken)
- {
- var list = items.ToList();
-
- await ItemRepository.SaveItems(list, cancellationToken).ConfigureAwait(false);
-
- foreach (var item in list)
- {
- RegisterItem(item);
- }
-
- if (ItemAdded != null)
- {
- foreach (var item in list)
- {
- try
- {
- ItemAdded(this, new ItemChangeEventArgs { Item = item });
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in ItemAdded event handler", ex);
- }
- }
- }
- }
-
- /// <summary>
- /// Updates the item.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="updateReason">The update reason.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task UpdateItem(BaseItem item, ItemUpdateType updateReason, CancellationToken cancellationToken)
- {
- var locationType = item.LocationType;
- if (locationType != LocationType.Remote && locationType != LocationType.Virtual)
- {
- await _providerManagerFactory().SaveMetadata(item, updateReason).ConfigureAwait(false);
- }
-
- item.DateLastSaved = DateTime.UtcNow;
-
- var logName = item.LocationType == LocationType.Remote ? item.Name ?? item.Path : item.Path ?? item.Name;
- _logger.Debug("Saving {0} to database.", logName);
-
- await ItemRepository.SaveItem(item, cancellationToken).ConfigureAwait(false);
-
- RegisterItem(item);
-
- if (ItemUpdated != null)
- {
- try
- {
- ItemUpdated(this, new ItemChangeEventArgs
- {
- Item = item,
- UpdateReason = updateReason
- });
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in ItemUpdated event handler", ex);
- }
- }
- }
-
- /// <summary>
- /// Reports the item removed.
- /// </summary>
- /// <param name="item">The item.</param>
- public void ReportItemRemoved(BaseItem item)
- {
- if (ItemRemoved != null)
- {
- try
- {
- ItemRemoved(this, new ItemChangeEventArgs { Item = item });
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in ItemRemoved event handler", ex);
- }
- }
- }
-
- /// <summary>
- /// Retrieves the item.
- /// </summary>
- /// <param name="id">The id.</param>
- /// <returns>BaseItem.</returns>
- public BaseItem RetrieveItem(Guid id)
- {
- return ItemRepository.RetrieveItem(id);
- }
-
- public IEnumerable<Folder> GetCollectionFolders(BaseItem item)
- {
- while (!(item.GetParent() is AggregateFolder) && item.GetParent() != null)
- {
- item = item.GetParent();
- }
-
- if (item == null)
- {
- return new List<Folder>();
- }
-
- return GetUserRootFolder().Children
- .OfType<Folder>()
- .Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path, StringComparer.OrdinalIgnoreCase));
- }
-
- public LibraryOptions GetLibraryOptions(BaseItem item)
- {
- var collectionFolder = item as CollectionFolder;
- if (collectionFolder == null)
- {
- collectionFolder = GetCollectionFolders(item)
- .OfType<CollectionFolder>()
- .FirstOrDefault();
- }
-
- var options = collectionFolder == null ? new LibraryOptions() : collectionFolder.GetLibraryOptions();
-
- if (options.SchemaVersion < 3)
- {
- options.SaveLocalMetadata = ConfigurationManager.Configuration.SaveLocalMeta;
- options.EnableInternetProviders = ConfigurationManager.Configuration.EnableInternetProviders;
- }
-
- if (options.SchemaVersion < 2)
- {
- var chapterOptions = ConfigurationManager.GetConfiguration<ChapterOptions>("chapters");
- options.ExtractChapterImagesDuringLibraryScan = chapterOptions.ExtractDuringLibraryScan;
-
- if (collectionFolder != null)
- {
- if (string.Equals(collectionFolder.CollectionType, "movies", StringComparison.OrdinalIgnoreCase))
- {
- options.EnableChapterImageExtraction = chapterOptions.EnableMovieChapterImageExtraction;
- }
- else if (string.Equals(collectionFolder.CollectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
- {
- options.EnableChapterImageExtraction = chapterOptions.EnableEpisodeChapterImageExtraction;
- }
- }
- }
-
- return options;
- }
-
- public string GetContentType(BaseItem item)
- {
- string configuredContentType = GetConfiguredContentType(item, false);
- if (!string.IsNullOrWhiteSpace(configuredContentType))
- {
- return configuredContentType;
- }
- configuredContentType = GetConfiguredContentType(item, true);
- if (!string.IsNullOrWhiteSpace(configuredContentType))
- {
- return configuredContentType;
- }
- return GetInheritedContentType(item);
- }
-
- public string GetInheritedContentType(BaseItem item)
- {
- var type = GetTopFolderContentType(item);
-
- if (!string.IsNullOrWhiteSpace(type))
- {
- return type;
- }
-
- return item.GetParents()
- .Select(GetConfiguredContentType)
- .LastOrDefault(i => !string.IsNullOrWhiteSpace(i));
- }
-
- public string GetConfiguredContentType(BaseItem item)
- {
- return GetConfiguredContentType(item, false);
- }
-
- public string GetConfiguredContentType(string path)
- {
- return GetContentTypeOverride(path, false);
- }
-
- public string GetConfiguredContentType(BaseItem item, bool inheritConfiguredPath)
- {
- ICollectionFolder collectionFolder = item as ICollectionFolder;
- if (collectionFolder != null)
- {
- return collectionFolder.CollectionType;
- }
- return GetContentTypeOverride(item.ContainingFolderPath, inheritConfiguredPath);
- }
-
- private string GetContentTypeOverride(string path, bool inherit)
- {
- var nameValuePair = ConfigurationManager.Configuration.ContentTypes.FirstOrDefault(i => string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase) || (inherit && !string.IsNullOrWhiteSpace(i.Name) && _fileSystem.ContainsSubPath(i.Name, path)));
- if (nameValuePair != null)
- {
- return nameValuePair.Value;
- }
- return null;
- }
-
- private string GetTopFolderContentType(BaseItem item)
- {
- if (item == null)
- {
- return null;
- }
-
- while (!(item.GetParent() is AggregateFolder) && item.GetParent() != null)
- {
- item = item.GetParent();
- }
-
- return GetUserRootFolder().Children
- .OfType<ICollectionFolder>()
- .Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path))
- .Select(i => i.CollectionType)
- .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
- }
-
- private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24);
- //private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromMinutes(1);
-
- public Task<UserView> GetNamedView(User user,
- string name,
- string viewType,
- string sortName,
- CancellationToken cancellationToken)
- {
- return GetNamedView(user, name, null, viewType, sortName, cancellationToken);
- }
-
- public async Task<UserView> GetNamedView(string name,
- string viewType,
- string sortName,
- CancellationToken cancellationToken)
- {
- var path = Path.Combine(ConfigurationManager.ApplicationPaths.ItemsByNamePath, "views");
-
- path = Path.Combine(path, _fileSystem.GetValidFilename(viewType));
-
- var id = GetNewItemId(path + "_namedview_" + name, typeof(UserView));
-
- var item = GetItemById(id) as UserView;
-
- var refresh = false;
-
- if (item == null || !string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase))
- {
- _fileSystem.CreateDirectory(path);
-
- item = new UserView
- {
- Path = path,
- Id = id,
- DateCreated = DateTime.UtcNow,
- Name = name,
- ViewType = viewType,
- ForcedSortName = sortName
- };
-
- await CreateItem(item, cancellationToken).ConfigureAwait(false);
-
- refresh = true;
- }
-
- if (!refresh)
- {
- refresh = DateTime.UtcNow - item.DateLastRefreshed >= _viewRefreshInterval;
- }
-
- if (!refresh && item.DisplayParentId != Guid.Empty)
- {
- var displayParent = GetItemById(item.DisplayParentId);
- refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
- }
-
- if (refresh)
- {
- await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false);
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
- {
- // Not sure why this is necessary but need to figure it out
- // View images are not getting utilized without this
- ForceSave = true
- });
- }
-
- return item;
- }
-
- public async Task<UserView> GetNamedView(User user,
- string name,
- string parentId,
- string viewType,
- string sortName,
- CancellationToken cancellationToken)
- {
- var idValues = "38_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty) + (viewType ?? string.Empty);
-
- var id = GetNewItemId(idValues, typeof(UserView));
-
- var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N"));
-
- var item = GetItemById(id) as UserView;
-
- var isNew = false;
-
- if (item == null)
- {
- _fileSystem.CreateDirectory(path);
-
- item = new UserView
- {
- Path = path,
- Id = id,
- DateCreated = DateTime.UtcNow,
- Name = name,
- ViewType = viewType,
- ForcedSortName = sortName,
- UserId = user.Id
- };
-
- if (!string.IsNullOrWhiteSpace(parentId))
- {
- item.DisplayParentId = new Guid(parentId);
- }
-
- await CreateItem(item, cancellationToken).ConfigureAwait(false);
-
- isNew = true;
- }
-
- var refresh = isNew || DateTime.UtcNow - item.DateLastRefreshed >= _viewRefreshInterval;
-
- if (!refresh && item.DisplayParentId != Guid.Empty)
- {
- var displayParent = GetItemById(item.DisplayParentId);
- refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
- }
-
- if (refresh)
- {
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
- {
- // Need to force save to increment DateLastSaved
- ForceSave = true
- });
- }
-
- return item;
- }
-
- public async Task<UserView> GetShadowView(BaseItem parent,
- string viewType,
- string sortName,
- CancellationToken cancellationToken)
- {
- if (parent == null)
- {
- throw new ArgumentNullException("parent");
- }
-
- var name = parent.Name;
- var parentId = parent.Id;
-
- var idValues = "38_namedview_" + name + parentId + (viewType ?? string.Empty);
-
- var id = GetNewItemId(idValues, typeof(UserView));
-
- var path = parent.Path;
-
- var item = GetItemById(id) as UserView;
-
- var isNew = false;
-
- if (item == null)
- {
- _fileSystem.CreateDirectory(path);
-
- item = new UserView
- {
- Path = path,
- Id = id,
- DateCreated = DateTime.UtcNow,
- Name = name,
- ViewType = viewType,
- ForcedSortName = sortName
- };
-
- item.DisplayParentId = parentId;
-
- await CreateItem(item, cancellationToken).ConfigureAwait(false);
-
- isNew = true;
- }
-
- var refresh = isNew || DateTime.UtcNow - item.DateLastRefreshed >= _viewRefreshInterval;
-
- if (!refresh && item.DisplayParentId != Guid.Empty)
- {
- var displayParent = GetItemById(item.DisplayParentId);
- refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
- }
-
- if (refresh)
- {
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
- {
- // Need to force save to increment DateLastSaved
- ForceSave = true
- });
- }
-
- return item;
- }
-
- public async Task<UserView> GetNamedView(string name,
- string parentId,
- string viewType,
- string sortName,
- string uniqueId,
- CancellationToken cancellationToken)
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- throw new ArgumentNullException("name");
- }
-
- var idValues = "37_namedview_" + name + (parentId ?? string.Empty) + (viewType ?? string.Empty);
- if (!string.IsNullOrWhiteSpace(uniqueId))
- {
- idValues += uniqueId;
- }
-
- var id = GetNewItemId(idValues, typeof(UserView));
-
- var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N"));
-
- var item = GetItemById(id) as UserView;
-
- var isNew = false;
-
- if (item == null)
- {
- _fileSystem.CreateDirectory(path);
-
- item = new UserView
- {
- Path = path,
- Id = id,
- DateCreated = DateTime.UtcNow,
- Name = name,
- ViewType = viewType,
- ForcedSortName = sortName
- };
-
- if (!string.IsNullOrWhiteSpace(parentId))
- {
- item.DisplayParentId = new Guid(parentId);
- }
-
- await CreateItem(item, cancellationToken).ConfigureAwait(false);
-
- isNew = true;
- }
-
- if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase))
- {
- item.ViewType = viewType;
- await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
- }
-
- var refresh = isNew || DateTime.UtcNow - item.DateLastRefreshed >= _viewRefreshInterval;
-
- if (!refresh && item.DisplayParentId != Guid.Empty)
- {
- var displayParent = GetItemById(item.DisplayParentId);
- refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
- }
-
- if (refresh)
- {
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
- {
- // Need to force save to increment DateLastSaved
- ForceSave = true
- });
- }
-
- return item;
- }
-
- public bool IsVideoFile(string path, LibraryOptions libraryOptions)
- {
- var resolver = new VideoResolver(GetNamingOptions(libraryOptions), new PatternsLogger());
- return resolver.IsVideoFile(path);
- }
-
- public bool IsVideoFile(string path)
- {
- return IsVideoFile(path, new LibraryOptions());
- }
-
- public bool IsAudioFile(string path, LibraryOptions libraryOptions)
- {
- var parser = new AudioFileParser(GetNamingOptions(libraryOptions));
- return parser.IsAudioFile(path);
- }
-
- public bool IsAudioFile(string path)
- {
- return IsAudioFile(path, new LibraryOptions());
- }
-
- public int? GetSeasonNumberFromPath(string path)
- {
- return new SeasonPathParser(GetNamingOptions(), new RegexProvider()).Parse(path, true, true).SeasonNumber;
- }
-
- public bool FillMissingEpisodeNumbersFromPath(Episode episode)
- {
- var resolver = new EpisodeResolver(GetNamingOptions(),
- new PatternsLogger());
-
- var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd ||
- episode.VideoType == VideoType.HdDvd;
-
- var locationType = episode.LocationType;
-
- var episodeInfo = locationType == LocationType.FileSystem || locationType == LocationType.Offline ?
- resolver.Resolve(episode.Path, isFolder) :
- new Naming.TV.EpisodeInfo();
-
- if (episodeInfo == null)
- {
- episodeInfo = new Naming.TV.EpisodeInfo();
- }
-
- var changed = false;
-
- if (episodeInfo.IsByDate)
- {
- if (episode.IndexNumber.HasValue)
- {
- episode.IndexNumber = null;
- changed = true;
- }
-
- if (episode.IndexNumberEnd.HasValue)
- {
- episode.IndexNumberEnd = null;
- changed = true;
- }
-
- if (!episode.PremiereDate.HasValue)
- {
- if (episodeInfo.Year.HasValue && episodeInfo.Month.HasValue && episodeInfo.Day.HasValue)
- {
- episode.PremiereDate = new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value).ToUniversalTime();
- }
-
- if (episode.PremiereDate.HasValue)
- {
- changed = true;
- }
- }
-
- if (!episode.ProductionYear.HasValue)
- {
- episode.ProductionYear = episodeInfo.Year;
-
- if (episode.ProductionYear.HasValue)
- {
- changed = true;
- }
- }
-
- if (!episode.ParentIndexNumber.HasValue)
- {
- var season = episode.Season;
-
- if (season != null)
- {
- episode.ParentIndexNumber = season.IndexNumber;
- }
-
- if (episode.ParentIndexNumber.HasValue)
- {
- changed = true;
- }
- }
- }
- else
- {
- if (!episode.IndexNumber.HasValue)
- {
- episode.IndexNumber = episodeInfo.EpisodeNumber;
-
- if (episode.IndexNumber.HasValue)
- {
- changed = true;
- }
- }
-
- if (!episode.IndexNumberEnd.HasValue)
- {
- episode.IndexNumberEnd = episodeInfo.EndingEpsiodeNumber;
-
- if (episode.IndexNumberEnd.HasValue)
- {
- changed = true;
- }
- }
-
- if (!episode.ParentIndexNumber.HasValue)
- {
- episode.ParentIndexNumber = episodeInfo.SeasonNumber;
-
- if (!episode.ParentIndexNumber.HasValue)
- {
- var season = episode.Season;
-
- if (season != null)
- {
- episode.ParentIndexNumber = season.IndexNumber;
- }
- }
-
- if (episode.ParentIndexNumber.HasValue)
- {
- changed = true;
- }
- }
- }
-
- return changed;
- }
-
- public NamingOptions GetNamingOptions()
- {
- return GetNamingOptions(new LibraryOptions());
- }
-
- public NamingOptions GetNamingOptions(LibraryOptions libraryOptions)
- {
- var options = new ExtendedNamingOptions();
-
- // These cause apps to have problems
- options.AudioFileExtensions.Remove(".m3u");
- options.AudioFileExtensions.Remove(".wpl");
-
- if (!libraryOptions.EnableArchiveMediaFiles)
- {
- options.AudioFileExtensions.Remove(".rar");
- options.AudioFileExtensions.Remove(".zip");
- }
-
- if (!libraryOptions.EnableArchiveMediaFiles)
- {
- options.VideoFileExtensions.Remove(".rar");
- options.VideoFileExtensions.Remove(".zip");
- }
-
- return options;
- }
-
- public ItemLookupInfo ParseName(string name)
- {
- var resolver = new VideoResolver(GetNamingOptions(), new PatternsLogger());
-
- var result = resolver.CleanDateTime(name);
- var cleanName = resolver.CleanString(result.Name);
-
- return new ItemLookupInfo
- {
- Name = cleanName.Name,
- Year = result.Year
- };
- }
-
- public IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
- {
- var files = owner.DetectIsInMixedFolder() ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory)
- .Where(i => string.Equals(i.Name, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => _fileSystem.GetFiles(i.FullName, false))
- .ToList();
-
- var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
-
- var videos = videoListResolver.Resolve(fileSystemChildren);
-
- var currentVideo = videos.FirstOrDefault(i => string.Equals(owner.Path, i.Files.First().Path, StringComparison.OrdinalIgnoreCase));
-
- if (currentVideo != null)
- {
- files.AddRange(currentVideo.Extras.Where(i => string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => _fileSystem.GetFileInfo(i.Path)));
- }
-
- var resolvers = new IItemResolver[]
- {
- new GenericVideoResolver<Trailer>(this)
- };
-
- return ResolvePaths(files, directoryService, null, new LibraryOptions(), null, resolvers)
- .OfType<Trailer>()
- .Select(video =>
- {
- // Try to retrieve it from the db. If we don't find it, use the resolved version
- var dbItem = GetItemById(video.Id) as Trailer;
-
- if (dbItem != null)
- {
- video = dbItem;
- }
-
- video.ExtraType = ExtraType.Trailer;
- video.TrailerTypes = new List<TrailerType> { TrailerType.LocalTrailer };
-
- return video;
-
- // Sort them so that the list can be easily compared for changes
- }).OrderBy(i => i.Path).ToList();
- }
-
- public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
- {
- var files = fileSystemChildren.Where(i => i.IsDirectory)
- .Where(i => string.Equals(i.Name, "extras", StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, "specials", StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => _fileSystem.GetFiles(i.FullName, false))
- .ToList();
-
- var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
-
- var videos = videoListResolver.Resolve(fileSystemChildren);
-
- var currentVideo = videos.FirstOrDefault(i => string.Equals(owner.Path, i.Files.First().Path, StringComparison.OrdinalIgnoreCase));
-
- if (currentVideo != null)
- {
- files.AddRange(currentVideo.Extras.Where(i => !string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => _fileSystem.GetFileInfo(i.Path)));
- }
-
- return ResolvePaths(files, directoryService, null, new LibraryOptions(), null)
- .OfType<Video>()
- .Select(video =>
- {
- // Try to retrieve it from the db. If we don't find it, use the resolved version
- var dbItem = GetItemById(video.Id) as Video;
-
- if (dbItem != null)
- {
- video = dbItem;
- }
-
- SetExtraTypeFromFilename(video);
-
- return video;
-
- // Sort them so that the list can be easily compared for changes
- }).OrderBy(i => i.Path).ToList();
- }
-
- public string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem)
- {
- if (ownerItem != null)
- {
- var libraryOptions = GetLibraryOptions(ownerItem);
- if (libraryOptions != null)
- {
- foreach (var pathInfo in libraryOptions.PathInfos)
- {
- if (string.IsNullOrWhiteSpace(pathInfo.NetworkPath))
- {
- continue;
- }
-
- var substitutionResult = SubstitutePathInternal(path, pathInfo.Path, pathInfo.NetworkPath);
- if (substitutionResult.Item2)
- {
- return substitutionResult.Item1;
- }
- }
- }
- }
-
- var metadataPath = ConfigurationManager.Configuration.MetadataPath;
- var metadataNetworkPath = ConfigurationManager.Configuration.MetadataNetworkPath;
-
- if (!string.IsNullOrWhiteSpace(metadataPath) && !string.IsNullOrWhiteSpace(metadataNetworkPath))
- {
- var metadataSubstitutionResult = SubstitutePathInternal(path, metadataPath, metadataNetworkPath);
- if (metadataSubstitutionResult.Item2)
- {
- return metadataSubstitutionResult.Item1;
- }
- }
-
- foreach (var map in ConfigurationManager.Configuration.PathSubstitutions)
- {
- var substitutionResult = SubstitutePathInternal(path, map.From, map.To);
- if (substitutionResult.Item2)
- {
- return substitutionResult.Item1;
- }
- }
-
- return path;
- }
-
- public string SubstitutePath(string path, string from, string to)
- {
- return SubstitutePathInternal(path, from, to).Item1;
- }
-
- private Tuple<string, bool> SubstitutePathInternal(string path, string from, string to)
- {
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException("path");
- }
- if (string.IsNullOrWhiteSpace(from))
- {
- throw new ArgumentNullException("from");
- }
- if (string.IsNullOrWhiteSpace(to))
- {
- throw new ArgumentNullException("to");
- }
-
- from = from.Trim();
- to = to.Trim();
-
- var newPath = path.Replace(from, to, StringComparison.OrdinalIgnoreCase);
- var changed = false;
-
- if (!string.Equals(newPath, path))
- {
- if (to.IndexOf('/') != -1)
- {
- newPath = newPath.Replace('\\', '/');
- }
- else
- {
- newPath = newPath.Replace('/', '\\');
- }
-
- changed = true;
- }
-
- return new Tuple<string, bool>(newPath, changed);
- }
-
- private void SetExtraTypeFromFilename(Video item)
- {
- var resolver = new ExtraResolver(GetNamingOptions(), new PatternsLogger(), new RegexProvider());
-
- var result = resolver.GetExtraInfo(item.Path);
-
- if (string.Equals(result.ExtraType, "deletedscene", StringComparison.OrdinalIgnoreCase))
- {
- item.ExtraType = ExtraType.DeletedScene;
- }
- else if (string.Equals(result.ExtraType, "behindthescenes", StringComparison.OrdinalIgnoreCase))
- {
- item.ExtraType = ExtraType.BehindTheScenes;
- }
- else if (string.Equals(result.ExtraType, "interview", StringComparison.OrdinalIgnoreCase))
- {
- item.ExtraType = ExtraType.Interview;
- }
- else if (string.Equals(result.ExtraType, "scene", StringComparison.OrdinalIgnoreCase))
- {
- item.ExtraType = ExtraType.Scene;
- }
- else if (string.Equals(result.ExtraType, "sample", StringComparison.OrdinalIgnoreCase))
- {
- item.ExtraType = ExtraType.Sample;
- }
- else
- {
- item.ExtraType = ExtraType.Clip;
- }
- }
-
- public List<PersonInfo> GetPeople(InternalPeopleQuery query)
- {
- return ItemRepository.GetPeople(query);
- }
-
- public List<PersonInfo> GetPeople(BaseItem item)
- {
- if (item.SupportsPeople)
- {
- var people = GetPeople(new InternalPeopleQuery
- {
- ItemId = item.Id
- });
-
- if (people.Count > 0)
- {
- return people;
- }
- }
-
- return new List<PersonInfo>();
- }
-
- public List<Person> GetPeopleItems(InternalPeopleQuery query)
- {
- return ItemRepository.GetPeopleNames(query).Select(i =>
- {
- try
- {
- return GetPerson(i);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting person", ex);
- return null;
- }
-
- }).Where(i => i != null).ToList();
- }
-
- public List<string> GetPeopleNames(InternalPeopleQuery query)
- {
- return ItemRepository.GetPeopleNames(query);
- }
-
- public Task UpdatePeople(BaseItem item, List<PersonInfo> people)
- {
- if (!item.SupportsPeople)
- {
- return Task.FromResult(true);
- }
-
- return ItemRepository.UpdatePeople(item.Id, people);
- }
-
- private readonly SemaphoreSlim _dynamicImageResourcePool = new SemaphoreSlim(1, 1);
- public async Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex)
- {
- foreach (var url in image.Path.Split('|'))
- {
- try
- {
- _logger.Debug("ConvertImageToLocal item {0} - image url: {1}", item.Id, url);
-
- await _providerManagerFactory().SaveImage(item, url, _dynamicImageResourcePool, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false);
-
- var newImage = item.GetImageInfo(image.Type, imageIndex);
-
- if (newImage != null)
- {
- newImage.IsPlaceholder = image.IsPlaceholder;
- }
-
- await item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
-
- return item.GetImageInfo(image.Type, imageIndex);
- }
- catch (HttpException ex)
- {
- if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound)
- {
- continue;
- }
- throw;
- }
- }
-
- // Remove this image to prevent it from retrying over and over
- item.RemoveImage(image);
- await item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
-
- throw new InvalidOperationException();
- }
-
- public void AddVirtualFolder(string name, string collectionType, LibraryOptions options, bool refreshLibrary)
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- throw new ArgumentNullException("name");
- }
-
- name = _fileSystem.GetValidFilename(name);
-
- var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
-
- var virtualFolderPath = Path.Combine(rootFolderPath, name);
- while (_fileSystem.DirectoryExists(virtualFolderPath))
- {
- name += "1";
- virtualFolderPath = Path.Combine(rootFolderPath, name);
- }
-
- var mediaPathInfos = options.PathInfos;
- if (mediaPathInfos != null)
- {
- var invalidpath = mediaPathInfos.FirstOrDefault(i => !_fileSystem.DirectoryExists(i.Path));
- if (invalidpath != null)
- {
- throw new ArgumentException("The specified path does not exist: " + invalidpath.Path + ".");
- }
- }
-
- _libraryMonitorFactory().Stop();
-
- try
- {
- _fileSystem.CreateDirectory(virtualFolderPath);
-
- if (!string.IsNullOrEmpty(collectionType))
- {
- var path = Path.Combine(virtualFolderPath, collectionType + ".collection");
-
- using (File.Create(path))
- {
-
- }
- }
-
- CollectionFolder.SaveLibraryOptions(virtualFolderPath, options);
-
- if (mediaPathInfos != null)
- {
- foreach (var path in mediaPathInfos)
- {
- AddMediaPathInternal(name, path, false);
- }
- }
- }
- finally
- {
- Task.Run(() =>
- {
- // No need to start if scanning the library because it will handle it
- if (refreshLibrary)
- {
- ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
- }
- else
- {
- // Need to add a delay here or directory watchers may still pick up the changes
- var task = Task.Delay(1000);
- // Have to block here to allow exceptions to bubble
- Task.WaitAll(task);
-
- _libraryMonitorFactory().Start();
- }
- });
- }
- }
-
- private bool ValidateNetworkPath(string path)
- {
- if (Environment.OSVersion.Platform == PlatformID.Win32NT)
- {
- // We can't validate protocol-based paths, so just allow them
- if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) == -1)
- {
- return Directory.Exists(path);
- }
- }
-
- // Without native support for unc, we cannot validate this when running under mono
- return true;
- }
-
- private const string ShortcutFileExtension = ".mblink";
- private const string ShortcutFileSearch = "*" + ShortcutFileExtension;
- public void AddMediaPath(string virtualFolderName, MediaPathInfo pathInfo)
- {
- AddMediaPathInternal(virtualFolderName, pathInfo, true);
- }
-
- private void AddMediaPathInternal(string virtualFolderName, MediaPathInfo pathInfo, bool saveLibraryOptions)
- {
- if (pathInfo == null)
- {
- throw new ArgumentNullException("path");
- }
-
- var path = pathInfo.Path;
-
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException("path");
- }
-
- if (!_fileSystem.DirectoryExists(path))
- {
- throw new DirectoryNotFoundException("The path does not exist.");
- }
-
- if (!string.IsNullOrWhiteSpace(pathInfo.NetworkPath) && !ValidateNetworkPath(pathInfo.NetworkPath))
- {
- throw new DirectoryNotFoundException("The network path does not exist.");
- }
-
- var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
- var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
-
- var shortcutFilename = _fileSystem.GetFileNameWithoutExtension(path);
-
- var lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
-
- while (_fileSystem.FileExists(lnk))
- {
- shortcutFilename += "1";
- lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
- }
-
- _fileSystem.CreateShortcut(lnk, path);
-
- RemoveContentTypeOverrides(path);
-
- if (saveLibraryOptions)
- {
- var libraryOptions = CollectionFolder.GetLibraryOptions(virtualFolderPath);
-
- var list = libraryOptions.PathInfos.ToList();
- list.Add(pathInfo);
- libraryOptions.PathInfos = list.ToArray();
-
- SyncLibraryOptionsToLocations(virtualFolderPath, libraryOptions);
-
- CollectionFolder.SaveLibraryOptions(virtualFolderPath, libraryOptions);
- }
- }
-
- public void UpdateMediaPath(string virtualFolderName, MediaPathInfo pathInfo)
- {
- if (pathInfo == null)
- {
- throw new ArgumentNullException("path");
- }
-
- if (!string.IsNullOrWhiteSpace(pathInfo.NetworkPath) && !ValidateNetworkPath(pathInfo.NetworkPath))
- {
- throw new DirectoryNotFoundException("The network path does not exist.");
- }
-
- var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
- var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
-
- var libraryOptions = CollectionFolder.GetLibraryOptions(virtualFolderPath);
-
- SyncLibraryOptionsToLocations(virtualFolderPath, libraryOptions);
-
- var list = libraryOptions.PathInfos.ToList();
- foreach (var originalPathInfo in list)
- {
- if (string.Equals(pathInfo.Path, originalPathInfo.Path, StringComparison.Ordinal))
- {
- originalPathInfo.NetworkPath = pathInfo.NetworkPath;
- break;
- }
- }
-
- libraryOptions.PathInfos = list.ToArray();
-
- CollectionFolder.SaveLibraryOptions(virtualFolderPath, libraryOptions);
- }
-
- private void SyncLibraryOptionsToLocations(string virtualFolderPath, LibraryOptions options)
- {
- var topLibraryFolders = GetUserRootFolder().Children.ToList();
- var info = GetVirtualFolderInfo(virtualFolderPath, topLibraryFolders);
-
- if (info.Locations.Count > 0 && info.Locations.Count != options.PathInfos.Length)
- {
- var list = options.PathInfos.ToList();
-
- foreach (var location in info.Locations)
- {
- if (!list.Any(i => string.Equals(i.Path, location, StringComparison.Ordinal)))
- {
- list.Add(new MediaPathInfo
- {
- Path = location
- });
- }
- }
-
- options.PathInfos = list.ToArray();
- }
- }
-
- public void RemoveVirtualFolder(string name, bool refreshLibrary)
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- throw new ArgumentNullException("name");
- }
-
- var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
-
- var path = Path.Combine(rootFolderPath, name);
-
- if (!_fileSystem.DirectoryExists(path))
- {
- throw new DirectoryNotFoundException("The media folder does not exist");
- }
-
- _libraryMonitorFactory().Stop();
-
- try
- {
- _fileSystem.DeleteDirectory(path, true);
- }
- finally
- {
- Task.Run(() =>
- {
- // No need to start if scanning the library because it will handle it
- if (refreshLibrary)
- {
- ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
- }
- else
- {
- // Need to add a delay here or directory watchers may still pick up the changes
- var task = Task.Delay(1000);
- // Have to block here to allow exceptions to bubble
- Task.WaitAll(task);
-
- _libraryMonitorFactory().Start();
- }
- });
- }
- }
-
- private void RemoveContentTypeOverrides(string path)
- {
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var removeList = new List<NameValuePair>();
-
- foreach (var contentType in ConfigurationManager.Configuration.ContentTypes)
- {
- if (string.Equals(path, contentType.Name, StringComparison.OrdinalIgnoreCase)
- || _fileSystem.ContainsSubPath(path, contentType.Name))
- {
- removeList.Add(contentType);
- }
- }
-
- if (removeList.Count > 0)
- {
- ConfigurationManager.Configuration.ContentTypes = ConfigurationManager.Configuration.ContentTypes
- .Except(removeList)
- .ToArray();
-
- ConfigurationManager.SaveConfiguration();
- }
- }
-
- public void RemoveMediaPath(string virtualFolderName, string mediaPath)
- {
- if (string.IsNullOrWhiteSpace(mediaPath))
- {
- throw new ArgumentNullException("mediaPath");
- }
-
- var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
- var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
-
- if (!_fileSystem.DirectoryExists(virtualFolderPath))
- {
- throw new DirectoryNotFoundException(string.Format("The media collection {0} does not exist", virtualFolderName));
- }
-
- var shortcut = Directory.EnumerateFiles(virtualFolderPath, ShortcutFileSearch, SearchOption.AllDirectories).FirstOrDefault(f => _fileSystem.ResolveShortcut(f).Equals(mediaPath, StringComparison.OrdinalIgnoreCase));
-
- if (!string.IsNullOrEmpty(shortcut))
- {
- _fileSystem.DeleteFile(shortcut);
- }
-
- var libraryOptions = CollectionFolder.GetLibraryOptions(virtualFolderPath);
-
- libraryOptions.PathInfos = libraryOptions
- .PathInfos
- .Where(i => !string.Equals(i.Path, mediaPath, StringComparison.Ordinal))
- .ToArray();
-
- CollectionFolder.SaveLibraryOptions(virtualFolderPath, libraryOptions);
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs
deleted file mode 100644
index 78107b82d..000000000
--- a/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- public class LocalTrailerPostScanTask : ILibraryPostScanTask
- {
- private readonly ILibraryManager _libraryManager;
- private readonly IChannelManager _channelManager;
-
- public LocalTrailerPostScanTask(ILibraryManager libraryManager, IChannelManager channelManager)
- {
- _libraryManager = libraryManager;
- _channelManager = channelManager;
- }
-
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var items = _libraryManager.GetItemList(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(BoxSet).Name, typeof(Game).Name, typeof(Movie).Name, typeof(Series).Name },
- Recursive = true
-
- }).OfType<IHasTrailers>().ToList();
-
- var trailerTypes = Enum.GetNames(typeof(TrailerType))
- .Select(i => (TrailerType)Enum.Parse(typeof(TrailerType), i, true))
- .Except(new[] { TrailerType.LocalTrailer })
- .ToArray();
-
- var trailers = _libraryManager.GetItemList(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(Trailer).Name },
- TrailerTypes = trailerTypes,
- Recursive = true
-
- }).ToArray();
-
- var numComplete = 0;
-
- foreach (var item in items)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- await AssignTrailers(item, trailers).ConfigureAwait(false);
-
- numComplete++;
- double percent = numComplete;
- percent /= items.Count;
- progress.Report(percent * 100);
- }
-
- progress.Report(100);
- }
-
- private async Task AssignTrailers(IHasTrailers item, BaseItem[] channelTrailers)
- {
- if (item is Game)
- {
- return;
- }
-
- var imdbId = item.GetProviderId(MetadataProviders.Imdb);
- var tmdbId = item.GetProviderId(MetadataProviders.Tmdb);
-
- var trailers = channelTrailers.Where(i =>
- {
- if (!string.IsNullOrWhiteSpace(imdbId) &&
- string.Equals(imdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- if (!string.IsNullOrWhiteSpace(tmdbId) &&
- string.Equals(tmdbId, i.GetProviderId(MetadataProviders.Tmdb), StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- return false;
- });
-
- var trailerIds = trailers.Select(i => i.Id)
- .ToList();
-
- if (!trailerIds.SequenceEqual(item.RemoteTrailerIds))
- {
- item.RemoteTrailerIds = trailerIds;
-
- var baseItem = (BaseItem)item;
- await baseItem.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None)
- .ConfigureAwait(false);
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
deleted file mode 100644
index 0f1931dda..000000000
--- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
+++ /dev/null
@@ -1,648 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Configuration;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- public class MediaSourceManager : IMediaSourceManager, IDisposable
- {
- private readonly IItemRepository _itemRepo;
- private readonly IUserManager _userManager;
- private readonly ILibraryManager _libraryManager;
- private readonly IJsonSerializer _jsonSerializer;
- private readonly IFileSystem _fileSystem;
-
- private IMediaSourceProvider[] _providers;
- private readonly ILogger _logger;
- private readonly IUserDataManager _userDataManager;
-
- public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, ILogger logger, IJsonSerializer jsonSerializer, IFileSystem fileSystem, IUserDataManager userDataManager)
- {
- _itemRepo = itemRepo;
- _userManager = userManager;
- _libraryManager = libraryManager;
- _logger = logger;
- _jsonSerializer = jsonSerializer;
- _fileSystem = fileSystem;
- _userDataManager = userDataManager;
- }
-
- public void AddParts(IEnumerable<IMediaSourceProvider> providers)
- {
- _providers = providers.ToArray();
- }
-
- public IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query)
- {
- var list = _itemRepo.GetMediaStreams(query)
- .ToList();
-
- foreach (var stream in list)
- {
- stream.SupportsExternalStream = StreamSupportsExternalStream(stream);
- }
-
- return list;
- }
-
- private bool StreamSupportsExternalStream(MediaStream stream)
- {
- if (stream.IsExternal)
- {
- return true;
- }
-
- if (stream.IsTextSubtitleStream)
- {
- return true;
- }
-
- return false;
- }
-
- public IEnumerable<MediaStream> GetMediaStreams(string mediaSourceId)
- {
- var list = GetMediaStreams(new MediaStreamQuery
- {
- ItemId = new Guid(mediaSourceId)
- });
-
- return GetMediaStreamsForItem(list);
- }
-
- public IEnumerable<MediaStream> GetMediaStreams(Guid itemId)
- {
- var list = GetMediaStreams(new MediaStreamQuery
- {
- ItemId = itemId
- });
-
- return GetMediaStreamsForItem(list);
- }
-
- private IEnumerable<MediaStream> GetMediaStreamsForItem(IEnumerable<MediaStream> streams)
- {
- var list = streams.ToList();
-
- var subtitleStreams = list
- .Where(i => i.Type == MediaStreamType.Subtitle)
- .ToList();
-
- if (subtitleStreams.Count > 0)
- {
- foreach (var subStream in subtitleStreams)
- {
- subStream.SupportsExternalStream = StreamSupportsExternalStream(subStream);
- }
- }
-
- return list;
- }
-
- public async Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, string[] supportedLiveMediaTypes, CancellationToken cancellationToken)
- {
- var item = _libraryManager.GetItemById(id);
-
- var hasMediaSources = (IHasMediaSources)item;
- User user = null;
-
- if (!string.IsNullOrWhiteSpace(userId))
- {
- user = _userManager.GetUserById(userId);
- }
-
- var mediaSources = GetStaticMediaSources(hasMediaSources, enablePathSubstitution, user);
- var dynamicMediaSources = await GetDynamicMediaSources(hasMediaSources, cancellationToken).ConfigureAwait(false);
-
- var list = new List<MediaSourceInfo>();
-
- list.AddRange(mediaSources);
-
- foreach (var source in dynamicMediaSources)
- {
- if (user != null)
- {
- SetUserProperties(hasMediaSources, source, user);
- }
- if (source.Protocol == MediaProtocol.File)
- {
- // TODO: Path substitution
- if (!_fileSystem.FileExists(source.Path))
- {
- source.SupportsDirectStream = false;
- }
- }
- else if (source.Protocol == MediaProtocol.Http)
- {
- // TODO: Allow this when the source is plain http, e.g. not HLS or Mpeg Dash
- source.SupportsDirectStream = false;
- }
- else
- {
- source.SupportsDirectStream = false;
- }
-
- list.Add(source);
- }
-
- foreach (var source in list)
- {
- if (user != null)
- {
- if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
- {
- if (!user.Policy.EnableAudioPlaybackTranscoding)
- {
- source.SupportsTranscoding = false;
- }
- }
- }
- }
-
- return SortMediaSources(list).Where(i => i.Type != MediaSourceType.Placeholder);
- }
-
- private async Task<IEnumerable<MediaSourceInfo>> GetDynamicMediaSources(IHasMediaSources item, CancellationToken cancellationToken)
- {
- var tasks = _providers.Select(i => GetDynamicMediaSources(item, i, cancellationToken));
- var results = await Task.WhenAll(tasks).ConfigureAwait(false);
-
- return results.SelectMany(i => i.ToList());
- }
-
- private async Task<IEnumerable<MediaSourceInfo>> GetDynamicMediaSources(IHasMediaSources item, IMediaSourceProvider provider, CancellationToken cancellationToken)
- {
- try
- {
- var sources = await provider.GetMediaSources(item, cancellationToken).ConfigureAwait(false);
- var list = sources.ToList();
-
- foreach (var mediaSource in list)
- {
- SetKeyProperties(provider, mediaSource);
- }
-
- return list;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting media sources", ex);
- return new List<MediaSourceInfo>();
- }
- }
-
- private void SetKeyProperties(IMediaSourceProvider provider, MediaSourceInfo mediaSource)
- {
- var prefix = provider.GetType().FullName.GetMD5().ToString("N") + LiveStreamIdDelimeter;
-
- if (!string.IsNullOrWhiteSpace(mediaSource.OpenToken) && !mediaSource.OpenToken.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
- {
- mediaSource.OpenToken = prefix + mediaSource.OpenToken;
- }
-
- if (!string.IsNullOrWhiteSpace(mediaSource.LiveStreamId) && !mediaSource.LiveStreamId.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
- {
- mediaSource.LiveStreamId = prefix + mediaSource.LiveStreamId;
- }
- }
-
- public async Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, string liveStreamId, bool enablePathSubstitution, CancellationToken cancellationToken)
- {
- if (!string.IsNullOrWhiteSpace(liveStreamId))
- {
- return await GetLiveStream(liveStreamId, cancellationToken).ConfigureAwait(false);
- }
- //await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- //try
- //{
- // var stream = _openStreams.Values.FirstOrDefault(i => string.Equals(i.MediaSource.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
-
- // if (stream != null)
- // {
- // return stream.MediaSource;
- // }
- //}
- //finally
- //{
- // _liveStreamSemaphore.Release();
- //}
-
- var sources = await GetPlayackMediaSources(item.Id.ToString("N"), null, enablePathSubstitution, new[] { MediaType.Audio, MediaType.Video },
- CancellationToken.None).ConfigureAwait(false);
-
- return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
- }
-
- public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null)
- {
- if (item == null)
- {
- throw new ArgumentNullException("item");
- }
-
- if (!(item is Video))
- {
- return item.GetMediaSources(enablePathSubstitution);
- }
-
- var sources = item.GetMediaSources(enablePathSubstitution).ToList();
-
- if (user != null)
- {
- foreach (var source in sources)
- {
- SetUserProperties(item, source, user);
- }
- }
-
- return sources;
- }
-
- private void SetUserProperties(IHasUserData item, MediaSourceInfo source, User user)
- {
- var userData = item == null ? new UserItemData() : _userDataManager.GetUserData(user, item);
-
- var allowRememberingSelection = item == null || item.EnableRememberingTrackSelections;
-
- SetDefaultAudioStreamIndex(source, userData, user, allowRememberingSelection);
- SetDefaultSubtitleStreamIndex(source, userData, user, allowRememberingSelection);
- }
-
- private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
- {
- if (userData.SubtitleStreamIndex.HasValue && user.Configuration.RememberSubtitleSelections && user.Configuration.SubtitleMode != SubtitlePlaybackMode.None && allowRememberingSelection)
- {
- var index = userData.SubtitleStreamIndex.Value;
- // Make sure the saved index is still valid
- if (index == -1 || source.MediaStreams.Any(i => i.Type == MediaStreamType.Subtitle && i.Index == index))
- {
- source.DefaultSubtitleStreamIndex = index;
- return;
- }
- }
-
- var preferredSubs = string.IsNullOrEmpty(user.Configuration.SubtitleLanguagePreference)
- ? new List<string>() : new List<string> { user.Configuration.SubtitleLanguagePreference };
-
- var defaultAudioIndex = source.DefaultAudioStreamIndex;
- var audioLangage = defaultAudioIndex == null
- ? null
- : source.MediaStreams.Where(i => i.Type == MediaStreamType.Audio && i.Index == defaultAudioIndex).Select(i => i.Language).FirstOrDefault();
-
- source.DefaultSubtitleStreamIndex = MediaStreamSelector.GetDefaultSubtitleStreamIndex(source.MediaStreams,
- preferredSubs,
- user.Configuration.SubtitleMode,
- audioLangage);
-
- MediaStreamSelector.SetSubtitleStreamScores(source.MediaStreams, preferredSubs,
- user.Configuration.SubtitleMode, audioLangage);
- }
-
- private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
- {
- if (userData.AudioStreamIndex.HasValue && user.Configuration.RememberAudioSelections && allowRememberingSelection)
- {
- var index = userData.AudioStreamIndex.Value;
- // Make sure the saved index is still valid
- if (source.MediaStreams.Any(i => i.Type == MediaStreamType.Audio && i.Index == index))
- {
- source.DefaultAudioStreamIndex = index;
- return;
- }
- }
-
- var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference)
- ? new string[] { }
- : new[] { user.Configuration.AudioLanguagePreference };
-
- source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.Configuration.PlayDefaultAudioTrack);
- }
-
- private IEnumerable<MediaSourceInfo> SortMediaSources(IEnumerable<MediaSourceInfo> sources)
- {
- return sources.OrderBy(i =>
- {
- if (i.VideoType.HasValue && i.VideoType.Value == VideoType.VideoFile)
- {
- return 0;
- }
-
- return 1;
-
- }).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0)
- .ThenByDescending(i =>
- {
- var stream = i.VideoStream;
-
- return stream == null || stream.Width == null ? 0 : stream.Width.Value;
- })
- .ToList();
- }
-
- private readonly Dictionary<string, LiveStreamInfo> _openStreams = new Dictionary<string, LiveStreamInfo>(StringComparer.OrdinalIgnoreCase);
- private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
-
- public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken)
- {
- await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- var tuple = GetProvider(request.OpenToken);
- var provider = tuple.Item1;
-
- var mediaSourceTuple = await provider.OpenMediaSource(tuple.Item2, cancellationToken).ConfigureAwait(false);
-
- var mediaSource = mediaSourceTuple.Item1;
-
- if (string.IsNullOrWhiteSpace(mediaSource.LiveStreamId))
- {
- throw new InvalidOperationException(string.Format("{0} returned null LiveStreamId", provider.GetType().Name));
- }
-
- SetKeyProperties(provider, mediaSource);
-
- var info = new LiveStreamInfo
- {
- Date = DateTime.UtcNow,
- EnableCloseTimer = enableAutoClose,
- Id = mediaSource.LiveStreamId,
- MediaSource = mediaSource,
- DirectStreamProvider = mediaSourceTuple.Item2
- };
-
- _openStreams[mediaSource.LiveStreamId] = info;
-
- if (enableAutoClose)
- {
- StartCloseTimer();
- }
-
- var json = _jsonSerializer.SerializeToString(mediaSource);
- _logger.Debug("Live stream opened: " + json);
- var clone = _jsonSerializer.DeserializeFromString<MediaSourceInfo>(json);
-
- if (!string.IsNullOrWhiteSpace(request.UserId))
- {
- var user = _userManager.GetUserById(request.UserId);
- var item = string.IsNullOrWhiteSpace(request.ItemId)
- ? null
- : _libraryManager.GetItemById(request.ItemId);
- SetUserProperties(item, clone, user);
- }
-
- return new LiveStreamResponse
- {
- MediaSource = clone
- };
- }
- finally
- {
- _liveStreamSemaphore.Release();
- }
- }
-
- public async Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken)
- {
- if (string.IsNullOrWhiteSpace(id))
- {
- throw new ArgumentNullException("id");
- }
-
- _logger.Debug("Getting already opened live stream {0}", id);
-
- await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- LiveStreamInfo info;
- if (_openStreams.TryGetValue(id, out info))
- {
- return new Tuple<MediaSourceInfo, IDirectStreamProvider>(info.MediaSource, info.DirectStreamProvider);
- }
- else
- {
- throw new ResourceNotFoundException();
- }
- }
- finally
- {
- _liveStreamSemaphore.Release();
- }
- }
-
- public async Task<MediaSourceInfo> GetLiveStream(string id, CancellationToken cancellationToken)
- {
- var result = await GetLiveStreamWithDirectStreamProvider(id, cancellationToken).ConfigureAwait(false);
- return result.Item1;
- }
-
- public async Task PingLiveStream(string id, CancellationToken cancellationToken)
- {
- await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- LiveStreamInfo info;
- if (_openStreams.TryGetValue(id, out info))
- {
- info.Date = DateTime.UtcNow;
- }
- else
- {
- _logger.Error("Failed to ping live stream {0}", id);
- }
- }
- finally
- {
- _liveStreamSemaphore.Release();
- }
- }
-
- private async Task CloseLiveStreamWithProvider(IMediaSourceProvider provider, string streamId)
- {
- _logger.Info("Closing live stream {0} with provider {1}", streamId, provider.GetType().Name);
-
- try
- {
- await provider.CloseMediaSource(streamId).ConfigureAwait(false);
- }
- catch (NotImplementedException)
- {
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error closing live stream {0}", ex, streamId);
- }
- }
-
- public async Task CloseLiveStream(string id)
- {
- if (string.IsNullOrWhiteSpace(id))
- {
- throw new ArgumentNullException("id");
- }
-
- await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false);
-
- try
- {
- LiveStreamInfo current;
-
- if (_openStreams.TryGetValue(id, out current))
- {
- _openStreams.Remove(id);
- current.Closed = true;
-
- if (current.MediaSource.RequiresClosing)
- {
- var tuple = GetProvider(id);
-
- await CloseLiveStreamWithProvider(tuple.Item1, tuple.Item2).ConfigureAwait(false);
- }
-
- if (_openStreams.Count == 0)
- {
- StopCloseTimer();
- }
- }
- }
- finally
- {
- _liveStreamSemaphore.Release();
- }
- }
-
- // Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message.
- private const char LiveStreamIdDelimeter = '_';
-
- private Tuple<IMediaSourceProvider, string> GetProvider(string key)
- {
- if (string.IsNullOrWhiteSpace(key))
- {
- throw new ArgumentException("key");
- }
-
- var keys = key.Split(new[] { LiveStreamIdDelimeter }, 2);
-
- var provider = _providers.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N"), keys[0], StringComparison.OrdinalIgnoreCase));
-
- var splitIndex = key.IndexOf(LiveStreamIdDelimeter);
- var keyId = key.Substring(splitIndex + 1);
-
- return new Tuple<IMediaSourceProvider, string>(provider, keyId);
- }
-
- private Timer _closeTimer;
- private readonly TimeSpan _openStreamMaxAge = TimeSpan.FromSeconds(180);
-
- private void StartCloseTimer()
- {
- StopCloseTimer();
-
- _closeTimer = new Timer(CloseTimerCallback, null, _openStreamMaxAge, _openStreamMaxAge);
- }
-
- private void StopCloseTimer()
- {
- var timer = _closeTimer;
-
- if (timer != null)
- {
- _closeTimer = null;
- timer.Dispose();
- }
- }
-
- private async void CloseTimerCallback(object state)
- {
- List<LiveStreamInfo> infos;
- await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false);
-
- try
- {
- infos = _openStreams
- .Values
- .Where(i => i.EnableCloseTimer && DateTime.UtcNow - i.Date > _openStreamMaxAge)
- .ToList();
- }
- finally
- {
- _liveStreamSemaphore.Release();
- }
-
- foreach (var info in infos)
- {
- if (!info.Closed)
- {
- try
- {
- await CloseLiveStream(info.Id).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error closing media source", ex);
- }
- }
- }
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- StopCloseTimer();
- Dispose(true);
- }
-
- private readonly object _disposeLock = new object();
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- lock (_disposeLock)
- {
- foreach (var key in _openStreams.Keys.ToList())
- {
- var task = CloseLiveStream(key);
-
- Task.WaitAll(task);
- }
- }
- }
- }
-
- private class LiveStreamInfo
- {
- public DateTime Date;
- public bool EnableCloseTimer;
- public string Id;
- public bool Closed;
- public MediaSourceInfo MediaSource;
- public IDirectStreamProvider DirectStreamProvider;
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Library/MusicManager.cs b/MediaBrowser.Server.Implementations/Library/MusicManager.cs
deleted file mode 100644
index 3ff434898..000000000
--- a/MediaBrowser.Server.Implementations/Library/MusicManager.cs
+++ /dev/null
@@ -1,157 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Playlists;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- public class MusicManager : IMusicManager
- {
- private readonly ILibraryManager _libraryManager;
-
- public MusicManager(ILibraryManager libraryManager)
- {
- _libraryManager = libraryManager;
- }
-
- public IEnumerable<Audio> GetInstantMixFromSong(Audio item, User user)
- {
- var list = new List<Audio>
- {
- item
- };
-
- return list.Concat(GetInstantMixFromGenres(item.Genres, user));
- }
-
- public IEnumerable<Audio> GetInstantMixFromArtist(MusicArtist artist, User user)
- {
- var genres = user.RootFolder
- .GetRecursiveChildren(user, new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Audio).Name }
- })
- .Cast<Audio>()
- .Where(i => i.HasAnyArtist(artist.Name))
- .SelectMany(i => i.Genres)
- .Concat(artist.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase);
-
- return GetInstantMixFromGenres(genres, user);
- }
-
- public IEnumerable<Audio> GetInstantMixFromAlbum(MusicAlbum item, User user)
- {
- var genres = item
- .GetRecursiveChildren(user, new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Audio).Name }
- })
- .Cast<Audio>()
- .SelectMany(i => i.Genres)
- .Concat(item.Genres)
- .DistinctNames();
-
- return GetInstantMixFromGenres(genres, user);
- }
-
- public IEnumerable<Audio> GetInstantMixFromFolder(Folder item, User user)
- {
- var genres = item
- .GetRecursiveChildren(user, new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] {typeof(Audio).Name}
- })
- .Cast<Audio>()
- .SelectMany(i => i.Genres)
- .Concat(item.Genres)
- .DistinctNames();
-
- return GetInstantMixFromGenres(genres, user);
- }
-
- public IEnumerable<Audio> GetInstantMixFromPlaylist(Playlist item, User user)
- {
- var genres = item
- .GetRecursiveChildren(user, new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Audio).Name }
- })
- .Cast<Audio>()
- .SelectMany(i => i.Genres)
- .Concat(item.Genres)
- .DistinctNames();
-
- return GetInstantMixFromGenres(genres, user);
- }
-
- public IEnumerable<Audio> GetInstantMixFromGenres(IEnumerable<string> genres, User user)
- {
- var genreList = genres.ToList();
-
- var inputItems = _libraryManager.GetItemList(new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Audio).Name },
-
- Genres = genreList.ToArray()
-
- });
-
- var genresDictionary = genreList.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
-
- return inputItems
- .Cast<Audio>()
- .Select(i => new Tuple<Audio, int>(i, i.Genres.Count(genresDictionary.ContainsKey)))
- .Where(i => i.Item2 > 0)
- .OrderByDescending(i => i.Item2)
- .ThenBy(i => Guid.NewGuid())
- .Select(i => i.Item1)
- .Take(100)
- .OrderBy(i => Guid.NewGuid());
- }
-
- public IEnumerable<Audio> GetInstantMixFromItem(BaseItem item, User user)
- {
- var genre = item as MusicGenre;
- if (genre != null)
- {
- return GetInstantMixFromGenres(new[] { item.Name }, user);
- }
-
- var playlist = item as Playlist;
- if (playlist != null)
- {
- return GetInstantMixFromPlaylist(playlist, user);
- }
-
- var album = item as MusicAlbum;
- if (album != null)
- {
- return GetInstantMixFromAlbum(album, user);
- }
-
- var artist = item as MusicArtist;
- if (artist != null)
- {
- return GetInstantMixFromArtist(artist, user);
- }
-
- var song = item as Audio;
- if (song != null)
- {
- return GetInstantMixFromSong(song, user);
- }
-
- var folder = item as Folder;
- if (folder != null)
- {
- return GetInstantMixFromFolder(folder, user);
- }
-
- return new Audio[] { };
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/PathExtensions.cs b/MediaBrowser.Server.Implementations/Library/PathExtensions.cs
deleted file mode 100644
index 6c0e3237e..000000000
--- a/MediaBrowser.Server.Implementations/Library/PathExtensions.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System;
-using System.Text.RegularExpressions;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- public static class PathExtensions
- {
- /// <summary>
- /// Gets the attribute value.
- /// </summary>
- /// <param name="str">The STR.</param>
- /// <param name="attrib">The attrib.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="System.ArgumentNullException">attrib</exception>
- public static string GetAttributeValue(this string str, string attrib)
- {
- if (string.IsNullOrEmpty(str))
- {
- throw new ArgumentNullException("str");
- }
-
- if (string.IsNullOrEmpty(attrib))
- {
- throw new ArgumentNullException("attrib");
- }
-
- string srch = "[" + attrib + "=";
- int start = str.IndexOf(srch, StringComparison.OrdinalIgnoreCase);
- if (start > -1)
- {
- start += srch.Length;
- int end = str.IndexOf(']', start);
- return str.Substring(start, end - start);
- }
- // for imdbid we also accept pattern matching
- if (string.Equals(attrib, "imdbid", StringComparison.OrdinalIgnoreCase))
- {
- var m = Regex.Match(str, "tt\\d{7}", RegexOptions.IgnoreCase);
- return m.Success ? m.Value : null;
- }
-
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs b/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs
deleted file mode 100644
index c7d9d39b8..000000000
--- a/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs
+++ /dev/null
@@ -1,183 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using System;
-using System.IO;
-using System.Linq;
-using System.Text.RegularExpressions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- /// <summary>
- /// Class ResolverHelper
- /// </summary>
- public static class ResolverHelper
- {
- /// <summary>
- /// Sets the initial item values.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="parent">The parent.</param>
- /// <param name="fileSystem">The file system.</param>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="directoryService">The directory service.</param>
- /// <exception cref="System.ArgumentException">Item must have a path</exception>
- public static void SetInitialItemValues(BaseItem item, Folder parent, IFileSystem fileSystem, ILibraryManager libraryManager, IDirectoryService directoryService)
- {
- // This version of the below method has no ItemResolveArgs, so we have to require the path already being set
- if (string.IsNullOrWhiteSpace(item.Path))
- {
- throw new ArgumentException("Item must have a Path");
- }
-
- // If the resolver didn't specify this
- if (parent != null)
- {
- item.SetParent(parent);
- }
-
- item.Id = libraryManager.GetNewItemId(item.Path, item.GetType());
-
- item.IsLocked = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1 ||
- item.GetParents().Any(i => i.IsLocked);
-
- // Make sure DateCreated and DateModified have values
- var fileInfo = directoryService.GetFile(item.Path);
- SetDateCreated(item, fileSystem, fileInfo);
-
- EnsureName(item, fileInfo);
- }
-
- /// <summary>
- /// Sets the initial item values.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- /// <param name="fileSystem">The file system.</param>
- /// <param name="libraryManager">The library manager.</param>
- public static void SetInitialItemValues(BaseItem item, ItemResolveArgs args, IFileSystem fileSystem, ILibraryManager libraryManager)
- {
- // If the resolver didn't specify this
- if (string.IsNullOrEmpty(item.Path))
- {
- item.Path = args.Path;
- }
-
- // If the resolver didn't specify this
- if (args.Parent != null)
- {
- item.SetParent(args.Parent);
- }
-
- item.Id = libraryManager.GetNewItemId(item.Path, item.GetType());
-
- // Make sure the item has a name
- EnsureName(item, args.FileInfo);
-
- item.IsLocked = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1 ||
- item.GetParents().Any(i => i.IsLocked);
-
- // Make sure DateCreated and DateModified have values
- EnsureDates(fileSystem, item, args);
- }
-
- /// <summary>
- /// Ensures the name.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="fileInfo">The file information.</param>
- private static void EnsureName(BaseItem item, FileSystemMetadata fileInfo)
- {
- // If the subclass didn't supply a name, add it here
- if (string.IsNullOrEmpty(item.Name) && !string.IsNullOrEmpty(item.Path))
- {
- item.Name = GetDisplayName(fileInfo.Name, fileInfo.IsDirectory);
- }
- }
-
- /// <summary>
- /// Gets the display name.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="isDirectory">if set to <c>true</c> [is directory].</param>
- /// <returns>System.String.</returns>
- private static string GetDisplayName(string path, bool isDirectory)
- {
- return isDirectory ? Path.GetFileName(path) : Path.GetFileNameWithoutExtension(path);
- }
-
- /// <summary>
- /// The MB name regex
- /// </summary>
- private static readonly Regex MbNameRegex = new Regex(@"(\[.*?\])", RegexOptions.Compiled);
-
- internal static string StripBrackets(string inputString)
- {
- var output = MbNameRegex.Replace(inputString, string.Empty).Trim();
- return Regex.Replace(output, @"\s+", " ");
- }
-
- /// <summary>
- /// Ensures DateCreated and DateModified have values
- /// </summary>
- /// <param name="fileSystem">The file system.</param>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- private static void EnsureDates(IFileSystem fileSystem, BaseItem item, ItemResolveArgs args)
- {
- if (fileSystem == null)
- {
- throw new ArgumentNullException("fileSystem");
- }
- if (item == null)
- {
- throw new ArgumentNullException("item");
- }
- if (args == null)
- {
- throw new ArgumentNullException("args");
- }
-
- // See if a different path came out of the resolver than what went in
- if (!string.Equals(args.Path, item.Path, StringComparison.OrdinalIgnoreCase))
- {
- var childData = args.IsDirectory ? args.GetFileSystemEntryByPath(item.Path) : null;
-
- if (childData != null)
- {
- SetDateCreated(item, fileSystem, childData);
- }
- else
- {
- var fileData = fileSystem.GetFileSystemInfo(item.Path);
-
- if (fileData.Exists)
- {
- SetDateCreated(item, fileSystem, fileData);
- }
- }
- }
- else
- {
- SetDateCreated(item, fileSystem, args.FileInfo);
- }
- }
-
- private static void SetDateCreated(BaseItem item, IFileSystem fileSystem, FileSystemMetadata info)
- {
- var config = BaseItem.ConfigurationManager.GetMetadataConfiguration();
-
- if (config.UseFileCreationTimeForDateAdded)
- {
- item.DateCreated = fileSystem.GetCreationTimeUtc(info);
- }
- else
- {
- item.DateCreated = DateTime.UtcNow;
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
deleted file mode 100644
index 039a17100..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Entities;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
-{
- /// <summary>
- /// Class AudioResolver
- /// </summary>
- public class AudioResolver : ItemResolver<Controller.Entities.Audio.Audio>
- {
- private readonly ILibraryManager _libraryManager;
-
- public AudioResolver(ILibraryManager libraryManager)
- {
- _libraryManager = libraryManager;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get { return ResolverPriority.Last; }
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Entities.Audio.Audio.</returns>
- protected override Controller.Entities.Audio.Audio Resolve(ItemResolveArgs args)
- {
- // Return audio if the path is a file and has a matching extension
-
- if (!args.IsDirectory)
- {
- var libraryOptions = args.GetLibraryOptions();
-
- if (_libraryManager.IsAudioFile(args.Path, libraryOptions))
- {
- var collectionType = args.GetCollectionType();
-
- var isMixed = string.IsNullOrWhiteSpace(collectionType);
-
- // For conflicting extensions, give priority to videos
- if (isMixed && _libraryManager.IsVideoFile(args.Path, libraryOptions))
- {
- return null;
- }
-
- var isStandalone = args.Parent == null;
-
- if (isStandalone ||
- string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase) ||
- isMixed)
- {
- return new Controller.Entities.Audio.Audio();
- }
- }
- }
-
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
deleted file mode 100644
index c1ac7d68c..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
+++ /dev/null
@@ -1,173 +0,0 @@
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Naming.Audio;
-using MediaBrowser.Server.Implementations.Logging;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.Configuration;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
-{
- /// <summary>
- /// Class MusicAlbumResolver
- /// </summary>
- public class MusicAlbumResolver : ItemResolver<MusicAlbum>
- {
- private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
- private readonly ILibraryManager _libraryManager;
-
- public MusicAlbumResolver(ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager)
- {
- _logger = logger;
- _fileSystem = fileSystem;
- _libraryManager = libraryManager;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get
- {
- // Behind special folder resolver
- return ResolverPriority.Second;
- }
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>MusicAlbum.</returns>
- protected override MusicAlbum Resolve(ItemResolveArgs args)
- {
- if (!args.IsDirectory) return null;
-
- // Avoid mis-identifying top folders
- if (args.HasParent<MusicAlbum>()) return null;
- if (args.Parent.IsRoot) return null;
-
- var collectionType = args.GetCollectionType();
-
- var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase);
-
- // If there's a collection type and it's not music, don't allow it.
- if (!isMusicMediaFolder)
- {
- return null;
- }
-
- return IsMusicAlbum(args) ? new MusicAlbum() : null;
- }
-
-
- /// <summary>
- /// Determine if the supplied file data points to a music album
- /// </summary>
- public bool IsMusicAlbum(string path, IDirectoryService directoryService, LibraryOptions libraryOptions)
- {
- return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService, _logger, _fileSystem, libraryOptions, _libraryManager);
- }
-
- /// <summary>
- /// Determine if the supplied resolve args should be considered a music album
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns><c>true</c> if [is music album] [the specified args]; otherwise, <c>false</c>.</returns>
- private bool IsMusicAlbum(ItemResolveArgs args)
- {
- // Args points to an album if parent is an Artist folder or it directly contains music
- if (args.IsDirectory)
- {
- //if (args.Parent is MusicArtist) return true; //saves us from testing children twice
- if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, args.GetLibraryOptions(), _libraryManager)) return true;
- }
-
- return false;
- }
-
- /// <summary>
- /// Determine if the supplied list contains what we should consider music
- /// </summary>
- private bool ContainsMusic(IEnumerable<FileSystemMetadata> list,
- bool allowSubfolders,
- IDirectoryService directoryService,
- ILogger logger,
- IFileSystem fileSystem,
- LibraryOptions libraryOptions,
- ILibraryManager libraryManager)
- {
- var discSubfolderCount = 0;
- var notMultiDisc = false;
-
- foreach (var fileSystemInfo in list)
- {
- if (fileSystemInfo.IsDirectory)
- {
- if (allowSubfolders)
- {
- var path = fileSystemInfo.FullName;
- var isMultiDisc = IsMultiDiscFolder(path, libraryOptions);
-
- if (isMultiDisc)
- {
- var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryOptions, libraryManager);
-
- if (hasMusic)
- {
- logger.Debug("Found multi-disc folder: " + path);
- discSubfolderCount++;
- }
- }
- else
- {
- var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryOptions, libraryManager);
-
- if (hasMusic)
- {
- // If there are folders underneath with music that are not multidisc, then this can't be a multi-disc album
- notMultiDisc = true;
- }
- }
- }
- }
-
- var fullName = fileSystemInfo.FullName;
-
- if (libraryManager.IsAudioFile(fullName, libraryOptions))
- {
- return true;
- }
- }
-
- if (notMultiDisc)
- {
- return false;
- }
-
- return discSubfolderCount > 0;
- }
-
- private bool IsMultiDiscFolder(string path, LibraryOptions libraryOptions)
- {
- var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(libraryOptions);
-
- var parser = new AlbumParser(namingOptions, new PatternsLogger());
- var result = parser.ParseMultiPart(path);
-
- return result.IsMultiPart;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
deleted file mode 100644
index be651b9c8..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
-{
- /// <summary>
- /// Class MusicArtistResolver
- /// </summary>
- public class MusicArtistResolver : ItemResolver<MusicArtist>
- {
- private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
- private readonly ILibraryManager _libraryManager;
- private readonly IServerConfigurationManager _config;
-
- public MusicArtistResolver(ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager, IServerConfigurationManager config)
- {
- _logger = logger;
- _fileSystem = fileSystem;
- _libraryManager = libraryManager;
- _config = config;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get
- {
- // Behind special folder resolver
- return ResolverPriority.Second;
- }
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>MusicArtist.</returns>
- protected override MusicArtist Resolve(ItemResolveArgs args)
- {
- if (!args.IsDirectory) return null;
-
- // Don't allow nested artists
- if (args.HasParent<MusicArtist>() || args.HasParent<MusicAlbum>())
- {
- return null;
- }
-
- var collectionType = args.GetCollectionType();
-
- var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase);
-
- // If there's a collection type and it's not music, it can't be a series
- if (!isMusicMediaFolder)
- {
- return null;
- }
-
- if (args.ContainsFileSystemEntryByName("artist.nfo"))
- {
- return new MusicArtist();
- }
-
- if (_config.Configuration.EnableSimpleArtistDetection)
- {
- return null;
- }
-
- // Avoid mis-identifying top folders
- if (args.Parent.IsRoot) return null;
-
- var directoryService = args.DirectoryService;
-
- var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager);
-
- // If we contain an album assume we are an artist folder
- return args.FileSystemChildren.Where(i => i.IsDirectory).Any(i => albumResolver.IsMusicAlbum(i.FullName, directoryService, args.GetLibraryOptions())) ? new MusicArtist() : null;
- }
-
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
deleted file mode 100644
index 4dce16139..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
+++ /dev/null
@@ -1,297 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Naming.Video;
-using MediaBrowser.Server.Implementations.Logging;
-using System;
-using System.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- /// <summary>
- /// Resolves a Path into a Video or Video subclass
- /// </summary>
- /// <typeparam name="T"></typeparam>
- public abstract class BaseVideoResolver<T> : Controller.Resolvers.ItemResolver<T>
- where T : Video, new()
- {
- protected readonly ILibraryManager LibraryManager;
-
- protected BaseVideoResolver(ILibraryManager libraryManager)
- {
- LibraryManager = libraryManager;
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>`0.</returns>
- protected override T Resolve(ItemResolveArgs args)
- {
- return ResolveVideo<T>(args, false);
- }
-
- /// <summary>
- /// Resolves the video.
- /// </summary>
- /// <typeparam name="TVideoType">The type of the T video type.</typeparam>
- /// <param name="args">The args.</param>
- /// <param name="parseName">if set to <c>true</c> [parse name].</param>
- /// <returns>``0.</returns>
- protected TVideoType ResolveVideo<TVideoType>(ItemResolveArgs args, bool parseName)
- where TVideoType : Video, new()
- {
- var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions();
-
- // If the path is a file check for a matching extensions
- var parser = new Naming.Video.VideoResolver(namingOptions, new PatternsLogger());
-
- if (args.IsDirectory)
- {
- TVideoType video = null;
- VideoFileInfo videoInfo = null;
-
- // Loop through each child file/folder and see if we find a video
- foreach (var child in args.FileSystemChildren)
- {
- var filename = child.Name;
-
- if (child.IsDirectory)
- {
- if (IsDvdDirectory(filename))
- {
- videoInfo = parser.ResolveDirectory(args.Path);
-
- if (videoInfo == null)
- {
- return null;
- }
-
- video = new TVideoType
- {
- Path = args.Path,
- VideoType = VideoType.Dvd,
- ProductionYear = videoInfo.Year
- };
- break;
- }
- if (IsBluRayDirectory(filename))
- {
- videoInfo = parser.ResolveDirectory(args.Path);
-
- if (videoInfo == null)
- {
- return null;
- }
-
- video = new TVideoType
- {
- Path = args.Path,
- VideoType = VideoType.BluRay,
- ProductionYear = videoInfo.Year
- };
- break;
- }
- }
- else if (IsDvdFile(filename))
- {
- videoInfo = parser.ResolveDirectory(args.Path);
-
- if (videoInfo == null)
- {
- return null;
- }
-
- video = new TVideoType
- {
- Path = args.Path,
- VideoType = VideoType.Dvd,
- ProductionYear = videoInfo.Year
- };
- break;
- }
- }
-
- if (video != null)
- {
- video.Name = parseName ?
- videoInfo.Name :
- Path.GetFileName(args.Path);
-
- Set3DFormat(video, videoInfo);
- }
-
- return video;
- }
- else
- {
- var videoInfo = parser.Resolve(args.Path, false, false);
-
- if (videoInfo == null)
- {
- return null;
- }
-
- if (LibraryManager.IsVideoFile(args.Path, args.GetLibraryOptions()) || videoInfo.IsStub)
- {
- var path = args.Path;
-
- var video = new TVideoType
- {
- Path = path,
- IsInMixedFolder = true,
- ProductionYear = videoInfo.Year
- };
-
- SetVideoType(video, videoInfo);
-
- video.Name = parseName ?
- videoInfo.Name :
- Path.GetFileNameWithoutExtension(args.Path);
-
- Set3DFormat(video, videoInfo);
-
- return video;
- }
- }
-
- return null;
- }
-
- protected void SetVideoType(Video video, VideoFileInfo videoInfo)
- {
- var extension = Path.GetExtension(video.Path);
- video.VideoType = string.Equals(extension, ".iso", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(extension, ".img", StringComparison.OrdinalIgnoreCase) ?
- VideoType.Iso :
- VideoType.VideoFile;
-
- video.IsShortcut = string.Equals(extension, ".strm", StringComparison.OrdinalIgnoreCase);
- video.IsPlaceHolder = videoInfo.IsStub;
-
- if (videoInfo.IsStub)
- {
- if (string.Equals(videoInfo.StubType, "dvd", StringComparison.OrdinalIgnoreCase))
- {
- video.VideoType = VideoType.Dvd;
- }
- else if (string.Equals(videoInfo.StubType, "hddvd", StringComparison.OrdinalIgnoreCase))
- {
- video.VideoType = VideoType.HdDvd;
- video.IsHD = true;
- }
- else if (string.Equals(videoInfo.StubType, "bluray", StringComparison.OrdinalIgnoreCase))
- {
- video.VideoType = VideoType.BluRay;
- video.IsHD = true;
- }
- else if (string.Equals(videoInfo.StubType, "hdtv", StringComparison.OrdinalIgnoreCase))
- {
- video.IsHD = true;
- }
- }
-
- SetIsoType(video);
- }
-
- protected void SetIsoType(Video video)
- {
- if (video.VideoType == VideoType.Iso)
- {
- if (video.Path.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1)
- {
- video.IsoType = IsoType.Dvd;
- }
- else if (video.Path.IndexOf("bluray", StringComparison.OrdinalIgnoreCase) != -1)
- {
- video.IsoType = IsoType.BluRay;
- }
- }
- }
-
- protected void Set3DFormat(Video video, bool is3D, string format3D)
- {
- if (is3D)
- {
- if (string.Equals(format3D, "fsbs", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.FullSideBySide;
- }
- else if (string.Equals(format3D, "ftab", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.FullTopAndBottom;
- }
- else if (string.Equals(format3D, "hsbs", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.HalfSideBySide;
- }
- else if (string.Equals(format3D, "htab", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.HalfTopAndBottom;
- }
- else if (string.Equals(format3D, "sbs", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.HalfSideBySide;
- }
- else if (string.Equals(format3D, "sbs3d", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.HalfSideBySide;
- }
- else if (string.Equals(format3D, "tab", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.HalfTopAndBottom;
- }
- else if (string.Equals(format3D, "mvc", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.MVC;
- }
- }
- }
-
- protected void Set3DFormat(Video video, VideoFileInfo videoInfo)
- {
- Set3DFormat(video, videoInfo.Is3D, videoInfo.Format3D);
- }
-
- protected void Set3DFormat(Video video)
- {
- var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions();
-
- var resolver = new Format3DParser(namingOptions, new PatternsLogger());
- var result = resolver.Parse(video.Path);
-
- Set3DFormat(video, result.Is3D, result.Format3D);
- }
-
- /// <summary>
- /// Determines whether [is DVD directory] [the specified directory name].
- /// </summary>
- /// <param name="directoryName">Name of the directory.</param>
- /// <returns><c>true</c> if [is DVD directory] [the specified directory name]; otherwise, <c>false</c>.</returns>
- protected bool IsDvdDirectory(string directoryName)
- {
- return string.Equals(directoryName, "video_ts", StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Determines whether [is DVD file] [the specified name].
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns><c>true</c> if [is DVD file] [the specified name]; otherwise, <c>false</c>.</returns>
- protected bool IsDvdFile(string name)
- {
- return string.Equals(name, "video_ts.ifo", StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Determines whether [is blu ray directory] [the specified directory name].
- /// </summary>
- /// <param name="directoryName">Name of the directory.</param>
- /// <returns><c>true</c> if [is blu ray directory] [the specified directory name]; otherwise, <c>false</c>.</returns>
- protected bool IsBluRayDirectory(string directoryName)
- {
- return string.Equals(directoryName, "bdmv", StringComparison.OrdinalIgnoreCase);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs
deleted file mode 100644
index ff07c5282..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- /// <summary>
- /// Class FolderResolver
- /// </summary>
- public class FolderResolver : FolderResolver<Folder>
- {
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get { return ResolverPriority.Last; }
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Folder.</returns>
- protected override Folder Resolve(ItemResolveArgs args)
- {
- if (args.IsDirectory)
- {
- return new Folder();
- }
-
- return null;
- }
- }
-
- /// <summary>
- /// Class FolderResolver
- /// </summary>
- /// <typeparam name="TItemType">The type of the T item type.</typeparam>
- public abstract class FolderResolver<TItemType> : ItemResolver<TItemType>
- where TItemType : Folder, new()
- {
- /// <summary>
- /// Sets the initial item values.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- protected override void SetInitialItemValues(TItemType item, ItemResolveArgs args)
- {
- base.SetInitialItemValues(item, args);
-
- item.IsRoot = args.Parent == null;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/ItemResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/ItemResolver.cs
deleted file mode 100644
index a03eda263..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/ItemResolver.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- /// <summary>
- /// Class ItemResolver
- /// </summary>
- /// <typeparam name="T"></typeparam>
- public abstract class ItemResolver<T> : IItemResolver
- where T : BaseItem, new()
- {
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>`0.</returns>
- protected virtual T Resolve(ItemResolveArgs args)
- {
- return null;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public virtual ResolverPriority Priority
- {
- get
- {
- return ResolverPriority.First;
- }
- }
-
- /// <summary>
- /// Sets initial values on the newly resolved item
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- protected virtual void SetInitialItemValues(T item, ItemResolveArgs args)
- {
- }
-
- /// <summary>
- /// Resolves the path.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>BaseItem.</returns>
- BaseItem IItemResolver.ResolvePath(ItemResolveArgs args)
- {
- var item = Resolve(args);
-
- if (item != null)
- {
- SetInitialItemValues(item, args);
- }
-
- return item;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs
deleted file mode 100644
index e3447afc9..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using System;
-using System.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
-{
- /// <summary>
- /// Class BoxSetResolver
- /// </summary>
- public class BoxSetResolver : FolderResolver<BoxSet>
- {
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>BoxSet.</returns>
- protected override BoxSet Resolve(ItemResolveArgs args)
- {
- // It's a boxset if all of the following conditions are met:
- // Is a Directory
- // Contains [boxset] in the path
- if (args.IsDirectory)
- {
- var filename = Path.GetFileName(args.Path);
-
- if (string.IsNullOrEmpty(filename))
- {
- return null;
- }
-
- if (filename.IndexOf("[boxset]", StringComparison.OrdinalIgnoreCase) != -1 ||
- args.ContainsFileSystemEntryByName("collection.xml"))
- {
- return new BoxSet
- {
- Path = args.Path,
- Name = ResolverHelper.StripBrackets(Path.GetFileName(args.Path))
- };
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Sets the initial item values.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- protected override void SetInitialItemValues(BoxSet item, ItemResolveArgs args)
- {
- base.SetInitialItemValues(item, args);
-
- SetProviderIdFromPath(item);
- }
-
- /// <summary>
- /// Sets the provider id from path.
- /// </summary>
- /// <param name="item">The item.</param>
- private void SetProviderIdFromPath(BaseItem item)
- {
- //we need to only look at the name of this actual item (not parents)
- var justName = Path.GetFileName(item.Path);
-
- var id = justName.GetAttributeValue("tmdbid");
-
- if (!string.IsNullOrEmpty(id))
- {
- item.SetProviderId(MetadataProviders.Tmdb, id);
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
deleted file mode 100644
index bb1d57688..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ /dev/null
@@ -1,541 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Naming.Video;
-using MediaBrowser.Server.Implementations.Logging;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
-{
- /// <summary>
- /// Class MovieResolver
- /// </summary>
- public class MovieResolver : BaseVideoResolver<Video>, IMultiItemResolver
- {
- public MovieResolver(ILibraryManager libraryManager)
- : base(libraryManager)
- {
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get
- {
- // Give plugins a chance to catch iso's first
- // Also since we have to loop through child files looking for videos,
- // see if we can avoid some of that by letting other resolvers claim folders first
- // Also run after series resolver
- return ResolverPriority.Third;
- }
- }
-
- public MultiItemResolverResult ResolveMultiple(Folder parent,
- List<FileSystemMetadata> files,
- string collectionType,
- IDirectoryService directoryService)
- {
- var result = ResolveMultipleInternal(parent, files, collectionType, directoryService);
-
- if (result != null)
- {
- foreach (var item in result.Items)
- {
- SetInitialItemValues((Video)item, null);
- }
- }
-
- return result;
- }
-
- private MultiItemResolverResult ResolveMultipleInternal(Folder parent,
- List<FileSystemMetadata> files,
- string collectionType,
- IDirectoryService directoryService)
- {
- if (IsInvalid(parent, collectionType))
- {
- return null;
- }
-
- if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
- {
- return ResolveVideos<MusicVideo>(parent, files, directoryService, false);
- }
-
- if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
- string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
- {
- return ResolveVideos<Video>(parent, files, directoryService, false);
- }
-
- if (string.IsNullOrEmpty(collectionType))
- {
- // Owned items should just use the plain video type
- if (parent == null)
- {
- return ResolveVideos<Video>(parent, files, directoryService, false);
- }
-
- if (parent is Series || parent.GetParents().OfType<Series>().Any())
- {
- return null;
- }
-
- return ResolveVideos<Movie>(parent, files, directoryService, false);
- }
-
- if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
- {
- return ResolveVideos<Movie>(parent, files, directoryService, true);
- }
-
- return null;
- }
-
- private MultiItemResolverResult ResolveVideos<T>(Folder parent, IEnumerable<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, bool suppportMultiEditions)
- where T : Video, new()
- {
- var files = new List<FileSystemMetadata>();
- var videos = new List<BaseItem>();
- var leftOver = new List<FileSystemMetadata>();
-
- // Loop through each child file/folder and see if we find a video
- foreach (var child in fileSystemEntries)
- {
- if (child.IsDirectory)
- {
- leftOver.Add(child);
- }
- else if (IsIgnored(child.Name))
- {
-
- }
- else
- {
- files.Add(child);
- }
- }
-
- var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions();
-
- var resolver = new VideoListResolver(namingOptions, new PatternsLogger());
- var resolverResult = resolver.Resolve(files, suppportMultiEditions).ToList();
-
- var result = new MultiItemResolverResult
- {
- ExtraFiles = leftOver,
- Items = videos
- };
-
- var isInMixedFolder = resolverResult.Count > 1;
-
- foreach (var video in resolverResult)
- {
- var firstVideo = video.Files.First();
-
- var videoItem = new T
- {
- Path = video.Files[0].Path,
- IsInMixedFolder = isInMixedFolder,
- ProductionYear = video.Year,
- Name = video.Name,
- AdditionalParts = video.Files.Skip(1).Select(i => i.Path).ToList(),
- LocalAlternateVersions = video.AlternateVersions.Select(i => i.Path).ToList()
- };
-
- SetVideoType(videoItem, firstVideo);
- Set3DFormat(videoItem, firstVideo);
-
- result.Items.Add(videoItem);
- }
-
- result.ExtraFiles.AddRange(files.Where(i => !ContainsFile(resolverResult, i)));
-
- return result;
- }
-
- private bool ContainsFile(List<VideoInfo> result, FileSystemMetadata file)
- {
- return result.Any(i => ContainsFile(i, file));
- }
-
- private bool ContainsFile(VideoInfo result, FileSystemMetadata file)
- {
- return result.Files.Any(i => ContainsFile(i, file)) ||
- result.AlternateVersions.Any(i => ContainsFile(i, file)) ||
- result.Extras.Any(i => ContainsFile(i, file));
- }
-
- private bool ContainsFile(VideoFileInfo result, FileSystemMetadata file)
- {
- return string.Equals(result.Path, file.FullName, StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Video.</returns>
- protected override Video Resolve(ItemResolveArgs args)
- {
- var collectionType = args.GetCollectionType();
-
- if (IsInvalid(args.Parent, collectionType))
- {
- return null;
- }
-
- // Find movies with their own folders
- if (args.IsDirectory)
- {
- var files = args.FileSystemChildren
- .Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
- .ToList();
-
- if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
- {
- return FindMovie<MusicVideo>(args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
- }
-
- if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
- {
- return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
- }
-
- if (string.IsNullOrEmpty(collectionType))
- {
- // Owned items will be caught by the plain video resolver
- if (args.Parent == null)
- {
- //return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
- return null;
- }
-
- if (args.HasParent<Series>())
- {
- return null;
- }
-
- {
- return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
- }
- }
-
- if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
- {
- return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
- }
-
- return null;
- }
-
- // Owned items will be caught by the plain video resolver
- if (args.Parent == null)
- {
- return null;
- }
-
- Video item = null;
-
- if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
- {
- item = ResolveVideo<MusicVideo>(args, false);
- }
-
- // To find a movie file, the collection type must be movies or boxsets
- else if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
- {
- item = ResolveVideo<Movie>(args, true);
- }
-
- else if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
- string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
- {
- item = ResolveVideo<Video>(args, false);
- }
- else if (string.IsNullOrEmpty(collectionType))
- {
- if (args.HasParent<Series>())
- {
- return null;
- }
-
- item = ResolveVideo<Video>(args, false);
- }
-
- if (item != null)
- {
- item.IsInMixedFolder = true;
- }
-
- return item;
- }
-
- private bool IsIgnored(string filename)
- {
- // Ignore samples
- var sampleFilename = " " + filename.Replace(".", " ", StringComparison.OrdinalIgnoreCase)
- .Replace("-", " ", StringComparison.OrdinalIgnoreCase)
- .Replace("_", " ", StringComparison.OrdinalIgnoreCase)
- .Replace("!", " ", StringComparison.OrdinalIgnoreCase);
-
- if (sampleFilename.IndexOf(" sample ", StringComparison.OrdinalIgnoreCase) != -1)
- {
- return true;
- }
-
- return false;
- }
-
- /// <summary>
- /// Sets the initial item values.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- protected override void SetInitialItemValues(Video item, ItemResolveArgs args)
- {
- base.SetInitialItemValues(item, args);
-
- SetProviderIdsFromPath(item);
- }
-
- /// <summary>
- /// Sets the provider id from path.
- /// </summary>
- /// <param name="item">The item.</param>
- private void SetProviderIdsFromPath(Video item)
- {
- if (item is Movie || item is MusicVideo)
- {
- //we need to only look at the name of this actual item (not parents)
- var justName = item.IsInMixedFolder ? Path.GetFileName(item.Path) : Path.GetFileName(item.ContainingFolderPath);
-
- if (!string.IsNullOrWhiteSpace(justName))
- {
- // check for tmdb id
- var tmdbid = justName.GetAttributeValue("tmdbid");
-
- if (!string.IsNullOrWhiteSpace(tmdbid))
- {
- item.SetProviderId(MetadataProviders.Tmdb, tmdbid);
- }
- }
-
- if (!string.IsNullOrWhiteSpace(item.Path))
- {
- // check for imdb id - we use full media path, as we can assume, that this will match in any use case (wither id in parent dir or in file name)
- var imdbid = item.Path.GetAttributeValue("imdbid");
-
- if (!string.IsNullOrWhiteSpace(imdbid))
- {
- item.SetProviderId(MetadataProviders.Imdb, imdbid);
- }
- }
- }
- }
-
- /// <summary>
- /// Finds a movie based on a child file system entries
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <returns>Movie.</returns>
- private T FindMovie<T>(string path, Folder parent, List<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, string collectionType, bool allowFilesAsFolders)
- where T : Video, new()
- {
- var multiDiscFolders = new List<FileSystemMetadata>();
-
- // Search for a folder rip
- foreach (var child in fileSystemEntries)
- {
- var filename = child.Name;
-
- if (child.IsDirectory)
- {
- if (IsDvdDirectory(filename))
- {
- var movie = new T
- {
- Path = path,
- VideoType = VideoType.Dvd
- };
- Set3DFormat(movie);
- return movie;
- }
- if (IsBluRayDirectory(filename))
- {
- var movie = new T
- {
- Path = path,
- VideoType = VideoType.BluRay
- };
- Set3DFormat(movie);
- return movie;
- }
-
- multiDiscFolders.Add(child);
- }
- else if (IsDvdFile(filename))
- {
- var movie = new T
- {
- Path = path,
- VideoType = VideoType.Dvd
- };
- Set3DFormat(movie);
- return movie;
- }
- }
-
- if (allowFilesAsFolders)
- {
- // TODO: Allow GetMultiDiscMovie in here
- var supportsMultiVersion = !string.Equals(collectionType, CollectionType.HomeVideos) &&
- !string.Equals(collectionType, CollectionType.Photos) &&
- !string.Equals(collectionType, CollectionType.MusicVideos);
-
- var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion);
-
- if (result.Items.Count == 1)
- {
- var movie = (T)result.Items[0];
- movie.IsInMixedFolder = false;
- movie.Name = Path.GetFileName(movie.ContainingFolderPath);
- return movie;
- }
-
- if (result.Items.Count == 0 && multiDiscFolders.Count > 0)
- {
- return GetMultiDiscMovie<T>(multiDiscFolders, directoryService);
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Gets the multi disc movie.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="multiDiscFolders">The folders.</param>
- /// <param name="directoryService">The directory service.</param>
- /// <returns>``0.</returns>
- private T GetMultiDiscMovie<T>(List<FileSystemMetadata> multiDiscFolders, IDirectoryService directoryService)
- where T : Video, new()
- {
- var videoTypes = new List<VideoType>();
-
- var folderPaths = multiDiscFolders.Select(i => i.FullName).Where(i =>
- {
- var subFileEntries = directoryService.GetFileSystemEntries(i)
- .ToList();
-
- var subfolders = subFileEntries
- .Where(e => e.IsDirectory)
- .Select(d => d.Name)
- .ToList();
-
- if (subfolders.Any(IsDvdDirectory))
- {
- videoTypes.Add(VideoType.Dvd);
- return true;
- }
- if (subfolders.Any(IsBluRayDirectory))
- {
- videoTypes.Add(VideoType.BluRay);
- return true;
- }
-
- var subFiles = subFileEntries
- .Where(e => !e.IsDirectory)
- .Select(d => d.Name);
-
- if (subFiles.Any(IsDvdFile))
- {
- videoTypes.Add(VideoType.Dvd);
- return true;
- }
-
- return false;
-
- }).OrderBy(i => i).ToList();
-
- // If different video types were found, don't allow this
- if (videoTypes.Distinct().Count() > 1)
- {
- return null;
- }
-
- if (folderPaths.Count == 0)
- {
- return null;
- }
-
- var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions();
- var resolver = new StackResolver(namingOptions, new PatternsLogger());
-
- var result = resolver.ResolveDirectories(folderPaths);
-
- if (result.Stacks.Count != 1)
- {
- return null;
- }
-
- var returnVideo = new T
- {
- Path = folderPaths[0],
-
- AdditionalParts = folderPaths.Skip(1).ToList(),
-
- VideoType = videoTypes[0],
-
- Name = result.Stacks[0].Name
- };
-
- SetIsoType(returnVideo);
-
- return returnVideo;
- }
-
- private bool IsInvalid(Folder parent, string collectionType)
- {
- if (parent != null)
- {
- if (parent.IsRoot)
- {
- return true;
- }
- }
-
- var validCollectionTypes = new[]
- {
- CollectionType.Movies,
- CollectionType.HomeVideos,
- CollectionType.MusicVideos,
- CollectionType.Movies,
- CollectionType.Photos
- };
-
- if (string.IsNullOrWhiteSpace(collectionType))
- {
- return false;
- }
-
- return !validCollectionTypes.Contains(collectionType, StringComparer.OrdinalIgnoreCase);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
deleted file mode 100644
index 957fafb92..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Entities;
-using System;
-using System.IO;
-using System.Linq;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- public class PhotoAlbumResolver : FolderResolver<PhotoAlbum>
- {
- private readonly IImageProcessor _imageProcessor;
- public PhotoAlbumResolver(IImageProcessor imageProcessor)
- {
- _imageProcessor = imageProcessor;
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Trailer.</returns>
- protected override PhotoAlbum Resolve(ItemResolveArgs args)
- {
- // Must be an image file within a photo collection
- if (args.IsDirectory && string.Equals(args.GetCollectionType(), CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
- {
- if (HasPhotos(args))
- {
- return new PhotoAlbum
- {
- Path = args.Path
- };
- }
- }
-
- return null;
- }
-
- private bool HasPhotos(ItemResolveArgs args)
- {
- return args.FileSystemChildren.Any(i => (!i.IsDirectory) && PhotoResolver.IsImageFile(i.FullName, _imageProcessor));
- }
-
- public override ResolverPriority Priority
- {
- get
- {
- // Behind special folder resolver
- return ResolverPriority.Second;
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
deleted file mode 100644
index 549ad522e..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using System;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.Configuration;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- public class PhotoResolver : ItemResolver<Photo>
- {
- private readonly IImageProcessor _imageProcessor;
- private readonly ILibraryManager _libraryManager;
-
- public PhotoResolver(IImageProcessor imageProcessor, ILibraryManager libraryManager)
- {
- _imageProcessor = imageProcessor;
- _libraryManager = libraryManager;
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Trailer.</returns>
- protected override Photo Resolve(ItemResolveArgs args)
- {
- if (!args.IsDirectory)
- {
- // Must be an image file within a photo collection
- var collectionType = args.GetCollectionType();
-
-
- if (string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase) ||
- (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) && args.GetLibraryOptions().EnablePhotos))
- {
- if (IsImageFile(args.Path, _imageProcessor))
- {
- var filename = Path.GetFileNameWithoutExtension(args.Path);
-
- // Make sure the image doesn't belong to a video file
- if (args.DirectoryService.GetFiles(Path.GetDirectoryName(args.Path)).Any(i => IsOwnedByMedia(args.GetLibraryOptions(), i, filename)))
- {
- return null;
- }
-
- return new Photo
- {
- Path = args.Path
- };
- }
- }
- }
-
- return null;
- }
-
- private bool IsOwnedByMedia(LibraryOptions libraryOptions, FileSystemMetadata file, string imageFilename)
- {
- if (_libraryManager.IsVideoFile(file.FullName, libraryOptions) && imageFilename.StartsWith(Path.GetFileNameWithoutExtension(file.Name), StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- return false;
- }
-
- private static readonly string[] IgnoreFiles =
- {
- "folder",
- "thumb",
- "landscape",
- "fanart",
- "backdrop",
- "poster",
- "cover"
- };
-
- internal static bool IsImageFile(string path, IImageProcessor imageProcessor)
- {
- var filename = Path.GetFileNameWithoutExtension(path) ?? string.Empty;
-
- if (IgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase))
- {
- return false;
- }
-
- if (IgnoreFiles.Any(i => filename.IndexOf(i, StringComparison.OrdinalIgnoreCase) != -1))
- {
- return false;
- }
-
- return imageProcessor.SupportedInputFormats.Contains((Path.GetExtension(path) ?? string.Empty).TrimStart('.'), StringComparer.OrdinalIgnoreCase);
- }
-
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PlaylistResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
deleted file mode 100644
index a95739f22..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Playlists;
-using System;
-using System.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- public class PlaylistResolver : FolderResolver<Playlist>
- {
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>BoxSet.</returns>
- protected override Playlist Resolve(ItemResolveArgs args)
- {
- // It's a boxset if all of the following conditions are met:
- // Is a Directory
- // Contains [playlist] in the path
- if (args.IsDirectory)
- {
- var filename = Path.GetFileName(args.Path);
-
- if (string.IsNullOrEmpty(filename))
- {
- return null;
- }
-
- if (filename.IndexOf("[playlist]", StringComparison.OrdinalIgnoreCase) != -1)
- {
- return new Playlist
- {
- Path = args.Path,
- Name = ResolverHelper.StripBrackets(Path.GetFileName(args.Path))
- };
- }
- }
-
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
deleted file mode 100644
index 7a6198a00..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-using System;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- class SpecialFolderResolver : FolderResolver<Folder>
- {
- private readonly IFileSystem _fileSystem;
- private readonly IServerApplicationPaths _appPaths;
-
- public SpecialFolderResolver(IFileSystem fileSystem, IServerApplicationPaths appPaths)
- {
- _fileSystem = fileSystem;
- _appPaths = appPaths;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get { return ResolverPriority.First; }
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Folder.</returns>
- protected override Folder Resolve(ItemResolveArgs args)
- {
- if (args.IsDirectory)
- {
- if (args.IsPhysicalRoot)
- {
- return new AggregateFolder();
- }
- if (string.Equals(args.Path, _appPaths.DefaultUserViewsPath, StringComparison.OrdinalIgnoreCase))
- {
- return new UserRootFolder(); //if we got here and still a root - must be user root
- }
- if (args.IsVf)
- {
- return new CollectionFolder
- {
- CollectionType = GetCollectionType(args),
- PhysicalLocationsList = args.PhysicalLocations.ToList()
- };
- }
- }
-
- return null;
- }
-
- private string GetCollectionType(ItemResolveArgs args)
- {
- return args.FileSystemChildren
- .Where(i =>
- {
-
- try
- {
- return !i.IsDirectory &&
- string.Equals(".collection", i.Extension, StringComparison.OrdinalIgnoreCase);
- }
- catch (IOException)
- {
- return false;
- }
-
- })
- .Select(i => _fileSystem.GetFileNameWithoutExtension(i))
- .FirstOrDefault();
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
deleted file mode 100644
index 6edc4a009..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using System;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using System.Linq;
-using MediaBrowser.Model.Entities;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
-{
- /// <summary>
- /// Class EpisodeResolver
- /// </summary>
- public class EpisodeResolver : BaseVideoResolver<Episode>
- {
- public EpisodeResolver(ILibraryManager libraryManager) : base(libraryManager)
- {
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Episode.</returns>
- protected override Episode Resolve(ItemResolveArgs args)
- {
- var parent = args.Parent;
-
- if (parent == null)
- {
- return null;
- }
-
- var season = parent as Season;
- // Just in case the user decided to nest episodes.
- // Not officially supported but in some cases we can handle it.
- if (season == null)
- {
- season = parent.GetParents().OfType<Season>().FirstOrDefault();
- }
-
- // If the parent is a Season or Series, then this is an Episode if the VideoResolver returns something
- // Also handle flat tv folders
- if (season != null ||
- string.Equals(args.GetCollectionType(), CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) ||
- args.HasParent<Series>())
- {
- var episode = ResolveVideo<Episode>(args, false);
-
- if (episode != null)
- {
- var series = parent as Series;
- if (series == null)
- {
- series = parent.GetParents().OfType<Series>().FirstOrDefault();
- }
-
- if (series != null)
- {
- episode.SeriesId = series.Id;
- episode.SeriesName = series.Name;
- episode.SeriesSortName = series.SortName;
- }
- if (season != null)
- {
- episode.SeasonId = season.Id;
- episode.SeasonName = season.Name;
- }
- }
-
- return episode;
- }
-
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
deleted file mode 100644
index fc4929748..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Naming.Common;
-using MediaBrowser.Naming.TV;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
-{
- /// <summary>
- /// Class SeasonResolver
- /// </summary>
- public class SeasonResolver : FolderResolver<Season>
- {
- /// <summary>
- /// The _config
- /// </summary>
- private readonly IServerConfigurationManager _config;
-
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="SeasonResolver"/> class.
- /// </summary>
- /// <param name="config">The config.</param>
- public SeasonResolver(IServerConfigurationManager config, ILibraryManager libraryManager)
- {
- _config = config;
- _libraryManager = libraryManager;
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Season.</returns>
- protected override Season Resolve(ItemResolveArgs args)
- {
- if (args.Parent is Series && args.IsDirectory)
- {
- var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions();
- var series = ((Series)args.Parent);
-
- var season = new Season
- {
- IndexNumber = new SeasonPathParser(namingOptions, new RegexProvider()).Parse(args.Path, true, true).SeasonNumber,
- SeriesId = series.Id,
- SeriesSortName = series.SortName,
- SeriesName = series.Name
- };
-
- if (season.IndexNumber.HasValue && season.IndexNumber.Value == 0)
- {
- season.Name = _config.Configuration.SeasonZeroDisplayName;
- }
-
- return season;
- }
-
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
deleted file mode 100644
index 83566e2c1..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
+++ /dev/null
@@ -1,251 +0,0 @@
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Naming.Common;
-using MediaBrowser.Naming.TV;
-using MediaBrowser.Server.Implementations.Logging;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.Configuration;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
-{
- /// <summary>
- /// Class SeriesResolver
- /// </summary>
- public class SeriesResolver : FolderResolver<Series>
- {
- private readonly IFileSystem _fileSystem;
- private readonly ILogger _logger;
- private readonly ILibraryManager _libraryManager;
-
- public SeriesResolver(IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager)
- {
- _fileSystem = fileSystem;
- _logger = logger;
- _libraryManager = libraryManager;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get
- {
- return ResolverPriority.Second;
- }
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Series.</returns>
- protected override Series Resolve(ItemResolveArgs args)
- {
- if (args.IsDirectory)
- {
- if (args.HasParent<Series>() || args.HasParent<Season>())
- {
- return null;
- }
-
- var collectionType = args.GetCollectionType();
- if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
- {
- //if (args.ContainsFileSystemEntryByName("tvshow.nfo"))
- //{
- // return new Series
- // {
- // Path = args.Path,
- // Name = Path.GetFileName(args.Path)
- // };
- //}
-
- var configuredContentType = _libraryManager.GetConfiguredContentType(args.Path);
- if (!string.Equals(configuredContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
- {
- return new Series
- {
- Path = args.Path,
- Name = Path.GetFileName(args.Path)
- };
- }
- }
- else if (string.IsNullOrWhiteSpace(collectionType))
- {
- if (args.ContainsFileSystemEntryByName("tvshow.nfo"))
- {
- if (args.Parent.IsRoot)
- {
- // For now, return null, but if we want to allow this in the future then add some additional checks to guard against a misplaced tvshow.nfo
- return null;
- }
-
- return new Series
- {
- Path = args.Path,
- Name = Path.GetFileName(args.Path)
- };
- }
-
- if (args.Parent.IsRoot)
- {
- return null;
- }
-
- if (IsSeriesFolder(args.Path, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager, args.GetLibraryOptions(), false))
- {
- return new Series
- {
- Path = args.Path,
- Name = Path.GetFileName(args.Path)
- };
- }
- }
- }
-
- return null;
- }
-
- public static bool IsSeriesFolder(string path,
- IEnumerable<FileSystemMetadata> fileSystemChildren,
- IDirectoryService directoryService,
- IFileSystem fileSystem,
- ILogger logger,
- ILibraryManager libraryManager,
- LibraryOptions libraryOptions,
- bool isTvContentType)
- {
- foreach (var child in fileSystemChildren)
- {
- //if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
- //{
- // //logger.Debug("Igoring series file or folder marked hidden: {0}", child.FullName);
- // continue;
- //}
-
- // Can't enforce this because files saved by Bitcasa are always marked System
- //if ((attributes & FileAttributes.System) == FileAttributes.System)
- //{
- // logger.Debug("Igoring series subfolder marked system: {0}", child.FullName);
- // continue;
- //}
-
- if (child.IsDirectory)
- {
- if (IsSeasonFolder(child.FullName, isTvContentType, libraryManager))
- {
- //logger.Debug("{0} is a series because of season folder {1}.", path, child.FullName);
- return true;
- }
- }
- else
- {
- string fullName = child.FullName;
- if (libraryManager.IsVideoFile(fullName, libraryOptions))
- {
- if (isTvContentType)
- {
- return true;
- }
-
- var namingOptions = ((LibraryManager)libraryManager).GetNamingOptions();
-
- // In mixed folders we need to be conservative and avoid expressions that may result in false positives (e.g. movies with numbers in the title)
- if (!isTvContentType)
- {
- namingOptions.EpisodeExpressions = namingOptions.EpisodeExpressions
- .Where(i => i.IsNamed && !i.IsOptimistic)
- .ToList();
- }
-
- var episodeResolver = new Naming.TV.EpisodeResolver(namingOptions, new PatternsLogger());
- var episodeInfo = episodeResolver.Resolve(fullName, false, false);
- if (episodeInfo != null && episodeInfo.EpisodeNumber.HasValue)
- {
- return true;
- }
- }
- }
- }
-
- logger.Debug("{0} is not a series folder.", path);
- return false;
- }
-
- /// <summary>
- /// Determines whether [is place holder] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if [is place holder] [the specified path]; otherwise, <c>false</c>.</returns>
- /// <exception cref="System.ArgumentNullException">path</exception>
- private static bool IsVideoPlaceHolder(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var extension = Path.GetExtension(path);
-
- return string.Equals(extension, ".disc", StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Determines whether [is season folder] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="isTvContentType">if set to <c>true</c> [is tv content type].</param>
- /// <param name="libraryManager">The library manager.</param>
- /// <returns><c>true</c> if [is season folder] [the specified path]; otherwise, <c>false</c>.</returns>
- private static bool IsSeasonFolder(string path, bool isTvContentType, ILibraryManager libraryManager)
- {
- var namingOptions = ((LibraryManager)libraryManager).GetNamingOptions();
-
- var seasonNumber = new SeasonPathParser(namingOptions, new RegexProvider()).Parse(path, isTvContentType, isTvContentType).SeasonNumber;
-
- return seasonNumber.HasValue;
- }
-
- /// <summary>
- /// Sets the initial item values.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- protected override void SetInitialItemValues(Series item, ItemResolveArgs args)
- {
- base.SetInitialItemValues(item, args);
-
- SetProviderIdFromPath(item, args.Path);
- }
-
- /// <summary>
- /// Sets the provider id from path.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="path">The path.</param>
- private void SetProviderIdFromPath(Series item, string path)
- {
- var justName = Path.GetFileName(path);
-
- var id = justName.GetAttributeValue("tvdbid");
-
- if (!string.IsNullOrEmpty(id))
- {
- item.SetProviderId(MetadataProviders.Tvdb, id);
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/VideoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/VideoResolver.cs
deleted file mode 100644
index c7f21cef1..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/VideoResolver.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- /// <summary>
- /// Resolves a Path into a Video
- /// </summary>
- public class VideoResolver : BaseVideoResolver<Video>
- {
- public VideoResolver(ILibraryManager libraryManager)
- : base(libraryManager)
- {
- }
-
- protected override Video Resolve(ItemResolveArgs args)
- {
- if (args.Parent != null)
- {
- // The movie resolver will handle this
- return null;
- }
-
- return base.Resolve(args);
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get { return ResolverPriority.Last; }
- }
- }
-
- public class GenericVideoResolver<T> : BaseVideoResolver<T>
- where T : Video, new ()
- {
- public GenericVideoResolver(ILibraryManager libraryManager) : base(libraryManager)
- {
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
deleted file mode 100644
index c266fb191..000000000
--- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
+++ /dev/null
@@ -1,280 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Search;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Extensions;
-using MediaBrowser.Model.Extensions;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- /// <summary>
- /// Class LuceneSearchEngine
- /// http://www.codeproject.com/Articles/320219/Lucene-Net-ultra-fast-search-for-MVC-or-WebForms
- /// </summary>
- public class SearchEngine : ISearchEngine
- {
- private readonly ILibraryManager _libraryManager;
- private readonly IUserManager _userManager;
- private readonly ILogger _logger;
-
- public SearchEngine(ILogManager logManager, ILibraryManager libraryManager, IUserManager userManager)
- {
- _libraryManager = libraryManager;
- _userManager = userManager;
-
- _logger = logManager.GetLogger("Lucene");
- }
-
- public async Task<QueryResult<SearchHintInfo>> GetSearchHints(SearchQuery query)
- {
- User user = null;
-
- if (string.IsNullOrWhiteSpace(query.UserId))
- {
- }
- else
- {
- user = _userManager.GetUserById(query.UserId);
- }
-
- var results = await GetSearchHints(query, user).ConfigureAwait(false);
-
- var searchResultArray = results.ToArray();
- results = searchResultArray;
-
- var count = searchResultArray.Length;
-
- if (query.StartIndex.HasValue)
- {
- results = results.Skip(query.StartIndex.Value);
- }
-
- if (query.Limit.HasValue)
- {
- results = results.Take(query.Limit.Value);
- }
-
- return new QueryResult<SearchHintInfo>
- {
- TotalRecordCount = count,
-
- Items = results.ToArray()
- };
- }
-
- private void AddIfMissing(List<string> list, string value)
- {
- if (!list.Contains(value, StringComparer.OrdinalIgnoreCase))
- {
- list.Add(value);
- }
- }
-
- /// <summary>
- /// Gets the search hints.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="user">The user.</param>
- /// <returns>IEnumerable{SearchHintResult}.</returns>
- /// <exception cref="System.ArgumentNullException">searchTerm</exception>
- private Task<IEnumerable<SearchHintInfo>> GetSearchHints(SearchQuery query, User user)
- {
- var searchTerm = query.SearchTerm;
-
- if (searchTerm != null)
- {
- searchTerm = searchTerm.Trim().RemoveDiacritics();
- }
-
- if (string.IsNullOrWhiteSpace(searchTerm))
- {
- throw new ArgumentNullException("searchTerm");
- }
-
- var terms = GetWords(searchTerm);
-
- var hints = new List<Tuple<BaseItem, string, int>>();
-
- var excludeItemTypes = new List<string>();
- var includeItemTypes = (query.IncludeItemTypes ?? new string[] { }).ToList();
-
- excludeItemTypes.Add(typeof(Year).Name);
- excludeItemTypes.Add(typeof(Folder).Name);
-
- if (query.IncludeGenres && (includeItemTypes.Count == 0 || includeItemTypes.Contains("Genre", StringComparer.OrdinalIgnoreCase)))
- {
- if (!query.IncludeMedia)
- {
- AddIfMissing(includeItemTypes, typeof(Genre).Name);
- AddIfMissing(includeItemTypes, typeof(GameGenre).Name);
- AddIfMissing(includeItemTypes, typeof(MusicGenre).Name);
- }
- }
- else
- {
- AddIfMissing(excludeItemTypes, typeof(Genre).Name);
- AddIfMissing(excludeItemTypes, typeof(GameGenre).Name);
- AddIfMissing(excludeItemTypes, typeof(MusicGenre).Name);
- }
-
- if (query.IncludePeople && (includeItemTypes.Count == 0 || includeItemTypes.Contains("People", StringComparer.OrdinalIgnoreCase) || includeItemTypes.Contains("Person", StringComparer.OrdinalIgnoreCase)))
- {
- if (!query.IncludeMedia)
- {
- AddIfMissing(includeItemTypes, typeof(Person).Name);
- }
- }
- else
- {
- AddIfMissing(excludeItemTypes, typeof(Person).Name);
- }
-
- if (query.IncludeStudios && (includeItemTypes.Count == 0 || includeItemTypes.Contains("Studio", StringComparer.OrdinalIgnoreCase)))
- {
- if (!query.IncludeMedia)
- {
- AddIfMissing(includeItemTypes, typeof(Studio).Name);
- }
- }
- else
- {
- AddIfMissing(excludeItemTypes, typeof(Studio).Name);
- }
-
- if (query.IncludeArtists && (includeItemTypes.Count == 0 || includeItemTypes.Contains("MusicArtist", StringComparer.OrdinalIgnoreCase)))
- {
- if (!query.IncludeMedia)
- {
- AddIfMissing(includeItemTypes, typeof(MusicArtist).Name);
- }
- }
- else
- {
- AddIfMissing(excludeItemTypes, typeof(MusicArtist).Name);
- }
-
- AddIfMissing(excludeItemTypes, typeof(CollectionFolder).Name);
-
- var mediaItems = _libraryManager.GetItemList(new InternalItemsQuery(user)
- {
- NameContains = searchTerm,
- ExcludeItemTypes = excludeItemTypes.ToArray(),
- IncludeItemTypes = includeItemTypes.ToArray(),
- Limit = query.Limit,
- IncludeItemsByName = true,
- IsVirtualItem = false
- });
-
- // Add search hints based on item name
- hints.AddRange(mediaItems.Select(item =>
- {
- var index = GetIndex(item.Name, searchTerm, terms);
-
- return new Tuple<BaseItem, string, int>(item, index.Item1, index.Item2);
- }));
-
- var returnValue = hints.Where(i => i.Item3 >= 0).OrderBy(i => i.Item3).Select(i => new SearchHintInfo
- {
- Item = i.Item1,
- MatchedTerm = i.Item2
- });
-
- return Task.FromResult(returnValue);
- }
-
- /// <summary>
- /// Gets the index.
- /// </summary>
- /// <param name="input">The input.</param>
- /// <param name="searchInput">The search input.</param>
- /// <param name="searchWords">The search input.</param>
- /// <returns>System.Int32.</returns>
- private Tuple<string, int> GetIndex(string input, string searchInput, List<string> searchWords)
- {
- if (string.IsNullOrWhiteSpace(input))
- {
- throw new ArgumentNullException("input");
- }
-
- input = input.RemoveDiacritics();
-
- if (string.Equals(input, searchInput, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, int>(searchInput, 0);
- }
-
- var index = input.IndexOf(searchInput, StringComparison.OrdinalIgnoreCase);
-
- if (index == 0)
- {
- return new Tuple<string, int>(searchInput, 1);
- }
- if (index > 0)
- {
- return new Tuple<string, int>(searchInput, 2);
- }
-
- var items = GetWords(input);
-
- for (var i = 0; i < searchWords.Count; i++)
- {
- var searchTerm = searchWords[i];
-
- for (var j = 0; j < items.Count; j++)
- {
- var item = items[j];
-
- if (string.Equals(item, searchTerm, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, int>(searchTerm, 3 + (i + 1) * (j + 1));
- }
-
- index = item.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase);
-
- if (index == 0)
- {
- return new Tuple<string, int>(searchTerm, 4 + (i + 1) * (j + 1));
- }
- if (index > 0)
- {
- return new Tuple<string, int>(searchTerm, 5 + (i + 1) * (j + 1));
- }
- }
- }
- return new Tuple<string, int>(null, -1);
- }
-
- /// <summary>
- /// Gets the words.
- /// </summary>
- /// <param name="term">The term.</param>
- /// <returns>System.String[][].</returns>
- private List<string> GetWords(string term)
- {
- var stoplist = GetStopList().ToList();
-
- return term.Split()
- .Where(i => !string.IsNullOrWhiteSpace(i) && !stoplist.Contains(i, StringComparer.OrdinalIgnoreCase))
- .ToList();
- }
-
- private IEnumerable<string> GetStopList()
- {
- return new[]
- {
- "the",
- "a",
- "of",
- "an"
- };
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
deleted file mode 100644
index 6a4e26ff9..000000000
--- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
+++ /dev/null
@@ -1,292 +0,0 @@
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Model.Channels;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Library;
-using MediaBrowser.Model.Querying;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Model.Globalization;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- public class UserViewManager : IUserViewManager
- {
- private readonly ILibraryManager _libraryManager;
- private readonly ILocalizationManager _localizationManager;
- private readonly IUserManager _userManager;
-
- private readonly IChannelManager _channelManager;
- private readonly ILiveTvManager _liveTvManager;
- private readonly IServerConfigurationManager _config;
-
- public UserViewManager(ILibraryManager libraryManager, ILocalizationManager localizationManager, IUserManager userManager, IChannelManager channelManager, ILiveTvManager liveTvManager, IServerConfigurationManager config)
- {
- _libraryManager = libraryManager;
- _localizationManager = localizationManager;
- _userManager = userManager;
- _channelManager = channelManager;
- _liveTvManager = liveTvManager;
- _config = config;
- }
-
- public async Task<IEnumerable<Folder>> GetUserViews(UserViewQuery query, CancellationToken cancellationToken)
- {
- var user = _userManager.GetUserById(query.UserId);
-
- var folders = user.RootFolder
- .GetChildren(user, true)
- .OfType<Folder>()
- .ToList();
-
- if (!query.IncludeHidden)
- {
- folders = folders.Where(i =>
- {
- var hidden = i as IHiddenFromDisplay;
- return hidden == null || !hidden.IsHiddenFromUser(user);
- }).ToList();
- }
-
- var plainFolderIds = user.Configuration.PlainFolderViews.Select(i => new Guid(i)).ToList();
-
- var groupedFolders = new List<ICollectionFolder>();
-
- var list = new List<Folder>();
-
- foreach (var folder in folders)
- {
- var collectionFolder = folder as ICollectionFolder;
- var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType;
-
- if (UserView.IsUserSpecific(folder))
- {
- list.Add(await _libraryManager.GetNamedView(user, folder.Name, folder.Id.ToString("N"), folderViewType, null, cancellationToken).ConfigureAwait(false));
- continue;
- }
-
- if (plainFolderIds.Contains(folder.Id) && UserView.IsEligibleForEnhancedView(folderViewType))
- {
- list.Add(folder);
- continue;
- }
-
- if (collectionFolder != null && UserView.IsEligibleForGrouping(folder) && user.IsFolderGrouped(folder.Id))
- {
- groupedFolders.Add(collectionFolder);
- continue;
- }
-
- if (query.PresetViews.Contains(folderViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
- {
- list.Add(await GetUserView(folder, folderViewType, string.Empty, cancellationToken).ConfigureAwait(false));
- }
- else
- {
- list.Add(folder);
- }
- }
-
- foreach (var viewType in new[] { CollectionType.Movies, CollectionType.TvShows })
- {
- var parents = groupedFolders.Where(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType))
- .ToList();
-
- if (parents.Count > 0)
- {
- list.Add(await GetUserView(parents, viewType, string.Empty, user, query.PresetViews, cancellationToken).ConfigureAwait(false));
- }
- }
-
- if (_config.Configuration.EnableFolderView)
- {
- var name = _localizationManager.GetLocalizedString("ViewType" + CollectionType.Folders);
- list.Add(await _libraryManager.GetNamedView(name, CollectionType.Folders, string.Empty, cancellationToken).ConfigureAwait(false));
- }
-
- if (query.IncludeExternalContent)
- {
- var channelResult = await _channelManager.GetChannelsInternal(new ChannelQuery
- {
- UserId = query.UserId
-
- }, cancellationToken).ConfigureAwait(false);
-
- var channels = channelResult.Items;
-
- if (_config.Configuration.EnableChannelView && channels.Length > 0)
- {
- list.Add(await _channelManager.GetInternalChannelFolder(cancellationToken).ConfigureAwait(false));
- }
- else
- {
- list.AddRange(channels);
- }
-
- if (_liveTvManager.GetEnabledUsers().Select(i => i.Id.ToString("N")).Contains(query.UserId))
- {
- list.Add(await _liveTvManager.GetInternalLiveTvFolder(CancellationToken.None).ConfigureAwait(false));
- }
- }
-
- var sorted = _libraryManager.Sort(list, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).ToList();
-
- var orders = user.Configuration.OrderedViews.ToList();
-
- return list
- .OrderBy(i =>
- {
- var index = orders.IndexOf(i.Id.ToString("N"));
-
- if (index == -1)
- {
- var view = i as UserView;
- if (view != null)
- {
- if (view.DisplayParentId != Guid.Empty)
- {
- index = orders.IndexOf(view.DisplayParentId.ToString("N"));
- }
- }
- }
-
- return index == -1 ? int.MaxValue : index;
- })
- .ThenBy(sorted.IndexOf)
- .ThenBy(i => i.SortName);
- }
-
- public Task<UserView> GetUserSubView(string name, string parentId, string type, string sortName, CancellationToken cancellationToken)
- {
- var uniqueId = parentId + "subview" + type;
-
- return _libraryManager.GetNamedView(name, parentId, type, sortName, uniqueId, cancellationToken);
- }
-
- public Task<UserView> GetUserSubView(string parentId, string type, string sortName, CancellationToken cancellationToken)
- {
- var name = _localizationManager.GetLocalizedString("ViewType" + type);
-
- return GetUserSubView(name, parentId, type, sortName, cancellationToken);
- }
-
- private async Task<Folder> GetUserView(List<ICollectionFolder> parents, string viewType, string sortName, User user, string[] presetViews, CancellationToken cancellationToken)
- {
- if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase)))
- {
- if (!presetViews.Contains(viewType, StringComparer.OrdinalIgnoreCase))
- {
- return (Folder)parents[0];
- }
-
- return await GetUserView((Folder)parents[0], viewType, string.Empty, cancellationToken).ConfigureAwait(false);
- }
-
- var name = _localizationManager.GetLocalizedString("ViewType" + viewType);
- return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
- }
-
- public Task<UserView> GetUserView(Folder parent, string viewType, string sortName, CancellationToken cancellationToken)
- {
- return _libraryManager.GetShadowView(parent, viewType, sortName, cancellationToken);
- }
-
- public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request)
- {
- var user = _userManager.GetUserById(request.UserId);
-
- var libraryItems = GetItemsForLatestItems(user, request);
-
- var list = new List<Tuple<BaseItem, List<BaseItem>>>();
-
- foreach (var item in libraryItems)
- {
- // Only grab the index container for media
- var container = item.IsFolder || !request.GroupItems ? null : item.LatestItemsIndexContainer;
-
- if (container == null)
- {
- list.Add(new Tuple<BaseItem, List<BaseItem>>(null, new List<BaseItem> { item }));
- }
- else
- {
- var current = list.FirstOrDefault(i => i.Item1 != null && i.Item1.Id == container.Id);
-
- if (current != null)
- {
- current.Item2.Add(item);
- }
- else
- {
- list.Add(new Tuple<BaseItem, List<BaseItem>>(container, new List<BaseItem> { item }));
- }
- }
-
- if (list.Count >= request.Limit)
- {
- break;
- }
- }
-
- return list;
- }
-
- private IEnumerable<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request)
- {
- var parentId = request.ParentId;
-
- var includeItemTypes = request.IncludeItemTypes;
- var limit = request.Limit ?? 10;
-
- var parentIds = string.IsNullOrEmpty(parentId)
- ? new string[] { }
- : new[] { parentId };
-
- if (parentIds.Length == 0)
- {
- parentIds = user.RootFolder.GetChildren(user, true)
- .OfType<Folder>()
- .Select(i => i.Id.ToString("N"))
- .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i))
- .ToArray();
- }
-
- if (parentIds.Length == 0)
- {
- return new List<BaseItem>();
- }
-
- var excludeItemTypes = includeItemTypes.Length == 0 ? new[]
- {
- typeof(Person).Name,
- typeof(Studio).Name,
- typeof(Year).Name,
- typeof(GameGenre).Name,
- typeof(MusicGenre).Name,
- typeof(Genre).Name
-
- } : new string[] { };
-
- return _libraryManager.GetItemList(new InternalItemsQuery(user)
- {
- IncludeItemTypes = includeItemTypes,
- SortOrder = SortOrder.Descending,
- SortBy = new[] { ItemSortBy.DateCreated },
- IsFolder = includeItemTypes.Length == 0 ? false : (bool?)null,
- ExcludeItemTypes = excludeItemTypes,
- ExcludeLocationTypes = new[] { LocationType.Virtual },
- Limit = limit * 5,
- SourceTypes = parentIds.Length == 0 ? new[] { SourceType.Library } : new SourceType[] { },
- IsPlayed = request.IsPlayed
-
- }, parentIds);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs
deleted file mode 100644
index 91b035a35..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- /// <summary>
- /// Class ArtistsPostScanTask
- /// </summary>
- public class ArtistsPostScanTask : ILibraryPostScanTask
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- public ArtistsPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- return new ArtistsValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs
deleted file mode 100644
index 3dcdbeae9..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- /// <summary>
- /// Class ArtistsValidator
- /// </summary>
- public class ArtistsValidator
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="logger">The logger.</param>
- public ArtistsValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var names = _itemRepo.GetAllArtistNames();
-
- var numComplete = 0;
- var count = names.Count;
-
- foreach (var name in names)
- {
- try
- {
- var item = _libraryManager.GetArtist(name);
-
- await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- // Don't clutter the log
- break;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing {0}", ex, name);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= count;
- percent *= 100;
-
- progress.Report(percent);
- }
-
- progress.Report(100);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs
deleted file mode 100644
index f3891180e..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- /// <summary>
- /// Class GameGenresPostScanTask
- /// </summary>
- public class GameGenresPostScanTask : ILibraryPostScanTask
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="GameGenresPostScanTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="logger">The logger.</param>
- public GameGenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- return new GameGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs
deleted file mode 100644
index b06c0b3b9..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- class GameGenresValidator
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- public GameGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var names = _itemRepo.GetGameGenreNames();
-
- var numComplete = 0;
- var count = names.Count;
-
- foreach (var name in names)
- {
- try
- {
- var item = _libraryManager.GetGameGenre(name);
-
- await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- // Don't clutter the log
- break;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing {0}", ex, name);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= count;
- percent *= 100;
-
- progress.Report(percent);
- }
-
- progress.Report(100);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs
deleted file mode 100644
index ed2429769..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using MediaBrowser.Controller.Library;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- public class GenresPostScanTask : ILibraryPostScanTask
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="logger">The logger.</param>
- public GenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- return new GenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs
deleted file mode 100644
index f35bb5136..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- class GenresValidator
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
-
- public GenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var names = _itemRepo.GetGenreNames();
-
- var numComplete = 0;
- var count = names.Count;
-
- foreach (var name in names)
- {
- try
- {
- var item = _libraryManager.GetGenre(name);
-
- await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- // Don't clutter the log
- break;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing {0}", ex, name);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= count;
- percent *= 100;
-
- progress.Report(percent);
- }
-
- progress.Report(100);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs
deleted file mode 100644
index 777532ff8..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- /// <summary>
- /// Class MusicGenresPostScanTask
- /// </summary>
- public class MusicGenresPostScanTask : ILibraryPostScanTask
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="logger">The logger.</param>
- public MusicGenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- return new MusicGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs
deleted file mode 100644
index 2be99f106..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- class MusicGenresValidator
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- public MusicGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var names = _itemRepo.GetMusicGenreNames();
-
- var numComplete = 0;
- var count = names.Count;
-
- foreach (var name in names)
- {
- try
- {
- var item = _libraryManager.GetMusicGenre(name);
-
- await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- // Don't clutter the log
- break;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing {0}", ex, name);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= count;
- percent *= 100;
-
- progress.Report(percent);
- }
-
- progress.Report(100);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
deleted file mode 100644
index d9a7199be..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
+++ /dev/null
@@ -1,172 +0,0 @@
-using MediaBrowser.Common.Progress;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- /// <summary>
- /// Class PeopleValidator
- /// </summary>
- public class PeopleValidator
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
-
- private readonly IServerConfigurationManager _config;
- private readonly IFileSystem _fileSystem;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="PeopleValidator" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="logger">The logger.</param>
- public PeopleValidator(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _config = config;
- _fileSystem = fileSystem;
- }
-
- private bool DownloadMetadata(PersonInfo i, PeopleMetadataOptions options)
- {
- if (i.IsType(PersonType.Actor))
- {
- return options.DownloadActorMetadata;
- }
- if (i.IsType(PersonType.Director))
- {
- return options.DownloadDirectorMetadata;
- }
- if (i.IsType(PersonType.Composer))
- {
- return options.DownloadComposerMetadata;
- }
- if (i.IsType(PersonType.Writer))
- {
- return options.DownloadWriterMetadata;
- }
- if (i.IsType(PersonType.Producer))
- {
- return options.DownloadProducerMetadata;
- }
- if (i.IsType(PersonType.GuestStar))
- {
- return options.DownloadGuestStarMetadata;
- }
-
- return options.DownloadOtherPeopleMetadata;
- }
-
- /// <summary>
- /// Validates the people.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
- {
- var innerProgress = new ActionableProgress<double>();
-
- innerProgress.RegisterAction(pct => progress.Report(pct * .15));
-
- var peopleOptions = _config.Configuration.PeopleMetadataOptions;
-
- var people = _libraryManager.GetPeople(new InternalPeopleQuery());
-
- var dict = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
-
- foreach (var person in people)
- {
- var isMetadataEnabled = DownloadMetadata(person, peopleOptions);
-
- bool currentValue;
- if (dict.TryGetValue(person.Name, out currentValue))
- {
- if (!currentValue && isMetadataEnabled)
- {
- dict[person.Name] = true;
- }
- }
- else
- {
- dict[person.Name] = isMetadataEnabled;
- }
- }
-
- var numComplete = 0;
-
- _logger.Debug("Will refresh {0} people", dict.Count);
-
- var numPeople = dict.Count;
-
- foreach (var person in dict)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- try
- {
- var item = _libraryManager.GetPerson(person.Key);
-
- var hasMetdata = !string.IsNullOrWhiteSpace(item.Overview);
- var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 30;
-
- var defaultMetadataRefreshMode = performFullRefresh
- ? MetadataRefreshMode.FullRefresh
- : MetadataRefreshMode.Default;
-
- var imageRefreshMode = performFullRefresh
- ? ImageRefreshMode.FullRefresh
- : ImageRefreshMode.Default;
-
- var options = new MetadataRefreshOptions(_fileSystem)
- {
- MetadataRefreshMode = person.Value ? defaultMetadataRefreshMode : MetadataRefreshMode.ValidationOnly,
- ImageRefreshMode = person.Value ? imageRefreshMode : ImageRefreshMode.ValidationOnly,
- ForceSave = performFullRefresh
- };
-
- await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- throw;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error validating IBN entry {0}", ex, person);
- }
-
- // Update progress
- numComplete++;
- double percent = numComplete;
- percent /= numPeople;
-
- progress.Report(100 * percent);
- }
-
- progress.Report(100);
-
- _logger.Info("People validation complete");
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs
deleted file mode 100644
index 77c6d5146..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- /// <summary>
- /// Class MusicGenresPostScanTask
- /// </summary>
- public class StudiosPostScanTask : ILibraryPostScanTask
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- public StudiosPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- return new StudiosValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
deleted file mode 100644
index a19b8158a..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- class StudiosValidator
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- private readonly IItemRepository _itemRepo;
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
-
- public StudiosValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var names = _itemRepo.GetStudioNames();
-
- var numComplete = 0;
- var count = names.Count;
-
- foreach (var name in names)
- {
- try
- {
- var item = _libraryManager.GetStudio(name);
-
- await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- // Don't clutter the log
- break;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing {0}", ex, name);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= count;
- percent *= 100;
-
- progress.Report(percent);
- }
-
- progress.Report(100);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs
deleted file mode 100644
index 164b14223..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- public class YearsPostScanTask : ILibraryPostScanTask
- {
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
-
- public YearsPostScanTask(ILibraryManager libraryManager, ILogger logger)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- }
-
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var yearNumber = 1900;
- var maxYear = DateTime.UtcNow.Year + 3;
- var count = maxYear - yearNumber + 1;
- var numComplete = 0;
-
- while (yearNumber < maxYear)
- {
- try
- {
- var year = _libraryManager.GetYear(yearNumber);
-
- await year.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- // Don't clutter the log
- break;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing year {0}", ex, yearNumber);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= count;
- percent *= 100;
-
- progress.Report(percent);
- yearNumber++;
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 397e5fc9f..1e5f760ca 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -15,7 +15,6 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Server.Implementations.FileOrganization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -1528,28 +1527,28 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private async void OnSuccessfulRecording(TimerInfo timer, string path)
{
- if (timer.IsProgramSeries && GetConfiguration().EnableAutoOrganize)
- {
- try
- {
- // this is to account for the library monitor holding a lock for additional time after the change is complete.
- // ideally this shouldn't be hard-coded
- await Task.Delay(30000).ConfigureAwait(false);
-
- var organize = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager);
-
- var result = await organize.OrganizeEpisodeFile(path, _config.GetAutoOrganizeOptions(), false, CancellationToken.None).ConfigureAwait(false);
-
- if (result.Status == FileSortingStatus.Success)
- {
- return;
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error processing new recording", ex);
- }
- }
+ //if (timer.IsProgramSeries && GetConfiguration().EnableAutoOrganize)
+ //{
+ // try
+ // {
+ // // this is to account for the library monitor holding a lock for additional time after the change is complete.
+ // // ideally this shouldn't be hard-coded
+ // await Task.Delay(30000).ConfigureAwait(false);
+
+ // var organize = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager);
+
+ // var result = await organize.OrganizeEpisodeFile(path, _config.GetAutoOrganizeOptions(), false, CancellationToken.None).ConfigureAwait(false);
+
+ // if (result.Status == FileSortingStatus.Success)
+ // {
+ // return;
+ // }
+ // }
+ // catch (Exception ex)
+ // {
+ // _logger.ErrorException("Error processing new recording", ex);
+ // }
+ //}
}
private void SaveNfo(TimerInfo timer, string recordingPath, string seriesPath)
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 037c6bd0c..fc71ef8a0 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -108,7 +108,6 @@
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
- <Compile Include="Activity\ActivityManager.cs" />
<Compile Include="Activity\ActivityRepository.cs" />
<Compile Include="Archiving\ZipClient.cs" />
<Compile Include="Collections\CollectionsDynamicFolder.cs" />
@@ -122,7 +121,6 @@
<Compile Include="Devices\DeviceManager.cs" />
<Compile Include="Devices\DeviceRepository.cs" />
<Compile Include="Devices\CameraUploadsFolder.cs" />
- <Compile Include="Dto\DtoService.cs" />
<Compile Include="EntryPoints\ActivityLogEntryPoint.cs" />
<Compile Include="EntryPoints\AutomaticRestartEntryPoint.cs" />
<Compile Include="EntryPoints\ExternalPortForwarding.cs" />
@@ -134,16 +132,9 @@
<Compile Include="EntryPoints\RefreshUsersMetadata.cs" />
<Compile Include="EntryPoints\UsageEntryPoint.cs" />
<Compile Include="EntryPoints\UsageReporter.cs" />
- <Compile Include="FileOrganization\EpisodeFileOrganizer.cs" />
- <Compile Include="FileOrganization\Extensions.cs" />
- <Compile Include="FileOrganization\FileOrganizationNotifier.cs" />
- <Compile Include="FileOrganization\FileOrganizationService.cs" />
- <Compile Include="FileOrganization\NameUtils.cs" />
- <Compile Include="FileOrganization\TvFolderOrganizer.cs" />
<Compile Include="EntryPoints\UdpServerEntryPoint.cs" />
<Compile Include="EntryPoints\ServerEventNotifier.cs" />
<Compile Include="EntryPoints\UserDataChangeNotifier.cs" />
- <Compile Include="FileOrganization\OrganizerScheduledTask.cs" />
<Compile Include="HttpServer\IHttpListener.cs" />
<Compile Include="HttpServer\Security\AuthorizationContext.cs" />
<Compile Include="HttpServer\ContainerAdapter.cs" />
@@ -171,45 +162,8 @@
<Compile Include="IO\LibraryMonitor.cs" />
<Compile Include="IO\MemoryStreamProvider.cs" />
<Compile Include="IO\ThrottledStream.cs" />
- <Compile Include="Library\CoreResolutionIgnoreRule.cs" />
- <Compile Include="Library\LibraryManager.cs" />
- <Compile Include="Library\LocalTrailerPostScanTask.cs" />
- <Compile Include="Library\MediaSourceManager.cs" />
- <Compile Include="Library\MusicManager.cs" />
- <Compile Include="Library\PathExtensions.cs" />
- <Compile Include="Library\Resolvers\SpecialFolderResolver.cs" />
- <Compile Include="Library\Resolvers\BaseVideoResolver.cs" />
- <Compile Include="Library\Resolvers\PhotoAlbumResolver.cs" />
- <Compile Include="Library\Resolvers\PhotoResolver.cs" />
- <Compile Include="Library\Resolvers\PlaylistResolver.cs" />
- <Compile Include="Library\SearchEngine.cs" />
- <Compile Include="Library\ResolverHelper.cs" />
- <Compile Include="Library\Resolvers\Audio\AudioResolver.cs" />
- <Compile Include="Library\Resolvers\Audio\MusicAlbumResolver.cs" />
- <Compile Include="Library\Resolvers\Audio\MusicArtistResolver.cs" />
- <Compile Include="Library\Resolvers\ItemResolver.cs" />
- <Compile Include="Library\Resolvers\FolderResolver.cs" />
- <Compile Include="Library\Resolvers\Movies\BoxSetResolver.cs" />
- <Compile Include="Library\Resolvers\Movies\MovieResolver.cs" />
- <Compile Include="Library\Resolvers\TV\EpisodeResolver.cs" />
- <Compile Include="Library\Resolvers\TV\SeasonResolver.cs" />
- <Compile Include="Library\Resolvers\TV\SeriesResolver.cs" />
- <Compile Include="Library\Resolvers\VideoResolver.cs" />
<Compile Include="Library\UserDataManager.cs" />
<Compile Include="Library\UserManager.cs" />
- <Compile Include="Library\UserViewManager.cs" />
- <Compile Include="Library\Validators\ArtistsPostScanTask.cs" />
- <Compile Include="Library\Validators\ArtistsValidator.cs" />
- <Compile Include="Library\Validators\GameGenresPostScanTask.cs" />
- <Compile Include="Library\Validators\GameGenresValidator.cs" />
- <Compile Include="Library\Validators\GenresPostScanTask.cs" />
- <Compile Include="Library\Validators\GenresValidator.cs" />
- <Compile Include="Library\Validators\MusicGenresPostScanTask.cs" />
- <Compile Include="Library\Validators\MusicGenresValidator.cs" />
- <Compile Include="Library\Validators\PeopleValidator.cs" />
- <Compile Include="Library\Validators\StudiosPostScanTask.cs" />
- <Compile Include="Library\Validators\StudiosValidator.cs" />
- <Compile Include="Library\Validators\YearsPostScanTask.cs" />
<Compile Include="LiveTv\ChannelImageProvider.cs" />
<Compile Include="LiveTv\EmbyTV\DirectRecorder.cs" />
<Compile Include="LiveTv\EmbyTV\EmbyTV.cs" />
@@ -267,19 +221,16 @@
<Compile Include="News\NewsEntryPoint.cs" />
<Compile Include="Notifications\IConfigurableNotificationService.cs" />
<Compile Include="Persistence\BaseSqliteRepository.cs" />
- <Compile Include="Persistence\CleanDatabaseScheduledTask.cs" />
<Compile Include="Persistence\DataExtensions.cs" />
<Compile Include="Persistence\IDbConnector.cs" />
<Compile Include="Persistence\MediaStreamColumns.cs" />
<Compile Include="Reflection\AssemblyInfo.cs" />
- <Compile Include="ScheduledTasks\RefreshMediaLibraryTask.cs" />
<Compile Include="Security\MBLicenseFile.cs" />
<Compile Include="Security\PluginSecurityManager.cs" />
<Compile Include="Security\RegRecord.cs" />
<Compile Include="Serialization\JsonSerializer.cs" />
<Compile Include="Social\SharingManager.cs" />
<Compile Include="Social\SharingRepository.cs" />
- <Compile Include="Sorting\StartDateComparer.cs" />
<Compile Include="Sync\SyncHelper.cs" />
<Compile Include="Sync\SyncJobOptions.cs" />
<Compile Include="Sync\SyncNotificationEntryPoint.cs" />
@@ -311,40 +262,10 @@
</Compile>
<Compile Include="Session\SessionWebSocketListener.cs" />
<Compile Include="Session\WebSocketController.cs" />
- <Compile Include="Sorting\AiredEpisodeOrderComparer.cs" />
- <Compile Include="Sorting\AirTimeComparer.cs" />
- <Compile Include="Sorting\AlbumArtistComparer.cs" />
- <Compile Include="Sorting\AlbumComparer.cs" />
- <Compile Include="Sorting\AlphanumComparator.cs" />
- <Compile Include="Sorting\ArtistComparer.cs" />
- <Compile Include="Sorting\BudgetComparer.cs" />
- <Compile Include="Sorting\CommunityRatingComparer.cs" />
- <Compile Include="Sorting\CriticRatingComparer.cs" />
- <Compile Include="Sorting\DateCreatedComparer.cs" />
- <Compile Include="Sorting\DateLastMediaAddedComparer.cs" />
- <Compile Include="Sorting\DatePlayedComparer.cs" />
- <Compile Include="Sorting\GameSystemComparer.cs" />
- <Compile Include="Sorting\IsFavoriteOrLikeComparer.cs" />
- <Compile Include="Sorting\IsFolderComparer.cs" />
- <Compile Include="Sorting\IsPlayedComparer.cs" />
- <Compile Include="Sorting\IsUnplayedComparer.cs" />
- <Compile Include="Sorting\MetascoreComparer.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\SeriesSortNameComparer.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\StudioComparer.cs" />
<Compile Include="Sync\AppSyncProvider.cs" />
<Compile Include="Sync\CloudSyncProfile.cs" />
<Compile Include="Sync\IHasSyncQuality.cs" />
diff --git a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
deleted file mode 100644
index ed1d21d9a..000000000
--- a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
+++ /dev/null
@@ -1,360 +0,0 @@
-using MediaBrowser.Common.Progress;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Globalization;
-using MediaBrowser.Model.Tasks;
-using MediaBrowser.Server.Implementations.ScheduledTasks;
-
-namespace MediaBrowser.Server.Implementations.Persistence
-{
- public class CleanDatabaseScheduledTask : IScheduledTask
- {
- private readonly ILibraryManager _libraryManager;
- private readonly IItemRepository _itemRepo;
- private readonly ILogger _logger;
- private readonly IServerConfigurationManager _config;
- private readonly IFileSystem _fileSystem;
- private readonly IHttpServer _httpServer;
- private readonly ILocalizationManager _localization;
- private readonly ITaskManager _taskManager;
-
- public const int MigrationVersion = 23;
- public static bool EnableUnavailableMessage = false;
-
- public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem, IHttpServer httpServer, ILocalizationManager localization, ITaskManager taskManager)
- {
- _libraryManager = libraryManager;
- _itemRepo = itemRepo;
- _logger = logger;
- _config = config;
- _fileSystem = fileSystem;
- _httpServer = httpServer;
- _localization = localization;
- _taskManager = taskManager;
- }
-
- public string Name
- {
- get { return "Clean Database"; }
- }
-
- public string Description
- {
- get { return "Deletes obsolete content from the database."; }
- }
-
- public string Category
- {
- get { return "Library"; }
- }
-
- public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
- {
- OnProgress(0);
-
- // Ensure these objects are lazy loaded.
- // Without this there is a deadlock that will need to be investigated
- var rootChildren = _libraryManager.RootFolder.Children.ToList();
- rootChildren = _libraryManager.GetUserRootFolder().Children.ToList();
-
- var innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(p =>
- {
- double newPercentCommplete = .4 * p;
- OnProgress(newPercentCommplete);
-
- progress.Report(newPercentCommplete);
- });
-
- await UpdateToLatestSchema(cancellationToken, innerProgress).ConfigureAwait(false);
-
- innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(p =>
- {
- double newPercentCommplete = 40 + .05 * p;
- OnProgress(newPercentCommplete);
- progress.Report(newPercentCommplete);
- });
- await CleanDeadItems(cancellationToken, innerProgress).ConfigureAwait(false);
- progress.Report(45);
-
- innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(p =>
- {
- double newPercentCommplete = 45 + .55 * p;
- OnProgress(newPercentCommplete);
- progress.Report(newPercentCommplete);
- });
- await CleanDeletedItems(cancellationToken, innerProgress).ConfigureAwait(false);
- progress.Report(100);
-
- await _itemRepo.UpdateInheritedValues(cancellationToken).ConfigureAwait(false);
-
- if (_config.Configuration.MigrationVersion < MigrationVersion)
- {
- _config.Configuration.MigrationVersion = MigrationVersion;
- _config.SaveConfiguration();
- }
-
- if (_config.Configuration.SchemaVersion < SqliteItemRepository.LatestSchemaVersion)
- {
- _config.Configuration.SchemaVersion = SqliteItemRepository.LatestSchemaVersion;
- _config.SaveConfiguration();
- }
-
- if (EnableUnavailableMessage)
- {
- EnableUnavailableMessage = false;
- _httpServer.GlobalResponse = null;
- _taskManager.QueueScheduledTask<RefreshMediaLibraryTask>();
- }
-
- _taskManager.SuspendTriggers = false;
- }
-
- private void OnProgress(double newPercentCommplete)
- {
- if (EnableUnavailableMessage)
- {
- var html = "<!doctype html><html><head><title>Emby</title></head><body>";
- var text = _localization.GetLocalizedString("DbUpgradeMessage");
- html += string.Format(text, newPercentCommplete.ToString("N2", CultureInfo.InvariantCulture));
-
- html += "<script>setTimeout(function(){window.location.reload(true);}, 5000);</script>";
- html += "</body></html>";
-
- _httpServer.GlobalResponse = html;
- }
- }
-
- private async Task UpdateToLatestSchema(CancellationToken cancellationToken, IProgress<double> progress)
- {
- var itemIds = _libraryManager.GetItemIds(new InternalItemsQuery
- {
- IsCurrentSchema = false,
- ExcludeItemTypes = new[] { typeof(LiveTvProgram).Name }
- });
-
- var numComplete = 0;
- var numItems = itemIds.Count;
-
- _logger.Debug("Upgrading schema for {0} items", numItems);
-
- var list = new List<BaseItem>();
-
- foreach (var itemId in itemIds)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- if (itemId != Guid.Empty)
- {
- // Somehow some invalid data got into the db. It probably predates the boundary checking
- var item = _libraryManager.GetItemById(itemId);
-
- if (item != null)
- {
- list.Add(item);
- }
- }
-
- if (list.Count >= 1000)
- {
- try
- {
- await _itemRepo.SaveItems(list, cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- throw;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving item", ex);
- }
-
- list.Clear();
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= numItems;
- progress.Report(percent * 100);
- }
-
- if (list.Count > 0)
- {
- try
- {
- await _itemRepo.SaveItems(list, cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- throw;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving item", ex);
- }
- }
-
- progress.Report(100);
- }
-
- private async Task CleanDeadItems(CancellationToken cancellationToken, IProgress<double> progress)
- {
- var itemIds = _libraryManager.GetItemIds(new InternalItemsQuery
- {
- HasDeadParentId = true
- });
-
- var numComplete = 0;
- var numItems = itemIds.Count;
-
- _logger.Debug("Cleaning {0} items with dead parent links", numItems);
-
- foreach (var itemId in itemIds)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var item = _libraryManager.GetItemById(itemId);
-
- if (item != null)
- {
- _logger.Info("Cleaning item {0} type: {1} path: {2}", item.Name, item.GetType().Name, item.Path ?? string.Empty);
-
- await item.Delete(new DeleteOptions
- {
- DeleteFileLocation = false
-
- }).ConfigureAwait(false);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= numItems;
- progress.Report(percent * 100);
- }
-
- progress.Report(100);
- }
-
- private async Task CleanDeletedItems(CancellationToken cancellationToken, IProgress<double> progress)
- {
- var result = _itemRepo.GetItemIdsWithPath(new InternalItemsQuery
- {
- LocationTypes = new[] { LocationType.FileSystem },
- //Limit = limit,
-
- // These have their own cleanup routines
- ExcludeItemTypes = new[]
- {
- typeof(Person).Name,
- typeof(Genre).Name,
- typeof(MusicGenre).Name,
- typeof(GameGenre).Name,
- typeof(Studio).Name,
- typeof(Year).Name,
- typeof(Channel).Name,
- typeof(AggregateFolder).Name,
- typeof(CollectionFolder).Name
- }
- });
-
- var numComplete = 0;
- var numItems = result.Items.Length;
-
- foreach (var item in result.Items)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var path = item.Item2;
-
- try
- {
- if (_fileSystem.FileExists(path) || _fileSystem.DirectoryExists(path))
- {
- continue;
- }
-
- var libraryItem = _libraryManager.GetItemById(item.Item1);
-
- if (libraryItem.IsTopParent)
- {
- continue;
- }
-
- var hasDualAccess = libraryItem as IHasDualAccess;
- if (hasDualAccess != null && hasDualAccess.IsAccessedByName)
- {
- continue;
- }
-
- var libraryItemPath = libraryItem.Path;
- if (!string.Equals(libraryItemPath, path, StringComparison.OrdinalIgnoreCase))
- {
- _logger.Error("CleanDeletedItems aborting delete for item {0}-{1} because paths don't match. {2}---{3}", libraryItem.Id, libraryItem.Name, libraryItem.Path ?? string.Empty, path ?? string.Empty);
- continue;
- }
-
- if (Folder.IsPathOffline(path))
- {
- await libraryItem.UpdateIsOffline(true).ConfigureAwait(false);
- continue;
- }
-
- _logger.Info("Deleting item from database {0} because path no longer exists. type: {1} path: {2}", libraryItem.Name, libraryItem.GetType().Name, libraryItemPath ?? string.Empty);
-
- await libraryItem.OnFileDeleted().ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- throw;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in CleanDeletedItems. File {0}", ex, path);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= numItems;
- progress.Report(percent * 100);
- }
- }
-
- /// <summary>
- /// Creates the triggers that define when the task will run
- /// </summary>
- /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
- public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
- {
- return new[] {
-
- // Every so often
- new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
- };
- }
-
- public string Key
- {
- get { return "CleanDatabase"; }
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs
deleted file mode 100644
index e695adb54..000000000
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Server.Implementations.Library;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Server.Implementations.ScheduledTasks
-{
- /// <summary>
- /// Class RefreshMediaLibraryTask
- /// </summary>
- public class RefreshMediaLibraryTask : IScheduledTask
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- private readonly IServerConfigurationManager _config;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="RefreshMediaLibraryTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- public RefreshMediaLibraryTask(ILibraryManager libraryManager, IServerConfigurationManager config)
- {
- _libraryManager = libraryManager;
- _config = config;
- }
-
- /// <summary>
- /// Creates the triggers that define when the task will run
- /// </summary>
- /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
- public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
- {
- return new[] {
-
- // Every so often
- new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(12).Ticks}
- };
- }
-
- /// <summary>
- /// Executes the internal.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- progress.Report(0);
-
- return ((LibraryManager)_libraryManager).ValidateMediaLibraryInternal(progress, cancellationToken);
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return "Scan media library"; }
- }
-
- /// <summary>
- /// Gets the description.
- /// </summary>
- /// <value>The description.</value>
- public string Description
- {
- get { return "Scans your media library and refreshes metatata based on configuration."; }
- }
-
- /// <summary>
- /// Gets the category.
- /// </summary>
- /// <value>The category.</value>
- public string Category
- {
- get
- {
- return "Library";
- }
- }
-
- public string Key
- {
- get { return "RefreshLibrary"; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs
deleted file mode 100644
index 7e6a252cd..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- public class AirTimeComparer : 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 DateTime.Compare(GetValue(x), GetValue(y));
- }
-
- /// <summary>
- /// Gets the value.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>System.String.</returns>
- private DateTime GetValue(BaseItem x)
- {
- var series = x as Series;
-
- if (series == null)
- {
- var season = x as Season;
-
- if (season != null)
- {
- series = season.Series;
- }
- else
- {
- var episode = x as Episode;
-
- if (episode != null)
- {
- series = episode.Series;
- }
- }
- }
-
- if (series != null)
- {
- DateTime result;
- if (DateTime.TryParse(series.AirTime, out result))
- {
- return result;
- }
- }
-
- return DateTime.MinValue;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.AirTime; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
deleted file mode 100644
index 91abbe34c..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
+++ /dev/null
@@ -1,160 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- class AiredEpisodeOrderComparer : 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)
- {
- if (x.PremiereDate.HasValue && y.PremiereDate.HasValue)
- {
- var val = DateTime.Compare(x.PremiereDate.Value, y.PremiereDate.Value);
-
- if (val != 0)
- {
- //return val;
- }
- }
-
- var episode1 = x as Episode;
- var episode2 = y as Episode;
-
- if (episode1 == null)
- {
- if (episode2 == null)
- {
- return 0;
- }
-
- return 1;
- }
-
- if (episode2 == null)
- {
- return -1;
- }
-
- return Compare(episode1, episode2);
- }
-
- private int Compare(Episode x, Episode y)
- {
- var isXSpecial = (x.ParentIndexNumber ?? -1) == 0;
- var isYSpecial = (y.ParentIndexNumber ?? -1) == 0;
-
- if (isXSpecial && isYSpecial)
- {
- return CompareSpecials(x, y);
- }
-
- if (!isXSpecial && !isYSpecial)
- {
- return CompareEpisodes(x, y);
- }
-
- if (!isXSpecial)
- {
- return CompareEpisodeToSpecial(x, y);
- }
-
- return CompareEpisodeToSpecial(y, x) * -1;
- }
-
- private int CompareEpisodeToSpecial(Episode x, Episode y)
- {
- // http://thetvdb.com/wiki/index.php?title=Special_Episodes
-
- var xSeason = x.ParentIndexNumber ?? -1;
- var ySeason = y.AirsAfterSeasonNumber ?? y.AirsBeforeSeasonNumber ?? -1;
-
- if (xSeason != ySeason)
- {
- return xSeason.CompareTo(ySeason);
- }
-
- // Special comes after episode
- if (y.AirsAfterSeasonNumber.HasValue)
- {
- return -1;
- }
-
- var yEpisode = y.AirsBeforeEpisodeNumber;
-
- // Special comes before the season
- if (!yEpisode.HasValue)
- {
- return 1;
- }
-
- // Compare episode number
- var xEpisode = x.IndexNumber;
-
- if (!xEpisode.HasValue)
- {
- // Can't really compare if this happens
- return 0;
- }
-
- // Special comes before episode
- if (xEpisode.Value == yEpisode.Value)
- {
- return 1;
- }
-
- return xEpisode.Value.CompareTo(yEpisode.Value);
- }
-
- private int CompareSpecials(Episode x, Episode y)
- {
- return GetSpecialCompareValue(x).CompareTo(GetSpecialCompareValue(y));
- }
-
- private int GetSpecialCompareValue(Episode item)
- {
- // First sort by season number
- // Since there are three sort orders, pad with 9 digits (3 for each, figure 1000 episode buffer should be enough)
- var val = (item.AirsAfterSeasonNumber ?? item.AirsBeforeSeasonNumber ?? 0) * 1000000000;
-
- // Second sort order is if it airs after the season
- if (item.AirsAfterSeasonNumber.HasValue)
- {
- val += 1000000;
- }
-
- // Third level is the episode number
- val += (item.AirsBeforeEpisodeNumber ?? 0) * 1000;
-
- // Finally, if that's still the same, last resort is the special number itself
- val += item.IndexNumber ?? 0;
-
- return val;
- }
-
- private int CompareEpisodes(Episode x, Episode y)
- {
- var xValue = (x.ParentIndexNumber ?? -1) * 1000 + (x.IndexNumber ?? -1);
- var yValue = (y.ParentIndexNumber ?? -1) * 1000 + (y.IndexNumber ?? -1);
-
- return xValue.CompareTo(yValue);
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.AiredEpisodeOrder; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs
deleted file mode 100644
index 3c79b0c32..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using System.Linq;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- /// <summary>
- /// Class AlbumArtistComparer
- /// </summary>
- public class AlbumArtistComparer : 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 audio = x as IHasAlbumArtist;
-
- return audio != null ? audio.AlbumArtists.FirstOrDefault() : null;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.AlbumArtist; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs
deleted file mode 100644
index f455d5c2b..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- /// <summary>
- /// Class AlbumComparer
- /// </summary>
- public class AlbumComparer : 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 audio = x as Audio;
-
- return audio == null ? string.Empty : audio.Album;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.Album; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs b/MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs
deleted file mode 100644
index 232bdb3b5..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-using System.Collections.Generic;
-using System.Text;
-using MediaBrowser.Controller.Sorting;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- public class AlphanumComparator : IComparer<string>
- {
- public static int CompareValues(string s1, string s2)
- {
- if (s1 == null || s2 == null)
- {
- return 0;
- }
-
- int thisMarker = 0, thisNumericChunk = 0;
- int thatMarker = 0, thatNumericChunk = 0;
-
- while ((thisMarker < s1.Length) || (thatMarker < s2.Length))
- {
- if (thisMarker >= s1.Length)
- {
- return -1;
- }
- else if (thatMarker >= s2.Length)
- {
- return 1;
- }
- char thisCh = s1[thisMarker];
- char thatCh = s2[thatMarker];
-
- StringBuilder thisChunk = new StringBuilder();
- StringBuilder thatChunk = new StringBuilder();
-
- while ((thisMarker < s1.Length) && (thisChunk.Length == 0 || SortHelper.InChunk(thisCh, thisChunk[0])))
- {
- thisChunk.Append(thisCh);
- thisMarker++;
-
- if (thisMarker < s1.Length)
- {
- thisCh = s1[thisMarker];
- }
- }
-
- while ((thatMarker < s2.Length) && (thatChunk.Length == 0 || SortHelper.InChunk(thatCh, thatChunk[0])))
- {
- thatChunk.Append(thatCh);
- thatMarker++;
-
- if (thatMarker < s2.Length)
- {
- thatCh = s2[thatMarker];
- }
- }
-
- int result = 0;
- // If both chunks contain numeric characters, sort them numerically
- if (char.IsDigit(thisChunk[0]) && char.IsDigit(thatChunk[0]))
- {
- if (!int.TryParse(thisChunk.ToString(), out thisNumericChunk))
- {
- return 0;
- }
- if (!int.TryParse(thatChunk.ToString(), out thatNumericChunk))
- {
- return 0;
- }
-
- if (thisNumericChunk < thatNumericChunk)
- {
- result = -1;
- }
-
- if (thisNumericChunk > thatNumericChunk)
- {
- result = 1;
- }
- }
- else
- {
- result = thisChunk.ToString().CompareTo(thatChunk.ToString());
- }
-
- if (result != 0)
- {
- return result;
- }
- }
-
- return 0;
- }
-
- public int Compare(string x, string y)
- {
- return CompareValues(x, y);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs b/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs
deleted file mode 100644
index 9ff8a5ace..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- /// <summary>
- /// Class ArtistComparer
- /// </summary>
- public class ArtistComparer : 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 audio = x as Audio;
-
- if (audio == null)
- {
- return string.Empty;
- }
-
- return audio.Artists.Count == 0 ? null : audio.Artists[0];
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.Artist; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/BudgetComparer.cs b/MediaBrowser.Server.Implementations/Sorting/BudgetComparer.cs
deleted file mode 100644
index 87a7325c6..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/BudgetComparer.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- public class BudgetComparer : 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));
- }
-
- private double GetValue(BaseItem x)
- {
- var hasBudget = x as IHasBudget;
- if (hasBudget != null)
- {
- return hasBudget.Budget ?? 0;
- }
- return 0;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.Budget; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs b/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs
deleted file mode 100644
index bdd18a648..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- public class CommunityRatingComparer : 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 (x.CommunityRating ?? 0).CompareTo(y.CommunityRating ?? 0);
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.CommunityRating; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/CriticRatingComparer.cs b/MediaBrowser.Server.Implementations/Sorting/CriticRatingComparer.cs
deleted file mode 100644
index 9484130cb..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/CriticRatingComparer.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- /// <summary>
- /// Class CriticRatingComparer
- /// </summary>
- public class CriticRatingComparer : 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));
- }
-
- private float GetValue(BaseItem x)
- {
- return x.CriticRating ?? 0;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.CriticRating; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs
deleted file mode 100644
index 9862f0a8a..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- /// <summary>
- /// Class DateCreatedComparer
- /// </summary>
- public class DateCreatedComparer : 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 DateTime.Compare(x.DateCreated, y.DateCreated);
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.DateCreated; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs
deleted file mode 100644
index 5080edffd..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- public class DateLastMediaAddedComparer : 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 GetDate(x).CompareTo(GetDate(y));
- }
-
- /// <summary>
- /// Gets the date.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>DateTime.</returns>
- private DateTime GetDate(BaseItem x)
- {
- var folder = x as Folder;
-
- if (folder != null)
- {
- if (folder.DateLastMediaAdded.HasValue)
- {
- return folder.DateLastMediaAdded.Value;
- }
- }
-
- return DateTime.MinValue;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.DateLastContentAdded; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
deleted file mode 100644
index 3edf23020..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- /// <summary>
- /// Class DatePlayedComparer
- /// </summary>
- public class DatePlayedComparer : 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 GetDate(x).CompareTo(GetDate(y));
- }
-
- /// <summary>
- /// Gets the date.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>DateTime.</returns>
- private DateTime GetDate(BaseItem x)
- {
- var userdata = UserDataRepository.GetUserData(User, x);
-
- if (userdata != null && userdata.LastPlayedDate.HasValue)
- {
- return userdata.LastPlayedDate.Value;
- }
-
- return DateTime.MinValue;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.DatePlayed; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/GameSystemComparer.cs b/MediaBrowser.Server.Implementations/Sorting/GameSystemComparer.cs
deleted file mode 100644
index eb83b98e9..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/GameSystemComparer.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-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; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs b/MediaBrowser.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs
deleted file mode 100644
index 658708dba..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- public class IsFavoriteOrLikeComparer : IUserBaseItemComparer
- {
- /// <summary>
- /// Gets or sets the user.
- /// </summary>
- /// <value>The user.</value>
- public User User { 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)
- {
- return x.IsFavoriteOrLiked(User) ? 0 : 1;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.IsFavoriteOrLiked; }
- }
-
- /// <summary>
- /// Gets or sets the user data repository.
- /// </summary>
- /// <value>The user data repository.</value>
- public IUserDataManager UserDataRepository { get; set; }
-
- /// <summary>
- /// Gets or sets the user manager.
- /// </summary>
- /// <value>The user manager.</value>
- public IUserManager UserManager { get; set; }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Sorting/IsFolderComparer.cs b/MediaBrowser.Server.Implementations/Sorting/IsFolderComparer.cs
deleted file mode 100644
index d2341d065..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/IsFolderComparer.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- public class IsFolderComparer : 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)
- {
- return x.IsFolder ? 0 : 1;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.IsFolder; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/IsPlayedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/IsPlayedComparer.cs
deleted file mode 100644
index aebfbdb1c..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/IsPlayedComparer.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- public class IsPlayedComparer : IUserBaseItemComparer
- {
- /// <summary>
- /// Gets or sets the user.
- /// </summary>
- /// <value>The user.</value>
- public User User { 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)
- {
- return x.IsPlayed(User) ? 0 : 1;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.IsUnplayed; }
- }
-
- /// <summary>
- /// Gets or sets the user data repository.
- /// </summary>
- /// <value>The user data repository.</value>
- public IUserDataManager UserDataRepository { get; set; }
-
- /// <summary>
- /// Gets or sets the user manager.
- /// </summary>
- /// <value>The user manager.</value>
- public IUserManager UserManager { get; set; }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Sorting/IsUnplayedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/IsUnplayedComparer.cs
deleted file mode 100644
index f1c6a5a4e..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/IsUnplayedComparer.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- public class IsUnplayedComparer : IUserBaseItemComparer
- {
- /// <summary>
- /// Gets or sets the user.
- /// </summary>
- /// <value>The user.</value>
- public User User { 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)
- {
- return x.IsUnplayed(User) ? 0 : 1;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.IsUnplayed; }
- }
-
- /// <summary>
- /// Gets or sets the user data repository.
- /// </summary>
- /// <value>The user data repository.</value>
- public IUserDataManager UserDataRepository { get; set; }
-
- /// <summary>
- /// Gets or sets the user manager.
- /// </summary>
- /// <value>The user manager.</value>
- public IUserManager UserManager { get; set; }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/MetascoreComparer.cs b/MediaBrowser.Server.Implementations/Sorting/MetascoreComparer.cs
deleted file mode 100644
index bfd162661..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/MetascoreComparer.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- public class MetascoreComparer : 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));
- }
-
- private float GetValue(BaseItem x)
- {
- var hasMetascore = x as IHasMetascore;
-
- if (hasMetascore != null)
- {
- return hasMetascore.Metascore ?? 0;
- }
-
- return 0;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.Metascore; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/NameComparer.cs b/MediaBrowser.Server.Implementations/Sorting/NameComparer.cs
deleted file mode 100644
index 49f86c485..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/NameComparer.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- /// <summary>
- /// Class NameComparer
- /// </summary>
- public class NameComparer : 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(x.Name, y.Name, StringComparison.CurrentCultureIgnoreCase);
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.Name; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/OfficialRatingComparer.cs b/MediaBrowser.Server.Implementations/Sorting/OfficialRatingComparer.cs
deleted file mode 100644
index 3b1939b70..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/OfficialRatingComparer.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Globalization;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- public class OfficialRatingComparer : IBaseItemComparer
- {
- private readonly ILocalizationManager _localization;
-
- public OfficialRatingComparer(ILocalizationManager localization)
- {
- _localization = localization;
- }
-
- /// <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)
- {
- var levelX = string.IsNullOrEmpty(x.OfficialRating) ? 0 : _localization.GetRatingLevel(x.OfficialRating) ?? 0;
- var levelY = string.IsNullOrEmpty(y.OfficialRating) ? 0 : _localization.GetRatingLevel(y.OfficialRating) ?? 0;
-
- return levelX.CompareTo(levelY);
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.OfficialRating; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs b/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs
deleted file mode 100644
index 8b14efffc..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- /// <summary>
- /// Class PlayCountComparer
- /// </summary>
- public class PlayCountComparer : IUserBaseItemComparer
- {
- /// <summary>
- /// Gets or sets the user.
- /// </summary>
- /// <value>The user.</value>
- public User User { 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 userdata = UserDataRepository.GetUserData(User, x);
-
- return userdata == null ? 0 : userdata.PlayCount;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.PlayCount; }
- }
-
- /// <summary>
- /// Gets or sets the user data repository.
- /// </summary>
- /// <value>The user data repository.</value>
- public IUserDataManager UserDataRepository { get; set; }
-
- /// <summary>
- /// Gets or sets the user manager.
- /// </summary>
- /// <value>The user manager.</value>
- public IUserManager UserManager { get; set; }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/PlayersComparer.cs b/MediaBrowser.Server.Implementations/Sorting/PlayersComparer.cs
deleted file mode 100644
index 5bcd080d7..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/PlayersComparer.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-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; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs b/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs
deleted file mode 100644
index ffe1fc24a..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- /// <summary>
- /// Class PremiereDateComparer
- /// </summary>
- public class PremiereDateComparer : 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 GetDate(x).CompareTo(GetDate(y));
- }
-
- /// <summary>
- /// Gets the date.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>DateTime.</returns>
- private DateTime GetDate(BaseItem x)
- {
- if (x.PremiereDate.HasValue)
- {
- return x.PremiereDate.Value;
- }
-
- if (x.ProductionYear.HasValue)
- {
- try
- {
- return new DateTime(x.ProductionYear.Value, 1, 1, 0, 0, 0, DateTimeKind.Utc);
- }
- catch (ArgumentOutOfRangeException)
- {
- // Don't blow up if the item has a bad ProductionYear, just return MinValue
- }
- }
- return DateTime.MinValue;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.PremiereDate; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs b/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs
deleted file mode 100644
index 16d531334..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- /// <summary>
- /// Class ProductionYearComparer
- /// </summary>
- public class ProductionYearComparer : 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 date.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>DateTime.</returns>
- private int GetValue(BaseItem x)
- {
- if (x.ProductionYear.HasValue)
- {
- return x.ProductionYear.Value;
- }
-
- if (x.PremiereDate.HasValue)
- {
- return x.PremiereDate.Value.Year;
- }
-
- return 0;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.ProductionYear; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs b/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs
deleted file mode 100644
index b1677331a..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- /// <summary>
- /// Class RandomComparer
- /// </summary>
- public class RandomComparer : 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 Guid.NewGuid().CompareTo(Guid.NewGuid());
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.Random; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/RevenueComparer.cs b/MediaBrowser.Server.Implementations/Sorting/RevenueComparer.cs
deleted file mode 100644
index 6caa27ac3..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/RevenueComparer.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- public class RevenueComparer : 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));
- }
-
- private double GetValue(BaseItem x)
- {
- var hasBudget = x as IHasBudget;
- if (hasBudget != null)
- {
- return hasBudget.Revenue ?? 0;
- }
- return 0;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.Revenue; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs b/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs
deleted file mode 100644
index 793cb265e..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- /// <summary>
- /// Class RuntimeComparer
- /// </summary>
- public class RuntimeComparer : 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 (x.RunTimeTicks ?? 0).CompareTo(y.RunTimeTicks ?? 0);
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.Runtime; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/SeriesSortNameComparer.cs b/MediaBrowser.Server.Implementations/Sorting/SeriesSortNameComparer.cs
deleted file mode 100644
index 6bc1264a4..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/SeriesSortNameComparer.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- class SeriesSortNameComparer : 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);
- }
-
- private string GetValue(BaseItem item)
- {
- var hasSeries = item as IHasSeries;
-
- return hasSeries != null ? hasSeries.SeriesSortName : null;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.SeriesSortName; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs b/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs
deleted file mode 100644
index 873753a2b..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- /// <summary>
- /// Class SortNameComparer
- /// </summary>
- public class SortNameComparer : 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(x.SortName, y.SortName, StringComparison.CurrentCultureIgnoreCase);
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.SortName; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/StartDateComparer.cs b/MediaBrowser.Server.Implementations/Sorting/StartDateComparer.cs
deleted file mode 100644
index 7e6f24ec1..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/StartDateComparer.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Sorting
-{
- public class StartDateComparer : 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 GetDate(x).CompareTo(GetDate(y));
- }
-
- /// <summary>
- /// Gets the date.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>DateTime.</returns>
- private DateTime GetDate(BaseItem x)
- {
- var hasStartDate = x as LiveTvProgram;
-
- if (hasStartDate != null)
- {
- return hasStartDate.StartDate;
- }
- return DateTime.MinValue;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.StartDate; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Sorting/StudioComparer.cs b/MediaBrowser.Server.Implementations/Sorting/StudioComparer.cs
deleted file mode 100644
index 83ab4dfc2..000000000
--- a/MediaBrowser.Server.Implementations/Sorting/StudioComparer.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-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; }
- }
- }
-}