using System; using System.Linq; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using System.Collections.Generic; using NzbDrone.Core.Tv.Events; namespace NzbDrone.Core.DataAugmentation.Scene { public interface ISceneMappingService { List GetSceneNames(int tvdbId, IEnumerable seasonNumbers); Nullable FindTvDbId(string title); List FindByTvdbId(int tvdbId); Nullable GetSeasonNumber(string title); } public class SceneMappingService : ISceneMappingService, IHandleAsync, IHandle, IExecute { private readonly ISceneMappingRepository _repository; private readonly IEnumerable _sceneMappingProviders; private readonly IEventAggregator _eventAggregator; private readonly Logger _logger; private readonly ICached _getTvdbIdCache; private readonly ICached> _findByTvdbIdCache; public SceneMappingService(ISceneMappingRepository repository, ICacheManager cacheManager, IEnumerable sceneMappingProviders, IEventAggregator eventAggregator, Logger logger) { _repository = repository; _sceneMappingProviders = sceneMappingProviders; _eventAggregator = eventAggregator; _getTvdbIdCache = cacheManager.GetCache(GetType(), "tvdb_id"); _findByTvdbIdCache = cacheManager.GetCache>(GetType(), "find_tvdb_id"); _logger = logger; } public List GetSceneNames(int tvdbId, IEnumerable seasonNumbers) { var names = _findByTvdbIdCache.Find(tvdbId.ToString()); if (names == null) { return new List(); } return FilterNonEnglish(names.Where(s => seasonNumbers.Contains(s.SeasonNumber) || s.SeasonNumber == -1) .Select(m => m.SearchTerm).Distinct().ToList()); } public Nullable FindTvDbId(string title) { var mapping = FindTvdbId(title); if (mapping == null) return null; return mapping.TvdbId; } public List FindByTvdbId(int tvdbId) { if (_findByTvdbIdCache.Count == 0) { RefreshCache(); } var mappings = _findByTvdbIdCache.Find(tvdbId.ToString()); if (mappings == null) { return new List(); } return mappings; } public Nullable GetSeasonNumber(string title) { var mapping = FindTvdbId(title); if (mapping == null) return null; return mapping.SeasonNumber; } private void UpdateMappings() { _logger.Info("Updating Scene mappings"); foreach (var sceneMappingProvider in _sceneMappingProviders) { try { var mappings = sceneMappingProvider.GetSceneMappings(); if (mappings.Any()) { _repository.Clear(sceneMappingProvider.GetType().Name); mappings.RemoveAll(sceneMapping => { if (sceneMapping.ParseTerm.IsNullOrWhiteSpace() || sceneMapping.SearchTerm.IsNullOrWhiteSpace()) { _logger.Warn("Invalid scene mapping found for: {0}, skipping", sceneMapping.TvdbId); return true; } return false; }); foreach (var sceneMapping in mappings) { sceneMapping.ParseTerm = sceneMapping.Title.CleanSeriesTitle(); sceneMapping.Type = sceneMappingProvider.GetType().Name; } _repository.InsertMany(mappings.DistinctBy(s => s.ParseTerm).ToList()); } else { _logger.Warn("Received empty list of mapping. will not update."); } } catch (Exception ex) { _logger.ErrorException("Failed to Update Scene Mappings:", ex); } } RefreshCache(); _eventAggregator.PublishEvent(new SceneMappingsUpdatedEvent()); } private SceneMapping FindTvdbId(string title) { if (_getTvdbIdCache.Count == 0) { RefreshCache(); } return _getTvdbIdCache.Find(title.CleanSeriesTitle()); } private void RefreshCache() { var mappings = _repository.All().ToList(); _getTvdbIdCache.Clear(); _findByTvdbIdCache.Clear(); foreach (var sceneMapping in mappings) { _getTvdbIdCache.Set(sceneMapping.ParseTerm.CleanSeriesTitle(), sceneMapping); } foreach (var sceneMapping in mappings.GroupBy(x => x.TvdbId)) { _findByTvdbIdCache.Set(sceneMapping.Key.ToString(), sceneMapping.ToList()); } } private List FilterNonEnglish(List titles) { return titles.Where(title => title.All(c => c <= 255)).ToList(); } public void HandleAsync(ApplicationStartedEvent message) { UpdateMappings(); } public void Handle(SeriesRefreshStartingEvent message) { UpdateMappings(); } public void Execute(UpdateSceneMappingCommand message) { UpdateMappings(); } } }