From dcde579a43797b6203bbedc1723ebdf5bc5bcc54 Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 7 Jul 2017 22:06:21 -0400 Subject: [PATCH] First Pass At AlbumStudio Page, Also Fixes Monitoring (#16) * First Pass At AlbumPass Page, Also Fixes Monitoring First Pass At AlbumPass Page, Also Fixes Monitoring * Catchy New Name, Fix Crash when visit Wanted Page Catchy New Name, Fix Crash when visit Wanted Page * Rename API to match Rename API to match * Get Bulk Monitoring Working on Album Studio Page Get Bulk Monitoring Working on Album Studio Page * Fix Wanted Query Fix Wanted Query * Codacy Codacy * Fix Cutoff Link To AlbumStudio Fix Cutoff Link To AlbumStudio * Add Header, Move Artist Monitor, Change Artist Column Heading Add Header, Move Artist Monitor, Change Artist Column Heading --- .../AlbumStudio/AlbumStudioModule.cs | 31 ++++++++ .../AlbumStudio/AlbumStudioResource.cs | 11 +++ src/NzbDrone.Api/Albums/AlbumModule.cs | 4 +- .../Albums/AlbumModuleWithSignalR.cs | 36 ++++++++- src/NzbDrone.Api/Albums/AlbumResource.cs | 1 + .../Albums/AlbumStatisticsResource.cs | 45 ++++++++++++ src/NzbDrone.Api/Calendar/CalendarModule.cs | 4 +- src/NzbDrone.Api/Music/ArtistResource.cs | 9 ++- src/NzbDrone.Api/NzbDrone.Api.csproj | 3 + src/NzbDrone.Api/Wanted/MissingModule.cs | 5 +- .../Music/AlbumMonitoredService.cs | 69 ++++++++++++++++++ src/NzbDrone.Core/Music/AlbumRepository.cs | 6 +- src/NzbDrone.Core/Music/Artist.cs | 27 ++----- src/NzbDrone.Core/Music/MonitoringOptions.cs | 11 +++ .../Music/TrackMonitoredService.cs | 73 +++++++++++++++++++ src/NzbDrone.Core/NzbDrone.Core.csproj | 3 + src/NzbDrone.Core/Tv/MonitoringOptions.cs | 3 - .../AlbumStudio/AlbumStudioCollectionView.js | 25 +++++++ .../AlbumStudioFooterView.js} | 57 +++++---------- .../AlbumStudioFooterViewTemplate.hbs} | 17 ++--- .../AlbumStudioLayout.js} | 68 ++++++++--------- .../AlbumStudio/AlbumStudioLayoutTemplate.hbs | 14 ++++ src/UI/AlbumStudio/AlbumsCell.js | 58 +++++++++++++++ src/UI/AlbumStudio/AlbumsCellTemplate.hbs | 1 + src/UI/AlbumStudio/SingleAlbumCell.js | 64 ++++++++++++++++ .../AlbumStudio/SingleAlbumCellTemplate.hbs | 30 ++++++++ .../albumstudio.less} | 17 +++-- src/UI/Artist/ArtistModel.js | 9 +-- src/UI/Artist/Details/AlbumCollectionView.js | 2 +- src/UI/Artist/Details/AlbumLayout.js | 20 ++--- src/UI/Artist/Details/ArtistDetailsLayout.js | 6 +- src/UI/Artist/Editor/ArtistEditorLayout.js | 4 +- src/UI/Artist/Index/ArtistIndexLayout.js | 4 +- src/UI/Cells/ArtistMonitoredCell.js | 39 ++++++++++ src/UI/Cells/TrackMonitoredCell.js | 2 +- src/UI/Cells/cells.less | 8 ++ src/UI/Content/theme.less | 2 +- src/UI/Controller.js | 8 +- src/UI/Router.js | 2 +- .../SeasonPass/SeasonPassLayoutTemplate.hbs | 13 ---- src/UI/SeasonPass/SeasonsCell.js | 26 ------- src/UI/SeasonPass/SeasonsCellTemplate.hbs | 37 ---------- src/UI/Wanted/Cutoff/CutoffUnmetLayout.js | 4 +- src/UI/Wanted/Missing/MissingLayout.js | 4 +- 44 files changed, 640 insertions(+), 242 deletions(-) create mode 100644 src/NzbDrone.Api/AlbumStudio/AlbumStudioModule.cs create mode 100644 src/NzbDrone.Api/AlbumStudio/AlbumStudioResource.cs create mode 100644 src/NzbDrone.Api/Albums/AlbumStatisticsResource.cs create mode 100644 src/NzbDrone.Core/Music/AlbumMonitoredService.cs create mode 100644 src/NzbDrone.Core/Music/MonitoringOptions.cs create mode 100644 src/NzbDrone.Core/Music/TrackMonitoredService.cs create mode 100644 src/UI/AlbumStudio/AlbumStudioCollectionView.js rename src/UI/{SeasonPass/SeasonPassFooterView.js => AlbumStudio/AlbumStudioFooterView.js} (57%) rename src/UI/{SeasonPass/SeasonPassFooterViewTemplate.hbs => AlbumStudio/AlbumStudioFooterViewTemplate.hbs} (60%) rename src/UI/{SeasonPass/SeasonPassLayout.js => AlbumStudio/AlbumStudioLayout.js} (63%) create mode 100644 src/UI/AlbumStudio/AlbumStudioLayoutTemplate.hbs create mode 100644 src/UI/AlbumStudio/AlbumsCell.js create mode 100644 src/UI/AlbumStudio/AlbumsCellTemplate.hbs create mode 100644 src/UI/AlbumStudio/SingleAlbumCell.js create mode 100644 src/UI/AlbumStudio/SingleAlbumCellTemplate.hbs rename src/UI/{SeasonPass/seasonpass.less => AlbumStudio/albumstudio.less} (83%) create mode 100644 src/UI/Cells/ArtistMonitoredCell.js delete mode 100644 src/UI/SeasonPass/SeasonPassLayoutTemplate.hbs delete mode 100644 src/UI/SeasonPass/SeasonsCell.js delete mode 100644 src/UI/SeasonPass/SeasonsCellTemplate.hbs diff --git a/src/NzbDrone.Api/AlbumStudio/AlbumStudioModule.cs b/src/NzbDrone.Api/AlbumStudio/AlbumStudioModule.cs new file mode 100644 index 000000000..4fa964a2f --- /dev/null +++ b/src/NzbDrone.Api/AlbumStudio/AlbumStudioModule.cs @@ -0,0 +1,31 @@ +using Nancy; +using NzbDrone.Api.Extensions; +using NzbDrone.Core.Music; + +namespace NzbDrone.Api.AlbumPass +{ + public class AlbumStudioModule : NzbDroneApiModule + { + private readonly IAlbumMonitoredService _albumMonitoredService; + + public AlbumStudioModule(IAlbumMonitoredService albumMonitoredService) + : base("/albumstudio") + { + _albumMonitoredService = albumMonitoredService; + Post["/"] = artist => UpdateAll(); + } + + private Response UpdateAll() + { + //Read from request + var request = Request.Body.FromJson(); + + foreach (var s in request.Artist) + { + _albumMonitoredService.SetAlbumMonitoredStatus(s, request.MonitoringOptions); + } + + return "ok".AsResponse(HttpStatusCode.Accepted); + } + } +} diff --git a/src/NzbDrone.Api/AlbumStudio/AlbumStudioResource.cs b/src/NzbDrone.Api/AlbumStudio/AlbumStudioResource.cs new file mode 100644 index 000000000..1b0779af9 --- /dev/null +++ b/src/NzbDrone.Api/AlbumStudio/AlbumStudioResource.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using NzbDrone.Core.Music; + +namespace NzbDrone.Api.AlbumPass +{ + public class AlbumStudioResource + { + public List Artist { get; set; } + public MonitoringOptions MonitoringOptions { get; set; } + } +} diff --git a/src/NzbDrone.Api/Albums/AlbumModule.cs b/src/NzbDrone.Api/Albums/AlbumModule.cs index f7e65d1ad..e2d635fd0 100644 --- a/src/NzbDrone.Api/Albums/AlbumModule.cs +++ b/src/NzbDrone.Api/Albums/AlbumModule.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using NzbDrone.Api.REST; using NzbDrone.Core.Music; +using NzbDrone.Core.ArtistStats; using NzbDrone.Core.DecisionEngine; using NzbDrone.SignalR; @@ -9,10 +10,11 @@ namespace NzbDrone.Api.Albums public class AlbumModule : AlbumModuleWithSignalR { public AlbumModule(IArtistService artistService, + IArtistStatisticsService artistStatisticsService, IAlbumService albumService, IQualityUpgradableSpecification qualityUpgradableSpecification, IBroadcastSignalRMessage signalRBroadcaster) - : base(albumService, artistService, qualityUpgradableSpecification, signalRBroadcaster) + : base(albumService, artistStatisticsService, artistService, qualityUpgradableSpecification, signalRBroadcaster) { GetResourceAll = GetAlbums; UpdateResource = SetMonitored; diff --git a/src/NzbDrone.Api/Albums/AlbumModuleWithSignalR.cs b/src/NzbDrone.Api/Albums/AlbumModuleWithSignalR.cs index df6aba322..59fe8fc2d 100644 --- a/src/NzbDrone.Api/Albums/AlbumModuleWithSignalR.cs +++ b/src/NzbDrone.Api/Albums/AlbumModuleWithSignalR.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; +using FluentValidation; using NzbDrone.Common.Extensions; using NzbDrone.Api.TrackFiles; using NzbDrone.Api.Music; @@ -8,6 +11,7 @@ using NzbDrone.Core.Download; using NzbDrone.Core.MediaFiles.Events; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Music; +using NzbDrone.Core.ArtistStats; using NzbDrone.SignalR; namespace NzbDrone.Api.Albums @@ -15,16 +19,19 @@ namespace NzbDrone.Api.Albums public abstract class AlbumModuleWithSignalR : NzbDroneRestModuleWithSignalR { protected readonly IAlbumService _albumService; + protected readonly IArtistStatisticsService _artistStatisticsService; protected readonly IArtistService _artistService; protected readonly IQualityUpgradableSpecification _qualityUpgradableSpecification; protected AlbumModuleWithSignalR(IAlbumService albumService, + IArtistStatisticsService artistStatisticsService, IArtistService artistService, IQualityUpgradableSpecification qualityUpgradableSpecification, IBroadcastSignalRMessage signalRBroadcaster) : base(signalRBroadcaster) { _albumService = albumService; + _artistStatisticsService = artistStatisticsService; _artistService = artistService; _qualityUpgradableSpecification = qualityUpgradableSpecification; @@ -32,6 +39,7 @@ namespace NzbDrone.Api.Albums } protected AlbumModuleWithSignalR(IAlbumService albumService, + IArtistStatisticsService artistStatisticsService, IArtistService artistService, IQualityUpgradableSpecification qualityUpgradableSpecification, IBroadcastSignalRMessage signalRBroadcaster, @@ -39,6 +47,7 @@ namespace NzbDrone.Api.Albums : base(signalRBroadcaster, resource) { _albumService = albumService; + _artistStatisticsService = artistStatisticsService; _artistService = artistService; _qualityUpgradableSpecification = qualityUpgradableSpecification; @@ -66,6 +75,8 @@ namespace NzbDrone.Api.Albums } } + FetchAndLinkAlbumStatistics(resource); + return resource; } @@ -91,9 +102,32 @@ namespace NzbDrone.Api.Albums } } + for (var i = 0; i < albums.Count; i++) + { + var resource = result[i]; + FetchAndLinkAlbumStatistics(resource); + } + + return result; } + private void FetchAndLinkAlbumStatistics(AlbumResource resource) + { + LinkArtistStatistics(resource, _artistStatisticsService.ArtistStatistics(resource.ArtistId)); + } + + private void LinkArtistStatistics(AlbumResource resource, ArtistStatistics artistStatistics) + { + if (artistStatistics.AlbumStatistics != null) + { + var dictAlbumStats = artistStatistics.AlbumStatistics.ToDictionary(v => v.AlbumId); + + resource.Statistics = dictAlbumStats.GetValueOrDefault(resource.Id).ToResource(); + + } + } + //TODO: Implement Track or Album Grabbed/Dowloaded Events //public void Handle(TrackGrabbedEvent message) diff --git a/src/NzbDrone.Api/Albums/AlbumResource.cs b/src/NzbDrone.Api/Albums/AlbumResource.cs index 1bab9d342..26f883be0 100644 --- a/src/NzbDrone.Api/Albums/AlbumResource.cs +++ b/src/NzbDrone.Api/Albums/AlbumResource.cs @@ -23,6 +23,7 @@ namespace NzbDrone.Api.Albums public List Genres { get; set; } public ArtistResource Artist { get; set; } public List Images { get; set; } + public AlbumStatisticsResource Statistics { get; set; } } diff --git a/src/NzbDrone.Api/Albums/AlbumStatisticsResource.cs b/src/NzbDrone.Api/Albums/AlbumStatisticsResource.cs new file mode 100644 index 000000000..13ffb2e4b --- /dev/null +++ b/src/NzbDrone.Api/Albums/AlbumStatisticsResource.cs @@ -0,0 +1,45 @@ +using System; +using NzbDrone.Core.ArtistStats; + +namespace NzbDrone.Api.Albums +{ + public class AlbumStatisticsResource + { + public int TrackFileCount { get; set; } + public int TrackCount { get; set; } + public int TotalTrackCount { get; set; } + public long SizeOnDisk { get; set; } + + public decimal PercentOfTracks + { + get + { + if (TrackCount == 0) + { + return 0; + } + + return (decimal)TrackFileCount / (decimal)TrackCount * 100; + } + } + } + + public static class AlbumStatisticsResourceMapper + { + public static AlbumStatisticsResource ToResource(this AlbumStatistics model) + { + if (model == null) + { + return null; + } + + return new AlbumStatisticsResource + { + TrackFileCount = model.TrackFileCount, + TrackCount = model.TrackCount, + TotalTrackCount = model.TotalTrackCount, + SizeOnDisk = model.SizeOnDisk + }; + } + } +} diff --git a/src/NzbDrone.Api/Calendar/CalendarModule.cs b/src/NzbDrone.Api/Calendar/CalendarModule.cs index 3f4a0c80d..352fad3a6 100644 --- a/src/NzbDrone.Api/Calendar/CalendarModule.cs +++ b/src/NzbDrone.Api/Calendar/CalendarModule.cs @@ -6,6 +6,7 @@ using NzbDrone.Api.Albums; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Tv; using NzbDrone.Core.Music; +using NzbDrone.Core.ArtistStats; using NzbDrone.SignalR; namespace NzbDrone.Api.Calendar @@ -13,10 +14,11 @@ namespace NzbDrone.Api.Calendar public class CalendarModule : AlbumModuleWithSignalR { public CalendarModule(IAlbumService albumService, + IArtistStatisticsService artistStatisticsService, IArtistService artistService, IQualityUpgradableSpecification qualityUpgradableSpecification, IBroadcastSignalRMessage signalRBroadcaster) - : base(albumService, artistService, qualityUpgradableSpecification, signalRBroadcaster, "calendar") + : base(albumService, artistStatisticsService, artistService, qualityUpgradableSpecification, signalRBroadcaster, "calendar") { GetResourceAll = GetCalendar; } diff --git a/src/NzbDrone.Api/Music/ArtistResource.cs b/src/NzbDrone.Api/Music/ArtistResource.cs index 2f58909a7..e242e6601 100644 --- a/src/NzbDrone.Api/Music/ArtistResource.cs +++ b/src/NzbDrone.Api/Music/ArtistResource.cs @@ -52,6 +52,7 @@ namespace NzbDrone.Api.Music public string RootFolderPath { get; set; } //public string Certification { get; set; } public List Genres { get; set; } + public string CleanName { get; set; } public HashSet Tags { get; set; } public DateTime Added { get; set; } public AddArtistOptions AddOptions { get; set; } @@ -73,6 +74,7 @@ namespace NzbDrone.Api.Music DiscogsId = model.DiscogsId, AllMusicId = model.AMId, Name = model.Name, + CleanName = model.CleanName, //AlternateTitles //SortTitle = resource.SortTitle, @@ -88,8 +90,7 @@ namespace NzbDrone.Api.Music //AirTime = resource.AirTime, Images = model.Images, Members = model.Members, - - Albums = model.Albums.ToResource(), + //Albums = model.Albums.ToResource(), //Year = resource.Year, Path = model.Path, @@ -127,6 +128,7 @@ namespace NzbDrone.Api.Music Id = resource.Id, Name = resource.Name, + CleanName = resource.CleanName, //AlternateTitles //SortTitle = resource.SortTitle, MBId = resource.MBId, @@ -145,8 +147,7 @@ namespace NzbDrone.Api.Music //AirTime = resource.AirTime, Images = resource.Images, Members = resource.Members, - - Albums = resource.Albums.ToModel(), + //Albums = resource.Albums.ToModel(), //Year = resource.Year, Path = resource.Path, diff --git a/src/NzbDrone.Api/NzbDrone.Api.csproj b/src/NzbDrone.Api/NzbDrone.Api.csproj index 3d504af28..233665156 100644 --- a/src/NzbDrone.Api/NzbDrone.Api.csproj +++ b/src/NzbDrone.Api/NzbDrone.Api.csproj @@ -89,6 +89,7 @@ Properties\SharedAssemblyInfo.cs + @@ -105,6 +106,8 @@ + + diff --git a/src/NzbDrone.Api/Wanted/MissingModule.cs b/src/NzbDrone.Api/Wanted/MissingModule.cs index ed186fe72..018ecec62 100644 --- a/src/NzbDrone.Api/Wanted/MissingModule.cs +++ b/src/NzbDrone.Api/Wanted/MissingModule.cs @@ -2,7 +2,7 @@ using NzbDrone.Api.Albums; using NzbDrone.Core.Datastore; using NzbDrone.Core.DecisionEngine; -using NzbDrone.Core.Tv; +using NzbDrone.Core.ArtistStats; using NzbDrone.Core.Music; using NzbDrone.SignalR; @@ -11,10 +11,11 @@ namespace NzbDrone.Api.Wanted public class MissingModule : AlbumModuleWithSignalR { public MissingModule(IAlbumService albumService, + IArtistStatisticsService artistStatisticsService, IArtistService artistService, IQualityUpgradableSpecification qualityUpgradableSpecification, IBroadcastSignalRMessage signalRBroadcaster) - : base(albumService, artistService, qualityUpgradableSpecification, signalRBroadcaster, "wanted/missing") + : base(albumService, artistStatisticsService, artistService, qualityUpgradableSpecification, signalRBroadcaster, "wanted/missing") { GetResourcePaged = GetMissingAlbums; } diff --git a/src/NzbDrone.Core/Music/AlbumMonitoredService.cs b/src/NzbDrone.Core/Music/AlbumMonitoredService.cs new file mode 100644 index 000000000..c19965f41 --- /dev/null +++ b/src/NzbDrone.Core/Music/AlbumMonitoredService.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NLog; +using NzbDrone.Common.Extensions; + +namespace NzbDrone.Core.Music +{ + public interface IAlbumMonitoredService + { + void SetAlbumMonitoredStatus(Artist album, MonitoringOptions monitoringOptions); + } + + public class AlbumMonitoredService : IAlbumMonitoredService + { + private readonly IArtistService _artistService; + private readonly IAlbumService _albumService; + private readonly ITrackService _trackService; + private readonly Logger _logger; + + public AlbumMonitoredService(IArtistService artistService, IAlbumService albumService, ITrackService trackService, Logger logger) + { + _artistService = artistService; + _albumService = albumService; + _trackService = trackService; + _logger = logger; + } + + public void SetAlbumMonitoredStatus(Artist artist, MonitoringOptions monitoringOptions) + { + if (monitoringOptions != null) + { + _logger.Debug("[{0}] Setting album monitored status.", artist.Name); + + var albums = _albumService.GetAlbumsByArtist(artist.Id); + + if (monitoringOptions.Monitored) + { + ToggleAlbumsMonitoredState(albums, true); + } + + else + { + ToggleAlbumsMonitoredState(albums, false); + } + + //TODO Add Other Options for Future/Exisitng/Missing Once we have a good way to check for Album Related Files. + + _albumService.UpdateAlbums(albums); + } + + _artistService.UpdateArtist(artist); + } + + private void ToggleAlbumsMonitoredState(IEnumerable albums, bool monitored) + { + foreach (var album in albums) + { + album.Monitored = monitored; + var tracks = _trackService.GetTracksByAlbum(album.ArtistId, album.Id); + foreach (var track in tracks) + { + track.Monitored = monitored; + } + _trackService.UpdateTracks(tracks); + } + } + } +} diff --git a/src/NzbDrone.Core/Music/AlbumRepository.cs b/src/NzbDrone.Core/Music/AlbumRepository.cs index a79ab3a31..04da93c9b 100644 --- a/src/NzbDrone.Core/Music/AlbumRepository.cs +++ b/src/NzbDrone.Core/Music/AlbumRepository.cs @@ -75,11 +75,11 @@ namespace NzbDrone.Core.Music private QueryBuilder GetMissingAlbumsQuery(PagingSpec pagingSpec, DateTime currentTime) { string sortKey; - int monitored = 0; + string monitored = "([t0].[Monitored] = 0) OR ([t1].[Monitored] = 0)"; if (pagingSpec.FilterExpression.ToString().Contains("True")) { - monitored = 1; + monitored = "([t0].[Monitored] = 1) AND ([t1].[Monitored] = 1)"; } if (pagingSpec.SortKey == "releaseDate") @@ -96,7 +96,7 @@ namespace NzbDrone.Core.Music } string query = string.Format("SELECT * FROM Albums [t0] INNER JOIN Artists [t1] ON ([t0].[ArtistId] = [t1].[Id])" + - "WHERE (([t0].[Monitored] = {0}) AND ([t1].[Monitored] = {0})) AND {1}" + + "WHERE ({0}) AND {1}" + " AND NOT EXISTS (SELECT 1 from Tracks [t2] WHERE [t2].albumId = [t0].id AND [t2].trackFileId <> 0) ORDER BY {2} {3} LIMIT {4} OFFSET {5}", monitored, BuildReleaseDateCutoffWhereClause(currentTime), sortKey, pagingSpec.ToSortDirection(), pagingSpec.PageSize, pagingSpec.PagingOffset()); diff --git a/src/NzbDrone.Core/Music/Artist.cs b/src/NzbDrone.Core/Music/Artist.cs index 0fc638803..f09048fb5 100644 --- a/src/NzbDrone.Core/Music/Artist.cs +++ b/src/NzbDrone.Core/Music/Artist.cs @@ -58,30 +58,19 @@ namespace NzbDrone.Core.Music { ForeignArtistId = otherArtist.ForeignArtistId; - MBId = otherArtist.MBId; - TADBId = otherArtist.TADBId; - DiscogsId = otherArtist.DiscogsId; - AMId = otherArtist.AMId; - Name = otherArtist.Name; - NameSlug = otherArtist.NameSlug; - CleanName = otherArtist.CleanName; - Monitored = otherArtist.Monitored; - AlbumFolder = otherArtist.AlbumFolder; - LastInfoSync = otherArtist.LastInfoSync; - Images = otherArtist.Images; + Path = otherArtist.Path; - Genres = otherArtist.Genres; - RootFolderPath = otherArtist.RootFolderPath; - Added = otherArtist.Added; + Profile = otherArtist.Profile; - ProfileId = otherArtist.ProfileId; + Albums = otherArtist.Albums; + + ProfileId = otherArtist.ProfileId; Tags = otherArtist.Tags; AddOptions = otherArtist.AddOptions; - Ratings = otherArtist.Ratings; - Members = otherArtist.Members; - - + RootFolderPath = otherArtist.RootFolderPath; + Monitored = otherArtist.Monitored; + AlbumFolder = otherArtist.AlbumFolder; } } diff --git a/src/NzbDrone.Core/Music/MonitoringOptions.cs b/src/NzbDrone.Core/Music/MonitoringOptions.cs new file mode 100644 index 000000000..2d345786e --- /dev/null +++ b/src/NzbDrone.Core/Music/MonitoringOptions.cs @@ -0,0 +1,11 @@ +using NzbDrone.Core.Datastore; + +namespace NzbDrone.Core.Music +{ + public class MonitoringOptions : IEmbeddedDocument + { + public bool IgnoreTracksWithFiles { get; set; } + public bool IgnoreTracksWithoutFiles { get; set; } + public bool Monitored { get; set; } + } +} diff --git a/src/NzbDrone.Core/Music/TrackMonitoredService.cs b/src/NzbDrone.Core/Music/TrackMonitoredService.cs new file mode 100644 index 000000000..da834f861 --- /dev/null +++ b/src/NzbDrone.Core/Music/TrackMonitoredService.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NLog; +using NzbDrone.Common.Extensions; + +namespace NzbDrone.Core.Music +{ + public interface ITrackMonitoredService + { + void SetTrackMonitoredStatus(Artist album, MonitoringOptions monitoringOptions); + } + + public class TrackMonitoredService : ITrackMonitoredService + { + private readonly IArtistService _albumService; + private readonly ITrackService _trackService; + private readonly Logger _logger; + + public TrackMonitoredService(IArtistService albumService, ITrackService trackService, Logger logger) + { + _albumService = albumService; + _trackService = trackService; + _logger = logger; + } + + public void SetTrackMonitoredStatus(Artist album, MonitoringOptions monitoringOptions) + { + if (monitoringOptions != null) + { + _logger.Debug("[{0}] Setting track monitored status.", album.Name); + + var tracks = _trackService.GetTracksByArtist(album.Id); + + if (monitoringOptions.IgnoreTracksWithFiles) + { + _logger.Debug("Ignoring Tracks with Files"); + ToggleTracksMonitoredState(tracks.Where(e => e.HasFile), false); + } + + else + { + _logger.Debug("Monitoring Tracks with Files"); + ToggleTracksMonitoredState(tracks.Where(e => e.HasFile), true); + } + + if (monitoringOptions.IgnoreTracksWithoutFiles) + { + _logger.Debug("Ignoring Tracks without Files"); + ToggleTracksMonitoredState(tracks.Where(e => !e.HasFile), false); + } + + else + { + _logger.Debug("Monitoring Episodes without Files"); + ToggleTracksMonitoredState(tracks.Where(e => !e.HasFile), true); + } + + _trackService.UpdateTracks(tracks); + } + + _albumService.UpdateArtist(album); + } + + private void ToggleTracksMonitoredState(IEnumerable tracks, bool monitored) + { + foreach (var track in tracks) + { + track.Monitored = monitored; + } + } + } +} diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index a57e58607..7711a501a 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -865,6 +865,9 @@ + + + diff --git a/src/NzbDrone.Core/Tv/MonitoringOptions.cs b/src/NzbDrone.Core/Tv/MonitoringOptions.cs index 760ec68ec..2cda68b1c 100644 --- a/src/NzbDrone.Core/Tv/MonitoringOptions.cs +++ b/src/NzbDrone.Core/Tv/MonitoringOptions.cs @@ -6,8 +6,5 @@ namespace NzbDrone.Core.Tv { public bool IgnoreEpisodesWithFiles { get; set; } public bool IgnoreEpisodesWithoutFiles { get; set; } - - public bool IgnoreTracksWithFiles { get; set; } - public bool IgnoreTracksWithoutFiles { get; set; } } } diff --git a/src/UI/AlbumStudio/AlbumStudioCollectionView.js b/src/UI/AlbumStudio/AlbumStudioCollectionView.js new file mode 100644 index 000000000..b844743c2 --- /dev/null +++ b/src/UI/AlbumStudio/AlbumStudioCollectionView.js @@ -0,0 +1,25 @@ +var _ = require('underscore'); +var Marionette = require('marionette'); +var SingleAlbumCell = require('./SingleAlbumCell'); +var AsSortedCollectionView = require('../Mixins/AsSortedCollectionView'); + +var view = Marionette.CollectionView.extend({ + + itemView : SingleAlbumCell, + + initialize : function(options) { + this.albumCollection = options.collection; + this.artist = options.artist; + }, + + itemViewOptions : function() { + return { + albumCollection : this.albumCollection, + artist : this.artist + }; + } +}); + +AsSortedCollectionView.call(view); + +module.exports = view; \ No newline at end of file diff --git a/src/UI/SeasonPass/SeasonPassFooterView.js b/src/UI/AlbumStudio/AlbumStudioFooterView.js similarity index 57% rename from src/UI/SeasonPass/SeasonPassFooterView.js rename to src/UI/AlbumStudio/AlbumStudioFooterView.js index f7d02706c..2726b0803 100644 --- a/src/UI/SeasonPass/SeasonPassFooterView.js +++ b/src/UI/AlbumStudio/AlbumStudioFooterView.js @@ -5,13 +5,13 @@ var vent = require('vent'); var RootFolders = require('../AddArtist/RootFolders/RootFolderCollection'); module.exports = Marionette.ItemView.extend({ - template : 'SeasonPass/SeasonPassFooterViewTemplate', + template : 'AlbumStudio/AlbumStudioFooterViewTemplate', ui : { - seriesMonitored : '.x-series-monitored', + artistMonitored : '.x-artist-monitored', monitor : '.x-monitor', selectedCount : '.x-selected-count', - container : '.series-editor-footer', + container : '.artist-editor-footer', actions : '.x-action', indicator : '.x-indicator', indicatorIcon : '.x-indicator-icon' @@ -22,14 +22,14 @@ module.exports = Marionette.ItemView.extend({ }, initialize : function(options) { - this.seriesCollection = options.collection; + this.artistCollection = options.collection; RootFolders.fetch().done(function() { RootFolders.synced = true; }); this.editorGrid = options.editorGrid; - this.listenTo(this.seriesCollection, 'backgrid:selected', this._updateInfo); + this.listenTo(this.artistCollection, 'backgrid:selected', this._updateInfo); }, onRender : function() { @@ -39,13 +39,13 @@ module.exports = Marionette.ItemView.extend({ _update : function() { var self = this; var selected = this.editorGrid.getSelectedModels(); - var seriesMonitored = this.ui.seriesMonitored.val(); + var artistMonitored = this.ui.artistMonitored.val(); var monitoringOptions; _.each(selected, function(model) { - if (seriesMonitored === 'true') { + if (artistMonitored === 'true') { model.set('monitored', true); - } else if (seriesMonitored === 'false') { + } else if (artistMonitored === 'false') { model.set('monitored', false); } @@ -54,10 +54,10 @@ module.exports = Marionette.ItemView.extend({ }); var promise = $.ajax({ - url : window.NzbDrone.ApiRoot + '/seasonpass', + url : window.NzbDrone.ApiRoot + '/albumstudio', type : 'POST', data : JSON.stringify({ - series : _.map(selected, function (model) { + artist : _.map(selected, function (model) { return model.toJSON(); }), monitoringOptions : monitoringOptions @@ -71,7 +71,7 @@ module.exports = Marionette.ItemView.extend({ }); promise.done(function () { - self.seriesCollection.trigger('seasonpass:saved'); + self.artistCollection.trigger('albumstudio:saved'); }); }, @@ -79,7 +79,7 @@ module.exports = Marionette.ItemView.extend({ var selected = this.editorGrid.getSelectedModels(); var selectedCount = selected.length; - this.ui.selectedCount.html('{0} series selected'.format(selectedCount)); + this.ui.selectedCount.html('{0} artists selected'.format(selectedCount)); if (selectedCount === 0) { this.ui.actions.attr('disabled', 'disabled'); @@ -90,48 +90,25 @@ module.exports = Marionette.ItemView.extend({ _getMonitoringOptions : function(model) { var monitor = this.ui.monitor.val(); - var lastSeason = _.max(model.get('seasons'), 'seasonNumber'); - var firstSeason = _.min(_.reject(model.get('seasons'), { seasonNumber : 0 }), 'seasonNumber'); if (monitor === 'noChange') { return null; } - model.setSeasonPass(firstSeason.seasonNumber); + model.setAlbumPass(0); var options = { - ignoreEpisodesWithFiles : false, - ignoreEpisodesWithoutFiles : false + ignoreTracksWithFiles : false, + ignoreTracksWithoutFiles : false, + monitored : true }; if (monitor === 'all') { return options; } - else if (monitor === 'future') { - options.ignoreEpisodesWithFiles = true; - options.ignoreEpisodesWithoutFiles = true; - } - - else if (monitor === 'latest') { - model.setSeasonPass(lastSeason.seasonNumber); - } - - else if (monitor === 'first') { - model.setSeasonPass(lastSeason.seasonNumber + 1); - model.setSeasonMonitored(firstSeason.seasonNumber); - } - - else if (monitor === 'missing') { - options.ignoreEpisodesWithFiles = true; - } - - else if (monitor === 'existing') { - options.ignoreEpisodesWithoutFiles = true; - } - else if (monitor === 'none') { - model.setSeasonPass(lastSeason.seasonNumber + 1); + options.monitored = false; } return options; diff --git a/src/UI/SeasonPass/SeasonPassFooterViewTemplate.hbs b/src/UI/AlbumStudio/AlbumStudioFooterViewTemplate.hbs similarity index 60% rename from src/UI/SeasonPass/SeasonPassFooterViewTemplate.hbs rename to src/UI/AlbumStudio/AlbumStudioFooterViewTemplate.hbs index c0178ba8e..35987aa7f 100644 --- a/src/UI/SeasonPass/SeasonPassFooterViewTemplate.hbs +++ b/src/UI/AlbumStudio/AlbumStudioFooterViewTemplate.hbs @@ -1,9 +1,9 @@ -