using NLog; using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles.Events; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Music.Events; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace NzbDrone.Core.Music { public interface ITrackService { Track GetTrack(int id); List GetTracks(IEnumerable ids); Track FindTrack(int artistId, int albumId, int trackNumber); Track FindTrackByTitle(int artistId, int albumId, string releaseTitle); List GetTracksByArtist(int artistId); List GetTracksByAlbum(int artistId, int albumId); //List GetTracksByAlbumTitle(string artistId, string albumTitle); List TracksWithFiles(int artistId); //PagingSpec TracksWithoutFiles(PagingSpec pagingSpec); List GetTracksByFileId(int trackFileId); void UpdateTrack(Track track); void SetTrackMonitored(int trackId, bool monitored); void UpdateTracks(List tracks); void InsertMany(List tracks); void UpdateMany(List tracks); void DeleteMany(List tracks); void SetTrackMonitoredByAlbum(int artistId, int albumId, bool monitored); } public class TrackService : ITrackService, IHandleAsync, IHandle, IHandle { private readonly ITrackRepository _trackRepository; private readonly IConfigService _configService; private readonly Logger _logger; public TrackService(ITrackRepository trackRepository, IConfigService configService, Logger logger) { _trackRepository = trackRepository; _configService = configService; _logger = logger; } public Track GetTrack(int id) { return _trackRepository.Get(id); } public List GetTracks(IEnumerable ids) { return _trackRepository.Get(ids).ToList(); } public Track FindTrack(int artistId, int albumId, int trackNumber) { return _trackRepository.Find(artistId, albumId, trackNumber); } public List GetTracksByArtist(int artistId) { _logger.Debug("Getting Tracks for ArtistId {0}", artistId); return _trackRepository.GetTracks(artistId).ToList(); } public List GetTracksByAlbum(int artistId, int albumId) { return _trackRepository.GetTracks(artistId, albumId); } public Track FindTrackByTitle(int artistId, int albumId, string releaseTitle) { // TODO: can replace this search mechanism with something smarter/faster/better var normalizedReleaseTitle = Parser.Parser.NormalizeEpisodeTitle(releaseTitle).Replace(".", " "); var tracks = _trackRepository.GetTracks(artistId, albumId); var matches = tracks.Select( track => new { Position = normalizedReleaseTitle.IndexOf(Parser.Parser.NormalizeEpisodeTitle(track.Title), StringComparison.CurrentCultureIgnoreCase), Length = Parser.Parser.NormalizeEpisodeTitle(track.Title).Length, Track = track }) .Where(e => e.Track.Title.Length > 0 && e.Position >= 0) .OrderBy(e => e.Position) .ThenByDescending(e => e.Length) .ToList(); if (matches.Any()) { return matches.First().Track; } return null; } public List TracksWithFiles(int artistId) { return _trackRepository.TracksWithFiles(artistId); } public PagingSpec TracksWithoutFiles(PagingSpec pagingSpec) { var episodeResult = _trackRepository.TracksWithoutFiles(pagingSpec); return episodeResult; } public List GetTracksByFileId(int trackFileId) { return _trackRepository.GetTracksByFileId(trackFileId); } public void UpdateTrack(Track track) { _trackRepository.Update(track); } public void SetTrackMonitored(int trackId, bool monitored) { var track = _trackRepository.Get(trackId); _trackRepository.SetMonitoredFlat(track, monitored); _logger.Debug("Monitored flag for Track:{0} was set to {1}", trackId, monitored); } public void SetTrackMonitoredByAlbum(int artistId, int albumId, bool monitored) { _trackRepository.SetMonitoredByAlbum(artistId, albumId, monitored); } public void UpdateTracks(List tracks) { _trackRepository.UpdateMany(tracks); } public void InsertMany(List tracks) { _trackRepository.InsertMany(tracks); } public void UpdateMany(List tracks) { _trackRepository.UpdateMany(tracks); } public void DeleteMany(List tracks) { _trackRepository.DeleteMany(tracks); } public void HandleAsync(ArtistDeletedEvent message) { var tracks = GetTracksByArtist(message.Artist.Id); _trackRepository.DeleteMany(tracks); } public void Handle(TrackFileDeletedEvent message) { foreach (var track in GetTracksByFileId(message.TrackFile.Id)) { _logger.Debug("Detaching track {0} from file.", track.Id); track.TrackFileId = 0; if (message.Reason != DeleteMediaFileReason.Upgrade && _configService.AutoUnmonitorPreviouslyDownloadedTracks) { track.Monitored = false; } UpdateTrack(track); } } public void Handle(TrackFileAddedEvent message) { foreach (var track in message.TrackFile.Tracks.Value) { _trackRepository.SetFileId(track.Id, message.TrackFile.Id); _logger.Debug("Linking [{0}] > [{1}]", message.TrackFile.RelativePath, track); } } } }