mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-30 11:48:26 -07:00
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
This commit is contained in:
parent
bb196e19e1
commit
dcde579a43
44 changed files with 640 additions and 242 deletions
31
src/NzbDrone.Api/AlbumStudio/AlbumStudioModule.cs
Normal file
31
src/NzbDrone.Api/AlbumStudio/AlbumStudioModule.cs
Normal file
|
@ -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<AlbumStudioResource>();
|
||||
|
||||
foreach (var s in request.Artist)
|
||||
{
|
||||
_albumMonitoredService.SetAlbumMonitoredStatus(s, request.MonitoringOptions);
|
||||
}
|
||||
|
||||
return "ok".AsResponse(HttpStatusCode.Accepted);
|
||||
}
|
||||
}
|
||||
}
|
11
src/NzbDrone.Api/AlbumStudio/AlbumStudioResource.cs
Normal file
11
src/NzbDrone.Api/AlbumStudio/AlbumStudioResource.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Api.AlbumPass
|
||||
{
|
||||
public class AlbumStudioResource
|
||||
{
|
||||
public List<Core.Music.Artist> Artist { get; set; }
|
||||
public MonitoringOptions MonitoringOptions { get; set; }
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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<AlbumResource, Track>
|
||||
{
|
||||
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)
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace NzbDrone.Api.Albums
|
|||
public List<string> Genres { get; set; }
|
||||
public ArtistResource Artist { get; set; }
|
||||
public List<MediaCover> Images { get; set; }
|
||||
public AlbumStatisticsResource Statistics { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
|
45
src/NzbDrone.Api/Albums/AlbumStatisticsResource.cs
Normal file
45
src/NzbDrone.Api/Albums/AlbumStatisticsResource.cs
Normal file
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace NzbDrone.Api.Music
|
|||
public string RootFolderPath { get; set; }
|
||||
//public string Certification { get; set; }
|
||||
public List<string> Genres { get; set; }
|
||||
public string CleanName { get; set; }
|
||||
public HashSet<int> 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,
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Albums\AlbumModuleWithSignalR.cs" />
|
||||
<Compile Include="Albums\AlbumStatisticsResource.cs" />
|
||||
<Compile Include="Authentication\AuthenticationService.cs" />
|
||||
<Compile Include="Authentication\EnableAuthInNancy.cs" />
|
||||
<Compile Include="Authentication\AuthenticationModule.cs" />
|
||||
|
@ -105,6 +106,8 @@
|
|||
<Compile Include="ClientSchema\SelectOption.cs" />
|
||||
<Compile Include="Commands\CommandModule.cs" />
|
||||
<Compile Include="Commands\CommandResource.cs" />
|
||||
<Compile Include="AlbumStudio\AlbumStudioModule.cs" />
|
||||
<Compile Include="AlbumStudio\AlbumStudioResource.cs" />
|
||||
<Compile Include="TrackFiles\TrackFileModule.cs" />
|
||||
<Compile Include="TrackFiles\TrackFileResource.cs" />
|
||||
<Compile Include="Albums\AlbumModule.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;
|
||||
}
|
||||
|
|
69
src/NzbDrone.Core/Music/AlbumMonitoredService.cs
Normal file
69
src/NzbDrone.Core/Music/AlbumMonitoredService.cs
Normal file
|
@ -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<Album> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -75,11 +75,11 @@ namespace NzbDrone.Core.Music
|
|||
private QueryBuilder<Album> GetMissingAlbumsQuery(PagingSpec<Album> 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());
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
11
src/NzbDrone.Core/Music/MonitoringOptions.cs
Normal file
11
src/NzbDrone.Core/Music/MonitoringOptions.cs
Normal file
|
@ -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; }
|
||||
}
|
||||
}
|
73
src/NzbDrone.Core/Music/TrackMonitoredService.cs
Normal file
73
src/NzbDrone.Core/Music/TrackMonitoredService.cs
Normal file
|
@ -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<Track> tracks, bool monitored)
|
||||
{
|
||||
foreach (var track in tracks)
|
||||
{
|
||||
track.Monitored = monitored;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -865,6 +865,9 @@
|
|||
<Compile Include="Extras\Metadata\MetadataType.cs" />
|
||||
<Compile Include="MetadataSource\IProvideSeriesInfo.cs" />
|
||||
<Compile Include="MetadataSource\ISearchForNewSeries.cs" />
|
||||
<Compile Include="Music\MonitoringOptions.cs" />
|
||||
<Compile Include="Music\AlbumMonitoredService.cs" />
|
||||
<Compile Include="Music\TrackMonitoredService.cs" />
|
||||
<Compile Include="Music\Member.cs" />
|
||||
<Compile Include="Music\AddArtistOptions.cs" />
|
||||
<Compile Include="Music\AddArtistService.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; }
|
||||
}
|
||||
}
|
||||
|
|
25
src/UI/AlbumStudio/AlbumStudioCollectionView.js
Normal file
25
src/UI/AlbumStudio/AlbumStudioCollectionView.js
Normal file
|
@ -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;
|
|
@ -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;
|
|
@ -1,9 +1,9 @@
|
|||
<div class="series-editor-footer">
|
||||
<div class="artist-editor-footer">
|
||||
<div class="row">
|
||||
<div class="form-group col-md-2">
|
||||
<label>Monitor series</label>
|
||||
<label>Monitor artist</label>
|
||||
|
||||
<select class="form-control x-action x-series-monitored">
|
||||
<select class="form-control x-action x-artist-monitored">
|
||||
<option value="noChange">No change</option>
|
||||
<option value="true">Monitored</option>
|
||||
<option value="false">Unmonitored</option>
|
||||
|
@ -11,24 +11,19 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group col-md-2">
|
||||
<label>Monitor episodes</label>
|
||||
<label>Monitor albums</label>
|
||||
|
||||
<select class="form-control x-action x-monitor">
|
||||
<option value="noChange">No change</option>
|
||||
<option value="all">All</option>
|
||||
<option value="future">Future</option>
|
||||
<option value="missing">Missing</option>
|
||||
<option value="existing">Existing</option>
|
||||
<option value="first">First Season</option>
|
||||
<option value="latest">Latest Season</option>
|
||||
<option value="none">None</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-3 actions">
|
||||
<label class="x-selected-count">0 series selected</label>
|
||||
<label class="x-selected-count">0 artists selected</label>
|
||||
<div>
|
||||
<button class="btn btn-primary x-action x-update">Update Selected Series</button>
|
||||
<button class="btn btn-primary x-action x-update">Update Selected Artist</button>
|
||||
<span class="indicator x-indicator"><i class="icon-lidarr-spinner fa-spin"></i></span>
|
||||
</div>
|
||||
</div>
|
|
@ -2,23 +2,23 @@ var _ = require('underscore');
|
|||
var vent = require('vent');
|
||||
var Backgrid = require('backgrid');
|
||||
var Marionette = require('marionette');
|
||||
var EmptyView = require('../Series/Index/EmptyView');
|
||||
var SeriesCollection = require('../Series/SeriesCollection');
|
||||
var EmptyView = require('../Artist/Index/EmptyView');
|
||||
var ArtistCollection = require('../Artist/ArtistCollection');
|
||||
var ToolbarLayout = require('../Shared/Toolbar/ToolbarLayout');
|
||||
var FooterView = require('./SeasonPassFooterView');
|
||||
var FooterView = require('./AlbumStudioFooterView');
|
||||
var SelectAllCell = require('../Cells/SelectAllCell');
|
||||
var SeriesStatusCell = require('../Cells/SeriesStatusCell');
|
||||
var SeriesTitleCell = require('../Cells/SeriesTitleCell');
|
||||
var SeriesMonitoredCell = require('../Cells/ToggleCell');
|
||||
var SeasonsCell = require('./SeasonsCell');
|
||||
var ArtistStatusCell = require('../Cells/ArtistStatusCell');
|
||||
var ArtistTitleCell = require('../Cells/ArtistTitleCell');
|
||||
var ArtistMonitoredCell = require('../Cells/ArtistMonitoredCell');
|
||||
var AlbumsCell = require('./AlbumsCell');
|
||||
require('../Mixins/backbone.signalr.mixin');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'SeasonPass/SeasonPassLayoutTemplate',
|
||||
template : 'AlbumStudio/AlbumStudioLayoutTemplate',
|
||||
|
||||
regions : {
|
||||
toolbar : '#x-toolbar',
|
||||
series : '#x-series'
|
||||
artist : '#x-artist'
|
||||
},
|
||||
|
||||
columns : [
|
||||
|
@ -31,42 +31,38 @@ module.exports = Marionette.Layout.extend({
|
|||
{
|
||||
name : 'statusWeight',
|
||||
label : '',
|
||||
cell : SeriesStatusCell
|
||||
},
|
||||
{
|
||||
name : 'title',
|
||||
label : 'Title',
|
||||
cell : SeriesTitleCell,
|
||||
cellValue : 'this'
|
||||
cell : ArtistStatusCell
|
||||
},
|
||||
{
|
||||
name : 'monitored',
|
||||
label : '',
|
||||
cell : SeriesMonitoredCell,
|
||||
label : 'Artist',
|
||||
cell : ArtistMonitoredCell,
|
||||
trueClass : 'icon-lidarr-monitored',
|
||||
falseClass : 'icon-lidarr-unmonitored',
|
||||
tooltip : 'Toggle series monitored status',
|
||||
tooltip : 'Toggle artist monitored status',
|
||||
sortable : false
|
||||
},
|
||||
|
||||
{
|
||||
name : 'seasons',
|
||||
label : 'Seasons',
|
||||
cell : SeasonsCell,
|
||||
name : 'albums',
|
||||
label : 'Albums',
|
||||
cell : AlbumsCell,
|
||||
cellValue : 'this'
|
||||
}
|
||||
],
|
||||
|
||||
initialize : function() {
|
||||
this.seriesCollection = SeriesCollection.clone();
|
||||
this.seriesCollection.shadowCollection.bindSignalR();
|
||||
this.artistCollection = ArtistCollection.clone();
|
||||
|
||||
// this.listenTo(this.seriesCollection, 'sync', this.render);
|
||||
this.listenTo(this.seriesCollection, 'seasonpass:saved', this.render);
|
||||
this.artistCollection.shadowCollection.bindSignalR();
|
||||
|
||||
this.listenTo(this.artistCollection, 'sync', this.render);
|
||||
this.listenTo(this.artistCollection, 'albumstudio:saved', this.render);
|
||||
|
||||
this.filteringOptions = {
|
||||
type : 'radio',
|
||||
storeState : true,
|
||||
menuKey : 'seasonpass.filterMode',
|
||||
menuKey : 'albumstudio.filterMode',
|
||||
defaultAction : 'all',
|
||||
items : [
|
||||
{
|
||||
|
@ -87,14 +83,14 @@ module.exports = Marionette.Layout.extend({
|
|||
key : 'continuing',
|
||||
title : '',
|
||||
tooltip : 'Continuing Only',
|
||||
icon : 'icon-lidarr-series-continuing',
|
||||
icon : 'icon-lidarr-artist-continuing',
|
||||
callback : this._setFilter
|
||||
},
|
||||
{
|
||||
key : 'ended',
|
||||
title : '',
|
||||
tooltip : 'Ended Only',
|
||||
icon : 'icon-lidarr-series-ended',
|
||||
icon : 'icon-lidarr-artist-ended',
|
||||
callback : this._setFilter
|
||||
}
|
||||
]
|
||||
|
@ -119,34 +115,34 @@ module.exports = Marionette.Layout.extend({
|
|||
},
|
||||
|
||||
_showTable : function() {
|
||||
if (this.seriesCollection.shadowCollection.length === 0) {
|
||||
this.series.show(new EmptyView());
|
||||
if (this.artistCollection.shadowCollection.length === 0) {
|
||||
this.artist.show(new EmptyView());
|
||||
this.toolbar.close();
|
||||
return;
|
||||
}
|
||||
|
||||
this.columns[0].sortedCollection = this.seriesCollection;
|
||||
this.columns[0].sortedCollection = this.artistCollection;
|
||||
|
||||
this.editorGrid = new Backgrid.Grid({
|
||||
collection : this.seriesCollection,
|
||||
collection : this.artistCollection,
|
||||
columns : this.columns,
|
||||
className : 'table table-hover'
|
||||
});
|
||||
|
||||
this.series.show(this.editorGrid);
|
||||
this.artist.show(this.editorGrid);
|
||||
this._showFooter();
|
||||
},
|
||||
|
||||
_showFooter : function() {
|
||||
vent.trigger(vent.Commands.OpenControlPanelCommand, new FooterView({
|
||||
editorGrid : this.editorGrid,
|
||||
collection : this.seriesCollection
|
||||
collection : this.artistCollection
|
||||
}));
|
||||
},
|
||||
|
||||
_setFilter : function(buttonContext) {
|
||||
var mode = buttonContext.model.get('key');
|
||||
|
||||
this.seriesCollection.setFilterMode(mode);
|
||||
this.artistCollection.setFilterMode(mode);
|
||||
}
|
||||
});
|
14
src/UI/AlbumStudio/AlbumStudioLayoutTemplate.hbs
Normal file
14
src/UI/AlbumStudio/AlbumStudioLayoutTemplate.hbs
Normal file
|
@ -0,0 +1,14 @@
|
|||
<h1>Album Studio</h1>
|
||||
<div id="x-toolbar"></div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert-info">Album Studio allows you to quickly change the monitored status of albums for all your artists in one place</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="x-artist"></div>
|
||||
</div>
|
||||
</div>
|
58
src/UI/AlbumStudio/AlbumsCell.js
Normal file
58
src/UI/AlbumStudio/AlbumsCell.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
var $ = require('jquery');
|
||||
var _ = require('underscore');
|
||||
var vent = require('vent');
|
||||
var Marionette = require('marionette');
|
||||
var TemplatedCell = require('../Cells/TemplatedCell');
|
||||
var AlbumCollection = require('../Artist/AlbumCollection');
|
||||
var LoadingView = require('../Shared/LoadingView');
|
||||
var ArtistCollection = require('../Artist/ArtistCollection');
|
||||
var AlbumCollectionView = require('./AlbumStudioCollectionView');
|
||||
//require('../Handlebars/Helpers/Numbers');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'AlbumStudio/AlbumsCellTemplate',
|
||||
|
||||
regions : {
|
||||
albums : '#albums'
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
this.artistCollection = ArtistCollection.clone();
|
||||
this.artistCollection.shadowCollection.bindSignalR();
|
||||
|
||||
this.listenTo(this.model, 'change:monitored', this._setMonitoredState);
|
||||
this.listenTo(this.model, 'remove', this._artistRemoved);
|
||||
this.listenTo(vent, vent.Events.CommandComplete, this._commandComplete);
|
||||
|
||||
this.listenTo(this.model, 'change', function(model, options) {
|
||||
if (options && options.changeSource === 'signalr') {
|
||||
this._refresh();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onRender : function(){
|
||||
this._showAlbums();
|
||||
},
|
||||
|
||||
_showAlbums : function() {
|
||||
var self = this;
|
||||
|
||||
this.albums.show(new LoadingView());
|
||||
|
||||
this.albumCollection = new AlbumCollection({ artistId : this.model.id }).bindSignalR();
|
||||
|
||||
$.when(this.albumCollection.fetch()).done(function() {
|
||||
var albumCollectionView = new AlbumCollectionView({
|
||||
collection : self.albumCollection,
|
||||
artist : self.model
|
||||
});
|
||||
|
||||
if (!self.isClosed) {
|
||||
self.albums.show(albumCollectionView);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
});
|
1
src/UI/AlbumStudio/AlbumsCellTemplate.hbs
Normal file
1
src/UI/AlbumStudio/AlbumsCellTemplate.hbs
Normal file
|
@ -0,0 +1 @@
|
|||
<div id="albums" class="artist-albums"></div>
|
64
src/UI/AlbumStudio/SingleAlbumCell.js
Normal file
64
src/UI/AlbumStudio/SingleAlbumCell.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
var vent = require('vent');
|
||||
var Marionette = require('marionette');
|
||||
var Backgrid = require('backgrid');
|
||||
var ToggleCell = require('../Cells/TrackMonitoredCell');
|
||||
var CommandController = require('../Commands/CommandController');
|
||||
var moment = require('moment');
|
||||
var _ = require('underscore');
|
||||
var Messenger = require('../Shared/Messenger');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'AlbumStudio/SingleAlbumCellTemplate',
|
||||
|
||||
ui : {
|
||||
albumMonitored : '.x-album-monitored'
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-album-monitored' : '_albumMonitored'
|
||||
},
|
||||
|
||||
|
||||
initialize : function(options) {
|
||||
this.artist = options.artist;
|
||||
this.listenTo(this.model, 'sync', this._afterAlbumMonitored);
|
||||
|
||||
},
|
||||
|
||||
onRender : function() {
|
||||
this._setAlbumMonitoredState();
|
||||
},
|
||||
|
||||
_albumMonitored : function() {
|
||||
if (!this.artist.get('monitored')) {
|
||||
|
||||
Messenger.show({
|
||||
message : 'Unable to change monitored state when artist is not monitored',
|
||||
type : 'error'
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var savePromise = this.model.save('monitored', !this.model.get('monitored'), { wait : true });
|
||||
|
||||
this.ui.albumMonitored.spinForPromise(savePromise);
|
||||
},
|
||||
|
||||
_afterAlbumMonitored : function() {
|
||||
this.render();
|
||||
},
|
||||
|
||||
_setAlbumMonitoredState : function() {
|
||||
this.ui.albumMonitored.removeClass('icon-lidarr-spinner fa-spin');
|
||||
|
||||
if (this.model.get('monitored')) {
|
||||
this.ui.albumMonitored.addClass('icon-lidarr-monitored');
|
||||
this.ui.albumMonitored.removeClass('icon-lidarr-unmonitored');
|
||||
} else {
|
||||
this.ui.albumMonitored.addClass('icon-lidarr-unmonitored');
|
||||
this.ui.albumMonitored.removeClass('icon-lidarr-monitored');
|
||||
}
|
||||
}
|
||||
|
||||
});
|
30
src/UI/AlbumStudio/SingleAlbumCellTemplate.hbs
Normal file
30
src/UI/AlbumStudio/SingleAlbumCellTemplate.hbs
Normal file
|
@ -0,0 +1,30 @@
|
|||
{{#if_eq statistics.totalTrackCount compare=0}}
|
||||
<span class="album album-unaired">
|
||||
{{else}}
|
||||
{{#if_eq statistics.percentOfTracks compare=100}}
|
||||
<span class="album album-all">
|
||||
{{else}}
|
||||
<span class="album album-partial">
|
||||
{{/if_eq}}
|
||||
{{/if_eq}}
|
||||
<span class="label">
|
||||
<span class="x-album-monitored album-monitored" title="Toggle album monitored status" data-album-number="{{seasonNumber}}">
|
||||
|
||||
</span>
|
||||
<span class="album-number">{{Pad2 title}}</span>
|
||||
</span><span class="label">
|
||||
{{#with statistics}}
|
||||
{{#if_eq trackCount compare=0}}
|
||||
<span class="album-status" title="No aired tracks"> </span>
|
||||
{{else}}
|
||||
{{#if_eq percentOfEpisodes compare=100}}
|
||||
<span class="album-status" title="{{trackFileCount}}/{{trackCount}} tracks downloaded">{{trackFileCount}}/{{trackCount}}</span>
|
||||
{{else}}
|
||||
<span class="album-status" title="{{trackFileCount}}/{{trackCount}} tracks downloaded">{{trackFileCount}}/{{trackCount}}</span>
|
||||
{{/if_eq}}
|
||||
{{/if_eq}}
|
||||
{{else}}
|
||||
<span class="album-status" title="No aired tracks"> </span>
|
||||
{{/with}}
|
||||
</span>
|
||||
</span>
|
|
@ -1,7 +1,14 @@
|
|||
@import "../Content/badges.less";
|
||||
@import "../Shared/Styles/clickable.less";
|
||||
|
||||
.season {
|
||||
.artist-albums {
|
||||
div {
|
||||
display : inline-block;
|
||||
padding : 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.album {
|
||||
display : inline-block;
|
||||
margin-bottom : 4px;
|
||||
|
||||
|
@ -31,11 +38,11 @@
|
|||
background-color : #f7f7f7;
|
||||
}
|
||||
|
||||
&.season-all .label:last-child {
|
||||
&.album-all .label:last-child {
|
||||
background-color : #e0ffe0;
|
||||
}
|
||||
|
||||
.season-monitored {
|
||||
.album-monitored {
|
||||
width : 16px;
|
||||
|
||||
i {
|
||||
|
@ -43,11 +50,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
.season-number {
|
||||
.album-number {
|
||||
font-size : 12px;
|
||||
}
|
||||
|
||||
.season-status {
|
||||
.album-status {
|
||||
display : inline-block;
|
||||
vertical-align : baseline !important;
|
||||
}
|
|
@ -11,18 +11,17 @@ module.exports = Backbone.Model.extend({
|
|||
status : 0
|
||||
},
|
||||
|
||||
setAlbumsMonitored : function(albumName) {
|
||||
setAlbumsMonitored : function(albumId) {
|
||||
_.each(this.get('albums'), function(album) {
|
||||
console.log(album);
|
||||
if (album.albumName === albumName) {
|
||||
if (album.albumId === albumId) {
|
||||
album.monitored = !album.monitored;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setAlbumPass : function(seasonNumber) {
|
||||
setAlbumPass : function(monitored) {
|
||||
_.each(this.get('albums'), function(album) {
|
||||
if (album.seasonNumber >= seasonNumber) {
|
||||
if (monitored === 0) {
|
||||
album.monitored = true;
|
||||
} else {
|
||||
album.monitored = false;
|
||||
|
|
|
@ -11,7 +11,7 @@ var view = Marionette.CollectionView.extend({
|
|||
if (!options.trackCollection) {
|
||||
throw 'trackCollection is needed';
|
||||
}
|
||||
console.log(options);
|
||||
|
||||
this.albumCollection = options.collection;
|
||||
this.trackCollection = options.trackCollection;
|
||||
this.artist = options.artist;
|
||||
|
|
|
@ -132,11 +132,9 @@ module.exports = Marionette.Layout.extend({
|
|||
this.trackCollection = this.fullTrackCollection.byAlbum(this.model.get('id'));
|
||||
this._updateTrackCollection();
|
||||
|
||||
console.log(options);
|
||||
|
||||
this.showingTracks = this._shouldShowTracks();
|
||||
|
||||
this.listenTo(this.model, 'sync', this._afterSeasonMonitored);
|
||||
this.listenTo(this.model, 'sync', this._afterAlbumMonitored);
|
||||
this.listenTo(this.trackCollection, 'sync', this.render);
|
||||
this.listenTo(this.fullTrackCollection, 'sync', this._refreshTracks);
|
||||
this.listenTo(this.model, 'change:images', this._updateImages);
|
||||
|
@ -203,28 +201,20 @@ module.exports = Marionette.Layout.extend({
|
|||
if (!this.artist.get('monitored')) {
|
||||
|
||||
Messenger.show({
|
||||
message : 'Unable to change monitored state when series is not monitored',
|
||||
message : 'Unable to change monitored state when artist is not monitored',
|
||||
type : 'error'
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var name = 'monitored';
|
||||
this.model.set(name, !this.model.get(name));
|
||||
this.artist.setSeasonMonitored(this.model.get('albumId'));
|
||||
|
||||
var savePromise = this.artist.save().always(this._afterSeasonMonitored.bind(this));
|
||||
//var savePromise = this.model.save('monitored', !this.model.get('monitored'), { wait : true });
|
||||
var savePromise = this.model.save('monitored', !this.model.get('monitored'), { wait : true });
|
||||
|
||||
this.ui.albumMonitored.spinForPromise(savePromise);
|
||||
},
|
||||
|
||||
_afterSeasonMonitored : function() {
|
||||
var self = this;
|
||||
|
||||
_.each(this.trackCollection.models, function(track) {
|
||||
track.set({ monitored : self.model.get('monitored') });
|
||||
});
|
||||
_afterAlbumMonitored : function() {
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
|
|
@ -127,11 +127,11 @@ module.exports = Marionette.Layout.extend({
|
|||
if (monitored) {
|
||||
this.ui.monitored.addClass('icon-lidarr-monitored');
|
||||
this.ui.monitored.removeClass('icon-lidarr-unmonitored');
|
||||
this.$el.removeClass('series-not-monitored');
|
||||
this.$el.removeClass('artist-not-monitored');
|
||||
} else {
|
||||
this.ui.monitored.addClass('icon-lidarr-unmonitored');
|
||||
this.ui.monitored.removeClass('icon-lidarr-monitored');
|
||||
this.$el.addClass('series-not-monitored');
|
||||
this.$el.addClass('artist-not-monitored');
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -172,8 +172,6 @@ module.exports = Marionette.Layout.extend({
|
|||
this.trackCollection = new TrackCollection({ artistId : this.model.id }).bindSignalR();
|
||||
this.trackFileCollection = new TrackFileCollection({ artistId : this.model.id }).bindSignalR();
|
||||
|
||||
console.log (this.trackCollection);
|
||||
|
||||
reqres.setHandler(reqres.Requests.GetEpisodeFileById, function(trackFileId) {
|
||||
return self.trackFileCollection.get(trackFileId);
|
||||
});
|
||||
|
|
|
@ -72,9 +72,9 @@ module.exports = Marionette.Layout.extend({
|
|||
storeState : false,
|
||||
items : [
|
||||
{
|
||||
title : 'Season Pass',
|
||||
title : 'Album Studio',
|
||||
icon : 'icon-lidarr-monitored',
|
||||
route : 'seasonpass'
|
||||
route : 'albumstudio'
|
||||
},
|
||||
{
|
||||
title : 'Update Library',
|
||||
|
|
|
@ -86,9 +86,9 @@ module.exports = Marionette.Layout.extend({
|
|||
route : 'addartist'
|
||||
},
|
||||
{
|
||||
title : 'Season Pass',
|
||||
title : 'Album Studio',
|
||||
icon : 'icon-lidarr-monitored',
|
||||
route : 'seasonpass'
|
||||
route : 'albumstudio'
|
||||
},
|
||||
{
|
||||
title : 'Artist Editor',
|
||||
|
|
39
src/UI/Cells/ArtistMonitoredCell.js
Normal file
39
src/UI/Cells/ArtistMonitoredCell.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
var ToggleCell = require('./ToggleCell');
|
||||
var Handlebars = require('handlebars');
|
||||
|
||||
module.exports = ToggleCell.extend({
|
||||
className : 'artist-monitored-cell',
|
||||
|
||||
events : {
|
||||
'click i' : '_onClick'
|
||||
},
|
||||
|
||||
render : function() {
|
||||
|
||||
this.$el.empty();
|
||||
this.$el.html('<i /><a href=""><span class="artist-monitored-name"></span></a>');
|
||||
|
||||
var name = this.column.get('name');
|
||||
|
||||
if (this.model.get(name)) {
|
||||
this.$('i').addClass(this.column.get('trueClass'));
|
||||
} else {
|
||||
this.$('i').addClass(this.column.get('falseClass'));
|
||||
}
|
||||
|
||||
var link = "/artist/" + this.model.get('nameSlug');
|
||||
var artistName = this.model.get('name');
|
||||
|
||||
this.$('a').attr('href', link );
|
||||
this.$('span').html(artistName);
|
||||
|
||||
var tooltip = this.column.get('tooltip');
|
||||
|
||||
if (tooltip) {
|
||||
this.$('i').attr('title', tooltip);
|
||||
}
|
||||
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
}
|
||||
});
|
|
@ -15,7 +15,7 @@ module.exports = ToggleCell.extend({
|
|||
if (!artist.get('monitored')) {
|
||||
|
||||
Messenger.show({
|
||||
message : 'Unable to change monitored state when series is not monitored',
|
||||
message : 'Unable to change monitored state when artist is not monitored',
|
||||
type : 'error'
|
||||
});
|
||||
|
||||
|
|
|
@ -15,6 +15,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
.artist-monitored-cell {
|
||||
.text-overflow();
|
||||
|
||||
.artist-monitored-name {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.track-title-cell {
|
||||
.text-overflow();
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
@import "../Shared/FileBrowser/filebrowser";
|
||||
@import "badges";
|
||||
@import "../ManualImport/manualimport";
|
||||
@import "../SeasonPass/seasonpass";
|
||||
@import "../AlbumStudio/albumstudio";
|
||||
|
||||
.main-region {
|
||||
@media (min-width : @screen-lg-min) {
|
||||
|
|
|
@ -9,7 +9,7 @@ var WantedLayout = require('./Wanted/WantedLayout');
|
|||
var CalendarLayout = require('./Calendar/CalendarLayout');
|
||||
var ReleaseLayout = require('./Release/ReleaseLayout');
|
||||
var SystemLayout = require('./System/SystemLayout');
|
||||
var SeasonPassLayout = require('./SeasonPass/SeasonPassLayout');
|
||||
var AlbumStudioLayout = require('./AlbumStudio/AlbumStudioLayout');
|
||||
//var SeriesEditorLayout = require('./Series/Editor/SeriesEditorLayout');
|
||||
var ArtistEditorLayout = require('./Artist/Editor/ArtistEditorLayout');
|
||||
|
||||
|
@ -49,9 +49,9 @@ module.exports = NzbDroneController.extend({
|
|||
this.showMainRegion(new SystemLayout({ action : action }));
|
||||
},
|
||||
|
||||
seasonPass : function() {
|
||||
this.setTitle('Season Pass');
|
||||
this.showMainRegion(new SeasonPassLayout());
|
||||
albumStudio : function() {
|
||||
this.setTitle('Album Studio');
|
||||
this.showMainRegion(new AlbumStudioLayout());
|
||||
},
|
||||
|
||||
artistEditor : function() {
|
||||
|
|
|
@ -18,7 +18,7 @@ module.exports = Marionette.AppRouter.extend({
|
|||
'rss' : 'rss',
|
||||
'system' : 'system',
|
||||
'system/:action' : 'system',
|
||||
'seasonpass' : 'seasonPass',
|
||||
'albumstudio' : 'albumStudio',
|
||||
'artisteditor' : 'artistEditor',
|
||||
':whatever' : 'showNotFound'
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
<div id="x-toolbar"></div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert-info">Season Pass allows you to quickly change the monitored status of seasons for all your series in one place</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="x-series"></div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,26 +0,0 @@
|
|||
var _ = require('underscore');
|
||||
var TemplatedCell = require('../Cells/TemplatedCell');
|
||||
//require('../Handlebars/Helpers/Numbers');
|
||||
|
||||
module.exports = TemplatedCell.extend({
|
||||
className : 'seasons-cell',
|
||||
template : 'SeasonPass/SeasonsCellTemplate',
|
||||
|
||||
events : {
|
||||
'click .x-season-monitored' : '_toggleSeasonMonitored'
|
||||
},
|
||||
|
||||
_toggleSeasonMonitored : function(e) {
|
||||
var target = this.$(e.target).closest('.x-season-monitored');
|
||||
var seasonNumber = parseInt(this.$(target).data('season-number'), 10);
|
||||
var icon = this.$(target).children('.x-season-monitored-icon');
|
||||
|
||||
this.model.setSeasonMonitored(seasonNumber);
|
||||
|
||||
//TODO: unbounce the save so we don't multiple to the server at the same time
|
||||
var savePromise = this.model.save();
|
||||
|
||||
icon.spinForPromise(savePromise);
|
||||
savePromise.always(this.render.bind(this));
|
||||
}
|
||||
});
|
|
@ -1,37 +0,0 @@
|
|||
{{#each seasons}}
|
||||
{{debug}}
|
||||
{{#if_eq statistics.totalEpisodeCount compare=0}}
|
||||
<span class="season season-unaired">
|
||||
{{else}}
|
||||
{{#if_eq statistics.percentOfEpisodes compare=100}}
|
||||
<span class="season season-all">
|
||||
{{else}}
|
||||
<span class="season season-partial">
|
||||
{{/if_eq}}
|
||||
{{/if_eq}}
|
||||
<span class="label">
|
||||
<span class="x-season-monitored season-monitored" title="Toggle season monitored status" data-season-number="{{seasonNumber}}">
|
||||
<i class="x-season-monitored-icon {{#if monitored}}icon-lidarr-monitored{{else}}icon-lidarr-unmonitored{{/if}}"/>
|
||||
</span>
|
||||
{{#if_eq seasonNumber compare="0"}}
|
||||
<span class="season-number">Specials</span>
|
||||
{{else}}
|
||||
<span class="season-number">S{{Pad2 seasonNumber}}</span>
|
||||
{{/if_eq}}
|
||||
</span><span class="label">
|
||||
{{#with statistics}}
|
||||
{{#if_eq totalEpisodeCount compare=0}}
|
||||
<span class="season-status" title="No aired episodes"> </span>
|
||||
{{else}}
|
||||
{{#if_eq percentOfEpisodes compare=100}}
|
||||
<span class="season-status" title="{{episodeFileCount}}/{{totalEpisodeCount}} episodes downloaded">{{episodeFileCount}}/{{totalEpisodeCount}}</span>
|
||||
{{else}}
|
||||
<span class="season-status" title="{{episodeFileCount}}/{{totalEpisodeCount}} episodes downloaded">{{episodeFileCount}}/{{totalEpisodeCount}}</span>
|
||||
{{/if_eq}}
|
||||
{{/if_eq}}
|
||||
{{else}}
|
||||
<span class="season-status" title="No aired episodes"> </span>
|
||||
{{/with}}
|
||||
</span>
|
||||
</span>
|
||||
{{/each}}
|
|
@ -107,9 +107,9 @@ module.exports = Marionette.Layout.extend({
|
|||
className : 'x-search-selected'
|
||||
},
|
||||
{
|
||||
title : 'Season Pass',
|
||||
title : 'Album Studio',
|
||||
icon : 'icon-lidarr-monitored',
|
||||
route : 'seasonpass'
|
||||
route : 'albumstudio'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
|
@ -126,9 +126,9 @@ module.exports = Marionette.Layout.extend({
|
|||
className : 'x-unmonitor-selected'
|
||||
},
|
||||
{
|
||||
title : 'Season Pass',
|
||||
title : 'Album Studio',
|
||||
icon : 'icon-lidarr-monitored',
|
||||
route : 'seasonpass'
|
||||
route : 'albumstudio'
|
||||
},
|
||||
{
|
||||
title : 'Rescan Drone Factory Folder',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue