mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-31 12:10:19 -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 System.Collections.Generic;
|
||||||
using NzbDrone.Api.REST;
|
using NzbDrone.Api.REST;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
|
using NzbDrone.Core.ArtistStats;
|
||||||
using NzbDrone.Core.DecisionEngine;
|
using NzbDrone.Core.DecisionEngine;
|
||||||
using NzbDrone.SignalR;
|
using NzbDrone.SignalR;
|
||||||
|
|
||||||
|
@ -9,10 +10,11 @@ namespace NzbDrone.Api.Albums
|
||||||
public class AlbumModule : AlbumModuleWithSignalR
|
public class AlbumModule : AlbumModuleWithSignalR
|
||||||
{
|
{
|
||||||
public AlbumModule(IArtistService artistService,
|
public AlbumModule(IArtistService artistService,
|
||||||
|
IArtistStatisticsService artistStatisticsService,
|
||||||
IAlbumService albumService,
|
IAlbumService albumService,
|
||||||
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
||||||
IBroadcastSignalRMessage signalRBroadcaster)
|
IBroadcastSignalRMessage signalRBroadcaster)
|
||||||
: base(albumService, artistService, qualityUpgradableSpecification, signalRBroadcaster)
|
: base(albumService, artistStatisticsService, artistService, qualityUpgradableSpecification, signalRBroadcaster)
|
||||||
{
|
{
|
||||||
GetResourceAll = GetAlbums;
|
GetResourceAll = GetAlbums;
|
||||||
UpdateResource = SetMonitored;
|
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.Common.Extensions;
|
||||||
using NzbDrone.Api.TrackFiles;
|
using NzbDrone.Api.TrackFiles;
|
||||||
using NzbDrone.Api.Music;
|
using NzbDrone.Api.Music;
|
||||||
|
@ -8,6 +11,7 @@ using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.MediaFiles.Events;
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
|
using NzbDrone.Core.ArtistStats;
|
||||||
using NzbDrone.SignalR;
|
using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Albums
|
namespace NzbDrone.Api.Albums
|
||||||
|
@ -15,16 +19,19 @@ namespace NzbDrone.Api.Albums
|
||||||
public abstract class AlbumModuleWithSignalR : NzbDroneRestModuleWithSignalR<AlbumResource, Track>
|
public abstract class AlbumModuleWithSignalR : NzbDroneRestModuleWithSignalR<AlbumResource, Track>
|
||||||
{
|
{
|
||||||
protected readonly IAlbumService _albumService;
|
protected readonly IAlbumService _albumService;
|
||||||
|
protected readonly IArtistStatisticsService _artistStatisticsService;
|
||||||
protected readonly IArtistService _artistService;
|
protected readonly IArtistService _artistService;
|
||||||
protected readonly IQualityUpgradableSpecification _qualityUpgradableSpecification;
|
protected readonly IQualityUpgradableSpecification _qualityUpgradableSpecification;
|
||||||
|
|
||||||
protected AlbumModuleWithSignalR(IAlbumService albumService,
|
protected AlbumModuleWithSignalR(IAlbumService albumService,
|
||||||
|
IArtistStatisticsService artistStatisticsService,
|
||||||
IArtistService artistService,
|
IArtistService artistService,
|
||||||
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
||||||
IBroadcastSignalRMessage signalRBroadcaster)
|
IBroadcastSignalRMessage signalRBroadcaster)
|
||||||
: base(signalRBroadcaster)
|
: base(signalRBroadcaster)
|
||||||
{
|
{
|
||||||
_albumService = albumService;
|
_albumService = albumService;
|
||||||
|
_artistStatisticsService = artistStatisticsService;
|
||||||
_artistService = artistService;
|
_artistService = artistService;
|
||||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||||
|
|
||||||
|
@ -32,6 +39,7 @@ namespace NzbDrone.Api.Albums
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AlbumModuleWithSignalR(IAlbumService albumService,
|
protected AlbumModuleWithSignalR(IAlbumService albumService,
|
||||||
|
IArtistStatisticsService artistStatisticsService,
|
||||||
IArtistService artistService,
|
IArtistService artistService,
|
||||||
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
||||||
IBroadcastSignalRMessage signalRBroadcaster,
|
IBroadcastSignalRMessage signalRBroadcaster,
|
||||||
|
@ -39,6 +47,7 @@ namespace NzbDrone.Api.Albums
|
||||||
: base(signalRBroadcaster, resource)
|
: base(signalRBroadcaster, resource)
|
||||||
{
|
{
|
||||||
_albumService = albumService;
|
_albumService = albumService;
|
||||||
|
_artistStatisticsService = artistStatisticsService;
|
||||||
_artistService = artistService;
|
_artistService = artistService;
|
||||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||||
|
|
||||||
|
@ -66,6 +75,8 @@ namespace NzbDrone.Api.Albums
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FetchAndLinkAlbumStatistics(resource);
|
||||||
|
|
||||||
return 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;
|
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
|
//TODO: Implement Track or Album Grabbed/Dowloaded Events
|
||||||
|
|
||||||
//public void Handle(TrackGrabbedEvent message)
|
//public void Handle(TrackGrabbedEvent message)
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace NzbDrone.Api.Albums
|
||||||
public List<string> Genres { get; set; }
|
public List<string> Genres { get; set; }
|
||||||
public ArtistResource Artist { get; set; }
|
public ArtistResource Artist { get; set; }
|
||||||
public List<MediaCover> Images { 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.DecisionEngine;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
|
using NzbDrone.Core.ArtistStats;
|
||||||
using NzbDrone.SignalR;
|
using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Calendar
|
namespace NzbDrone.Api.Calendar
|
||||||
|
@ -13,10 +14,11 @@ namespace NzbDrone.Api.Calendar
|
||||||
public class CalendarModule : AlbumModuleWithSignalR
|
public class CalendarModule : AlbumModuleWithSignalR
|
||||||
{
|
{
|
||||||
public CalendarModule(IAlbumService albumService,
|
public CalendarModule(IAlbumService albumService,
|
||||||
|
IArtistStatisticsService artistStatisticsService,
|
||||||
IArtistService artistService,
|
IArtistService artistService,
|
||||||
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
||||||
IBroadcastSignalRMessage signalRBroadcaster)
|
IBroadcastSignalRMessage signalRBroadcaster)
|
||||||
: base(albumService, artistService, qualityUpgradableSpecification, signalRBroadcaster, "calendar")
|
: base(albumService, artistStatisticsService, artistService, qualityUpgradableSpecification, signalRBroadcaster, "calendar")
|
||||||
{
|
{
|
||||||
GetResourceAll = GetCalendar;
|
GetResourceAll = GetCalendar;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ namespace NzbDrone.Api.Music
|
||||||
public string RootFolderPath { get; set; }
|
public string RootFolderPath { get; set; }
|
||||||
//public string Certification { get; set; }
|
//public string Certification { get; set; }
|
||||||
public List<string> Genres { get; set; }
|
public List<string> Genres { get; set; }
|
||||||
|
public string CleanName { get; set; }
|
||||||
public HashSet<int> Tags { get; set; }
|
public HashSet<int> Tags { get; set; }
|
||||||
public DateTime Added { get; set; }
|
public DateTime Added { get; set; }
|
||||||
public AddArtistOptions AddOptions { get; set; }
|
public AddArtistOptions AddOptions { get; set; }
|
||||||
|
@ -73,6 +74,7 @@ namespace NzbDrone.Api.Music
|
||||||
DiscogsId = model.DiscogsId,
|
DiscogsId = model.DiscogsId,
|
||||||
AllMusicId = model.AMId,
|
AllMusicId = model.AMId,
|
||||||
Name = model.Name,
|
Name = model.Name,
|
||||||
|
CleanName = model.CleanName,
|
||||||
//AlternateTitles
|
//AlternateTitles
|
||||||
//SortTitle = resource.SortTitle,
|
//SortTitle = resource.SortTitle,
|
||||||
|
|
||||||
|
@ -88,8 +90,7 @@ namespace NzbDrone.Api.Music
|
||||||
//AirTime = resource.AirTime,
|
//AirTime = resource.AirTime,
|
||||||
Images = model.Images,
|
Images = model.Images,
|
||||||
Members = model.Members,
|
Members = model.Members,
|
||||||
|
//Albums = model.Albums.ToResource(),
|
||||||
Albums = model.Albums.ToResource(),
|
|
||||||
//Year = resource.Year,
|
//Year = resource.Year,
|
||||||
|
|
||||||
Path = model.Path,
|
Path = model.Path,
|
||||||
|
@ -127,6 +128,7 @@ namespace NzbDrone.Api.Music
|
||||||
Id = resource.Id,
|
Id = resource.Id,
|
||||||
|
|
||||||
Name = resource.Name,
|
Name = resource.Name,
|
||||||
|
CleanName = resource.CleanName,
|
||||||
//AlternateTitles
|
//AlternateTitles
|
||||||
//SortTitle = resource.SortTitle,
|
//SortTitle = resource.SortTitle,
|
||||||
MBId = resource.MBId,
|
MBId = resource.MBId,
|
||||||
|
@ -145,8 +147,7 @@ namespace NzbDrone.Api.Music
|
||||||
//AirTime = resource.AirTime,
|
//AirTime = resource.AirTime,
|
||||||
Images = resource.Images,
|
Images = resource.Images,
|
||||||
Members = resource.Members,
|
Members = resource.Members,
|
||||||
|
//Albums = resource.Albums.ToModel(),
|
||||||
Albums = resource.Albums.ToModel(),
|
|
||||||
//Year = resource.Year,
|
//Year = resource.Year,
|
||||||
|
|
||||||
Path = resource.Path,
|
Path = resource.Path,
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Albums\AlbumModuleWithSignalR.cs" />
|
<Compile Include="Albums\AlbumModuleWithSignalR.cs" />
|
||||||
|
<Compile Include="Albums\AlbumStatisticsResource.cs" />
|
||||||
<Compile Include="Authentication\AuthenticationService.cs" />
|
<Compile Include="Authentication\AuthenticationService.cs" />
|
||||||
<Compile Include="Authentication\EnableAuthInNancy.cs" />
|
<Compile Include="Authentication\EnableAuthInNancy.cs" />
|
||||||
<Compile Include="Authentication\AuthenticationModule.cs" />
|
<Compile Include="Authentication\AuthenticationModule.cs" />
|
||||||
|
@ -105,6 +106,8 @@
|
||||||
<Compile Include="ClientSchema\SelectOption.cs" />
|
<Compile Include="ClientSchema\SelectOption.cs" />
|
||||||
<Compile Include="Commands\CommandModule.cs" />
|
<Compile Include="Commands\CommandModule.cs" />
|
||||||
<Compile Include="Commands\CommandResource.cs" />
|
<Compile Include="Commands\CommandResource.cs" />
|
||||||
|
<Compile Include="AlbumStudio\AlbumStudioModule.cs" />
|
||||||
|
<Compile Include="AlbumStudio\AlbumStudioResource.cs" />
|
||||||
<Compile Include="TrackFiles\TrackFileModule.cs" />
|
<Compile Include="TrackFiles\TrackFileModule.cs" />
|
||||||
<Compile Include="TrackFiles\TrackFileResource.cs" />
|
<Compile Include="TrackFiles\TrackFileResource.cs" />
|
||||||
<Compile Include="Albums\AlbumModule.cs" />
|
<Compile Include="Albums\AlbumModule.cs" />
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
using NzbDrone.Api.Albums;
|
using NzbDrone.Api.Albums;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.DecisionEngine;
|
using NzbDrone.Core.DecisionEngine;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.ArtistStats;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
using NzbDrone.SignalR;
|
using NzbDrone.SignalR;
|
||||||
|
|
||||||
|
@ -11,10 +11,11 @@ namespace NzbDrone.Api.Wanted
|
||||||
public class MissingModule : AlbumModuleWithSignalR
|
public class MissingModule : AlbumModuleWithSignalR
|
||||||
{
|
{
|
||||||
public MissingModule(IAlbumService albumService,
|
public MissingModule(IAlbumService albumService,
|
||||||
|
IArtistStatisticsService artistStatisticsService,
|
||||||
IArtistService artistService,
|
IArtistService artistService,
|
||||||
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
||||||
IBroadcastSignalRMessage signalRBroadcaster)
|
IBroadcastSignalRMessage signalRBroadcaster)
|
||||||
: base(albumService, artistService, qualityUpgradableSpecification, signalRBroadcaster, "wanted/missing")
|
: base(albumService, artistStatisticsService, artistService, qualityUpgradableSpecification, signalRBroadcaster, "wanted/missing")
|
||||||
{
|
{
|
||||||
GetResourcePaged = GetMissingAlbums;
|
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)
|
private QueryBuilder<Album> GetMissingAlbumsQuery(PagingSpec<Album> pagingSpec, DateTime currentTime)
|
||||||
{
|
{
|
||||||
string sortKey;
|
string sortKey;
|
||||||
int monitored = 0;
|
string monitored = "([t0].[Monitored] = 0) OR ([t1].[Monitored] = 0)";
|
||||||
|
|
||||||
if (pagingSpec.FilterExpression.ToString().Contains("True"))
|
if (pagingSpec.FilterExpression.ToString().Contains("True"))
|
||||||
{
|
{
|
||||||
monitored = 1;
|
monitored = "([t0].[Monitored] = 1) AND ([t1].[Monitored] = 1)";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pagingSpec.SortKey == "releaseDate")
|
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])" +
|
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}",
|
" 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());
|
monitored, BuildReleaseDateCutoffWhereClause(currentTime), sortKey, pagingSpec.ToSortDirection(), pagingSpec.PageSize, pagingSpec.PagingOffset());
|
||||||
|
|
||||||
|
|
|
@ -58,30 +58,19 @@ namespace NzbDrone.Core.Music
|
||||||
{
|
{
|
||||||
|
|
||||||
ForeignArtistId = otherArtist.ForeignArtistId;
|
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;
|
Path = otherArtist.Path;
|
||||||
Genres = otherArtist.Genres;
|
|
||||||
RootFolderPath = otherArtist.RootFolderPath;
|
|
||||||
Added = otherArtist.Added;
|
|
||||||
Profile = otherArtist.Profile;
|
Profile = otherArtist.Profile;
|
||||||
ProfileId = otherArtist.ProfileId;
|
|
||||||
Albums = otherArtist.Albums;
|
Albums = otherArtist.Albums;
|
||||||
|
|
||||||
|
ProfileId = otherArtist.ProfileId;
|
||||||
Tags = otherArtist.Tags;
|
Tags = otherArtist.Tags;
|
||||||
AddOptions = otherArtist.AddOptions;
|
AddOptions = otherArtist.AddOptions;
|
||||||
Ratings = otherArtist.Ratings;
|
RootFolderPath = otherArtist.RootFolderPath;
|
||||||
Members = otherArtist.Members;
|
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="Extras\Metadata\MetadataType.cs" />
|
||||||
<Compile Include="MetadataSource\IProvideSeriesInfo.cs" />
|
<Compile Include="MetadataSource\IProvideSeriesInfo.cs" />
|
||||||
<Compile Include="MetadataSource\ISearchForNewSeries.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\Member.cs" />
|
||||||
<Compile Include="Music\AddArtistOptions.cs" />
|
<Compile Include="Music\AddArtistOptions.cs" />
|
||||||
<Compile Include="Music\AddArtistService.cs" />
|
<Compile Include="Music\AddArtistService.cs" />
|
||||||
|
|
|
@ -6,8 +6,5 @@ namespace NzbDrone.Core.Tv
|
||||||
{
|
{
|
||||||
public bool IgnoreEpisodesWithFiles { get; set; }
|
public bool IgnoreEpisodesWithFiles { get; set; }
|
||||||
public bool IgnoreEpisodesWithoutFiles { 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');
|
var RootFolders = require('../AddArtist/RootFolders/RootFolderCollection');
|
||||||
|
|
||||||
module.exports = Marionette.ItemView.extend({
|
module.exports = Marionette.ItemView.extend({
|
||||||
template : 'SeasonPass/SeasonPassFooterViewTemplate',
|
template : 'AlbumStudio/AlbumStudioFooterViewTemplate',
|
||||||
|
|
||||||
ui : {
|
ui : {
|
||||||
seriesMonitored : '.x-series-monitored',
|
artistMonitored : '.x-artist-monitored',
|
||||||
monitor : '.x-monitor',
|
monitor : '.x-monitor',
|
||||||
selectedCount : '.x-selected-count',
|
selectedCount : '.x-selected-count',
|
||||||
container : '.series-editor-footer',
|
container : '.artist-editor-footer',
|
||||||
actions : '.x-action',
|
actions : '.x-action',
|
||||||
indicator : '.x-indicator',
|
indicator : '.x-indicator',
|
||||||
indicatorIcon : '.x-indicator-icon'
|
indicatorIcon : '.x-indicator-icon'
|
||||||
|
@ -22,14 +22,14 @@ module.exports = Marionette.ItemView.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize : function(options) {
|
initialize : function(options) {
|
||||||
this.seriesCollection = options.collection;
|
this.artistCollection = options.collection;
|
||||||
|
|
||||||
RootFolders.fetch().done(function() {
|
RootFolders.fetch().done(function() {
|
||||||
RootFolders.synced = true;
|
RootFolders.synced = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.editorGrid = options.editorGrid;
|
this.editorGrid = options.editorGrid;
|
||||||
this.listenTo(this.seriesCollection, 'backgrid:selected', this._updateInfo);
|
this.listenTo(this.artistCollection, 'backgrid:selected', this._updateInfo);
|
||||||
},
|
},
|
||||||
|
|
||||||
onRender : function() {
|
onRender : function() {
|
||||||
|
@ -39,13 +39,13 @@ module.exports = Marionette.ItemView.extend({
|
||||||
_update : function() {
|
_update : function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
var selected = this.editorGrid.getSelectedModels();
|
var selected = this.editorGrid.getSelectedModels();
|
||||||
var seriesMonitored = this.ui.seriesMonitored.val();
|
var artistMonitored = this.ui.artistMonitored.val();
|
||||||
var monitoringOptions;
|
var monitoringOptions;
|
||||||
|
|
||||||
_.each(selected, function(model) {
|
_.each(selected, function(model) {
|
||||||
if (seriesMonitored === 'true') {
|
if (artistMonitored === 'true') {
|
||||||
model.set('monitored', true);
|
model.set('monitored', true);
|
||||||
} else if (seriesMonitored === 'false') {
|
} else if (artistMonitored === 'false') {
|
||||||
model.set('monitored', false);
|
model.set('monitored', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,10 +54,10 @@ module.exports = Marionette.ItemView.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
var promise = $.ajax({
|
var promise = $.ajax({
|
||||||
url : window.NzbDrone.ApiRoot + '/seasonpass',
|
url : window.NzbDrone.ApiRoot + '/albumstudio',
|
||||||
type : 'POST',
|
type : 'POST',
|
||||||
data : JSON.stringify({
|
data : JSON.stringify({
|
||||||
series : _.map(selected, function (model) {
|
artist : _.map(selected, function (model) {
|
||||||
return model.toJSON();
|
return model.toJSON();
|
||||||
}),
|
}),
|
||||||
monitoringOptions : monitoringOptions
|
monitoringOptions : monitoringOptions
|
||||||
|
@ -71,7 +71,7 @@ module.exports = Marionette.ItemView.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
promise.done(function () {
|
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 selected = this.editorGrid.getSelectedModels();
|
||||||
var selectedCount = selected.length;
|
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) {
|
if (selectedCount === 0) {
|
||||||
this.ui.actions.attr('disabled', 'disabled');
|
this.ui.actions.attr('disabled', 'disabled');
|
||||||
|
@ -90,48 +90,25 @@ module.exports = Marionette.ItemView.extend({
|
||||||
|
|
||||||
_getMonitoringOptions : function(model) {
|
_getMonitoringOptions : function(model) {
|
||||||
var monitor = this.ui.monitor.val();
|
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') {
|
if (monitor === 'noChange') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
model.setSeasonPass(firstSeason.seasonNumber);
|
model.setAlbumPass(0);
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
ignoreEpisodesWithFiles : false,
|
ignoreTracksWithFiles : false,
|
||||||
ignoreEpisodesWithoutFiles : false
|
ignoreTracksWithoutFiles : false,
|
||||||
|
monitored : true
|
||||||
};
|
};
|
||||||
|
|
||||||
if (monitor === 'all') {
|
if (monitor === 'all') {
|
||||||
return options;
|
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') {
|
else if (monitor === 'none') {
|
||||||
model.setSeasonPass(lastSeason.seasonNumber + 1);
|
options.monitored = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
|
@ -1,9 +1,9 @@
|
||||||
<div class="series-editor-footer">
|
<div class="artist-editor-footer">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="form-group col-md-2">
|
<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="noChange">No change</option>
|
||||||
<option value="true">Monitored</option>
|
<option value="true">Monitored</option>
|
||||||
<option value="false">Unmonitored</option>
|
<option value="false">Unmonitored</option>
|
||||||
|
@ -11,24 +11,19 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group col-md-2">
|
<div class="form-group col-md-2">
|
||||||
<label>Monitor episodes</label>
|
<label>Monitor albums</label>
|
||||||
|
|
||||||
<select class="form-control x-action x-monitor">
|
<select class="form-control x-action x-monitor">
|
||||||
<option value="noChange">No change</option>
|
<option value="noChange">No change</option>
|
||||||
<option value="all">All</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>
|
<option value="none">None</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group col-md-3 actions">
|
<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>
|
<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>
|
<span class="indicator x-indicator"><i class="icon-lidarr-spinner fa-spin"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -2,23 +2,23 @@ var _ = require('underscore');
|
||||||
var vent = require('vent');
|
var vent = require('vent');
|
||||||
var Backgrid = require('backgrid');
|
var Backgrid = require('backgrid');
|
||||||
var Marionette = require('marionette');
|
var Marionette = require('marionette');
|
||||||
var EmptyView = require('../Series/Index/EmptyView');
|
var EmptyView = require('../Artist/Index/EmptyView');
|
||||||
var SeriesCollection = require('../Series/SeriesCollection');
|
var ArtistCollection = require('../Artist/ArtistCollection');
|
||||||
var ToolbarLayout = require('../Shared/Toolbar/ToolbarLayout');
|
var ToolbarLayout = require('../Shared/Toolbar/ToolbarLayout');
|
||||||
var FooterView = require('./SeasonPassFooterView');
|
var FooterView = require('./AlbumStudioFooterView');
|
||||||
var SelectAllCell = require('../Cells/SelectAllCell');
|
var SelectAllCell = require('../Cells/SelectAllCell');
|
||||||
var SeriesStatusCell = require('../Cells/SeriesStatusCell');
|
var ArtistStatusCell = require('../Cells/ArtistStatusCell');
|
||||||
var SeriesTitleCell = require('../Cells/SeriesTitleCell');
|
var ArtistTitleCell = require('../Cells/ArtistTitleCell');
|
||||||
var SeriesMonitoredCell = require('../Cells/ToggleCell');
|
var ArtistMonitoredCell = require('../Cells/ArtistMonitoredCell');
|
||||||
var SeasonsCell = require('./SeasonsCell');
|
var AlbumsCell = require('./AlbumsCell');
|
||||||
require('../Mixins/backbone.signalr.mixin');
|
require('../Mixins/backbone.signalr.mixin');
|
||||||
|
|
||||||
module.exports = Marionette.Layout.extend({
|
module.exports = Marionette.Layout.extend({
|
||||||
template : 'SeasonPass/SeasonPassLayoutTemplate',
|
template : 'AlbumStudio/AlbumStudioLayoutTemplate',
|
||||||
|
|
||||||
regions : {
|
regions : {
|
||||||
toolbar : '#x-toolbar',
|
toolbar : '#x-toolbar',
|
||||||
series : '#x-series'
|
artist : '#x-artist'
|
||||||
},
|
},
|
||||||
|
|
||||||
columns : [
|
columns : [
|
||||||
|
@ -31,42 +31,38 @@ module.exports = Marionette.Layout.extend({
|
||||||
{
|
{
|
||||||
name : 'statusWeight',
|
name : 'statusWeight',
|
||||||
label : '',
|
label : '',
|
||||||
cell : SeriesStatusCell
|
cell : ArtistStatusCell
|
||||||
},
|
|
||||||
{
|
|
||||||
name : 'title',
|
|
||||||
label : 'Title',
|
|
||||||
cell : SeriesTitleCell,
|
|
||||||
cellValue : 'this'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'monitored',
|
name : 'monitored',
|
||||||
label : '',
|
label : 'Artist',
|
||||||
cell : SeriesMonitoredCell,
|
cell : ArtistMonitoredCell,
|
||||||
trueClass : 'icon-lidarr-monitored',
|
trueClass : 'icon-lidarr-monitored',
|
||||||
falseClass : 'icon-lidarr-unmonitored',
|
falseClass : 'icon-lidarr-unmonitored',
|
||||||
tooltip : 'Toggle series monitored status',
|
tooltip : 'Toggle artist monitored status',
|
||||||
sortable : false
|
sortable : false
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name : 'seasons',
|
name : 'albums',
|
||||||
label : 'Seasons',
|
label : 'Albums',
|
||||||
cell : SeasonsCell,
|
cell : AlbumsCell,
|
||||||
cellValue : 'this'
|
cellValue : 'this'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
initialize : function() {
|
initialize : function() {
|
||||||
this.seriesCollection = SeriesCollection.clone();
|
this.artistCollection = ArtistCollection.clone();
|
||||||
this.seriesCollection.shadowCollection.bindSignalR();
|
|
||||||
|
|
||||||
// this.listenTo(this.seriesCollection, 'sync', this.render);
|
this.artistCollection.shadowCollection.bindSignalR();
|
||||||
this.listenTo(this.seriesCollection, 'seasonpass:saved', this.render);
|
|
||||||
|
this.listenTo(this.artistCollection, 'sync', this.render);
|
||||||
|
this.listenTo(this.artistCollection, 'albumstudio:saved', this.render);
|
||||||
|
|
||||||
this.filteringOptions = {
|
this.filteringOptions = {
|
||||||
type : 'radio',
|
type : 'radio',
|
||||||
storeState : true,
|
storeState : true,
|
||||||
menuKey : 'seasonpass.filterMode',
|
menuKey : 'albumstudio.filterMode',
|
||||||
defaultAction : 'all',
|
defaultAction : 'all',
|
||||||
items : [
|
items : [
|
||||||
{
|
{
|
||||||
|
@ -87,14 +83,14 @@ module.exports = Marionette.Layout.extend({
|
||||||
key : 'continuing',
|
key : 'continuing',
|
||||||
title : '',
|
title : '',
|
||||||
tooltip : 'Continuing Only',
|
tooltip : 'Continuing Only',
|
||||||
icon : 'icon-lidarr-series-continuing',
|
icon : 'icon-lidarr-artist-continuing',
|
||||||
callback : this._setFilter
|
callback : this._setFilter
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key : 'ended',
|
key : 'ended',
|
||||||
title : '',
|
title : '',
|
||||||
tooltip : 'Ended Only',
|
tooltip : 'Ended Only',
|
||||||
icon : 'icon-lidarr-series-ended',
|
icon : 'icon-lidarr-artist-ended',
|
||||||
callback : this._setFilter
|
callback : this._setFilter
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -119,34 +115,34 @@ module.exports = Marionette.Layout.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
_showTable : function() {
|
_showTable : function() {
|
||||||
if (this.seriesCollection.shadowCollection.length === 0) {
|
if (this.artistCollection.shadowCollection.length === 0) {
|
||||||
this.series.show(new EmptyView());
|
this.artist.show(new EmptyView());
|
||||||
this.toolbar.close();
|
this.toolbar.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.columns[0].sortedCollection = this.seriesCollection;
|
this.columns[0].sortedCollection = this.artistCollection;
|
||||||
|
|
||||||
this.editorGrid = new Backgrid.Grid({
|
this.editorGrid = new Backgrid.Grid({
|
||||||
collection : this.seriesCollection,
|
collection : this.artistCollection,
|
||||||
columns : this.columns,
|
columns : this.columns,
|
||||||
className : 'table table-hover'
|
className : 'table table-hover'
|
||||||
});
|
});
|
||||||
|
|
||||||
this.series.show(this.editorGrid);
|
this.artist.show(this.editorGrid);
|
||||||
this._showFooter();
|
this._showFooter();
|
||||||
},
|
},
|
||||||
|
|
||||||
_showFooter : function() {
|
_showFooter : function() {
|
||||||
vent.trigger(vent.Commands.OpenControlPanelCommand, new FooterView({
|
vent.trigger(vent.Commands.OpenControlPanelCommand, new FooterView({
|
||||||
editorGrid : this.editorGrid,
|
editorGrid : this.editorGrid,
|
||||||
collection : this.seriesCollection
|
collection : this.artistCollection
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_setFilter : function(buttonContext) {
|
_setFilter : function(buttonContext) {
|
||||||
var mode = buttonContext.model.get('key');
|
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 "../Content/badges.less";
|
||||||
@import "../Shared/Styles/clickable.less";
|
@import "../Shared/Styles/clickable.less";
|
||||||
|
|
||||||
.season {
|
.artist-albums {
|
||||||
|
div {
|
||||||
|
display : inline-block;
|
||||||
|
padding : 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.album {
|
||||||
display : inline-block;
|
display : inline-block;
|
||||||
margin-bottom : 4px;
|
margin-bottom : 4px;
|
||||||
|
|
||||||
|
@ -31,11 +38,11 @@
|
||||||
background-color : #f7f7f7;
|
background-color : #f7f7f7;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.season-all .label:last-child {
|
&.album-all .label:last-child {
|
||||||
background-color : #e0ffe0;
|
background-color : #e0ffe0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.season-monitored {
|
.album-monitored {
|
||||||
width : 16px;
|
width : 16px;
|
||||||
|
|
||||||
i {
|
i {
|
||||||
|
@ -43,11 +50,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.season-number {
|
.album-number {
|
||||||
font-size : 12px;
|
font-size : 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.season-status {
|
.album-status {
|
||||||
display : inline-block;
|
display : inline-block;
|
||||||
vertical-align : baseline !important;
|
vertical-align : baseline !important;
|
||||||
}
|
}
|
|
@ -11,18 +11,17 @@ module.exports = Backbone.Model.extend({
|
||||||
status : 0
|
status : 0
|
||||||
},
|
},
|
||||||
|
|
||||||
setAlbumsMonitored : function(albumName) {
|
setAlbumsMonitored : function(albumId) {
|
||||||
_.each(this.get('albums'), function(album) {
|
_.each(this.get('albums'), function(album) {
|
||||||
console.log(album);
|
if (album.albumId === albumId) {
|
||||||
if (album.albumName === albumName) {
|
|
||||||
album.monitored = !album.monitored;
|
album.monitored = !album.monitored;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
setAlbumPass : function(seasonNumber) {
|
setAlbumPass : function(monitored) {
|
||||||
_.each(this.get('albums'), function(album) {
|
_.each(this.get('albums'), function(album) {
|
||||||
if (album.seasonNumber >= seasonNumber) {
|
if (monitored === 0) {
|
||||||
album.monitored = true;
|
album.monitored = true;
|
||||||
} else {
|
} else {
|
||||||
album.monitored = false;
|
album.monitored = false;
|
||||||
|
|
|
@ -11,7 +11,7 @@ var view = Marionette.CollectionView.extend({
|
||||||
if (!options.trackCollection) {
|
if (!options.trackCollection) {
|
||||||
throw 'trackCollection is needed';
|
throw 'trackCollection is needed';
|
||||||
}
|
}
|
||||||
console.log(options);
|
|
||||||
this.albumCollection = options.collection;
|
this.albumCollection = options.collection;
|
||||||
this.trackCollection = options.trackCollection;
|
this.trackCollection = options.trackCollection;
|
||||||
this.artist = options.artist;
|
this.artist = options.artist;
|
||||||
|
|
|
@ -132,11 +132,9 @@ module.exports = Marionette.Layout.extend({
|
||||||
this.trackCollection = this.fullTrackCollection.byAlbum(this.model.get('id'));
|
this.trackCollection = this.fullTrackCollection.byAlbum(this.model.get('id'));
|
||||||
this._updateTrackCollection();
|
this._updateTrackCollection();
|
||||||
|
|
||||||
console.log(options);
|
|
||||||
|
|
||||||
this.showingTracks = this._shouldShowTracks();
|
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.trackCollection, 'sync', this.render);
|
||||||
this.listenTo(this.fullTrackCollection, 'sync', this._refreshTracks);
|
this.listenTo(this.fullTrackCollection, 'sync', this._refreshTracks);
|
||||||
this.listenTo(this.model, 'change:images', this._updateImages);
|
this.listenTo(this.model, 'change:images', this._updateImages);
|
||||||
|
@ -203,28 +201,20 @@ module.exports = Marionette.Layout.extend({
|
||||||
if (!this.artist.get('monitored')) {
|
if (!this.artist.get('monitored')) {
|
||||||
|
|
||||||
Messenger.show({
|
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'
|
type : 'error'
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var name = 'monitored';
|
//var savePromise = this.model.save('monitored', !this.model.get('monitored'), { wait : true });
|
||||||
this.model.set(name, !this.model.get(name));
|
var savePromise = this.model.save('monitored', !this.model.get('monitored'), { wait : true });
|
||||||
this.artist.setSeasonMonitored(this.model.get('albumId'));
|
|
||||||
|
|
||||||
var savePromise = this.artist.save().always(this._afterSeasonMonitored.bind(this));
|
|
||||||
|
|
||||||
this.ui.albumMonitored.spinForPromise(savePromise);
|
this.ui.albumMonitored.spinForPromise(savePromise);
|
||||||
},
|
},
|
||||||
|
|
||||||
_afterSeasonMonitored : function() {
|
_afterAlbumMonitored : function() {
|
||||||
var self = this;
|
|
||||||
|
|
||||||
_.each(this.trackCollection.models, function(track) {
|
|
||||||
track.set({ monitored : self.model.get('monitored') });
|
|
||||||
});
|
|
||||||
|
|
||||||
this.render();
|
this.render();
|
||||||
},
|
},
|
||||||
|
|
|
@ -127,11 +127,11 @@ module.exports = Marionette.Layout.extend({
|
||||||
if (monitored) {
|
if (monitored) {
|
||||||
this.ui.monitored.addClass('icon-lidarr-monitored');
|
this.ui.monitored.addClass('icon-lidarr-monitored');
|
||||||
this.ui.monitored.removeClass('icon-lidarr-unmonitored');
|
this.ui.monitored.removeClass('icon-lidarr-unmonitored');
|
||||||
this.$el.removeClass('series-not-monitored');
|
this.$el.removeClass('artist-not-monitored');
|
||||||
} else {
|
} else {
|
||||||
this.ui.monitored.addClass('icon-lidarr-unmonitored');
|
this.ui.monitored.addClass('icon-lidarr-unmonitored');
|
||||||
this.ui.monitored.removeClass('icon-lidarr-monitored');
|
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.trackCollection = new TrackCollection({ artistId : this.model.id }).bindSignalR();
|
||||||
this.trackFileCollection = new TrackFileCollection({ 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) {
|
reqres.setHandler(reqres.Requests.GetEpisodeFileById, function(trackFileId) {
|
||||||
return self.trackFileCollection.get(trackFileId);
|
return self.trackFileCollection.get(trackFileId);
|
||||||
});
|
});
|
||||||
|
|
|
@ -72,9 +72,9 @@ module.exports = Marionette.Layout.extend({
|
||||||
storeState : false,
|
storeState : false,
|
||||||
items : [
|
items : [
|
||||||
{
|
{
|
||||||
title : 'Season Pass',
|
title : 'Album Studio',
|
||||||
icon : 'icon-lidarr-monitored',
|
icon : 'icon-lidarr-monitored',
|
||||||
route : 'seasonpass'
|
route : 'albumstudio'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title : 'Update Library',
|
title : 'Update Library',
|
||||||
|
|
|
@ -86,9 +86,9 @@ module.exports = Marionette.Layout.extend({
|
||||||
route : 'addartist'
|
route : 'addartist'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title : 'Season Pass',
|
title : 'Album Studio',
|
||||||
icon : 'icon-lidarr-monitored',
|
icon : 'icon-lidarr-monitored',
|
||||||
route : 'seasonpass'
|
route : 'albumstudio'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title : 'Artist Editor',
|
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')) {
|
if (!artist.get('monitored')) {
|
||||||
|
|
||||||
Messenger.show({
|
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'
|
type : 'error'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.artist-monitored-cell {
|
||||||
|
.text-overflow();
|
||||||
|
|
||||||
|
.artist-monitored-name {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.track-title-cell {
|
.track-title-cell {
|
||||||
.text-overflow();
|
.text-overflow();
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
@import "../Shared/FileBrowser/filebrowser";
|
@import "../Shared/FileBrowser/filebrowser";
|
||||||
@import "badges";
|
@import "badges";
|
||||||
@import "../ManualImport/manualimport";
|
@import "../ManualImport/manualimport";
|
||||||
@import "../SeasonPass/seasonpass";
|
@import "../AlbumStudio/albumstudio";
|
||||||
|
|
||||||
.main-region {
|
.main-region {
|
||||||
@media (min-width : @screen-lg-min) {
|
@media (min-width : @screen-lg-min) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ var WantedLayout = require('./Wanted/WantedLayout');
|
||||||
var CalendarLayout = require('./Calendar/CalendarLayout');
|
var CalendarLayout = require('./Calendar/CalendarLayout');
|
||||||
var ReleaseLayout = require('./Release/ReleaseLayout');
|
var ReleaseLayout = require('./Release/ReleaseLayout');
|
||||||
var SystemLayout = require('./System/SystemLayout');
|
var SystemLayout = require('./System/SystemLayout');
|
||||||
var SeasonPassLayout = require('./SeasonPass/SeasonPassLayout');
|
var AlbumStudioLayout = require('./AlbumStudio/AlbumStudioLayout');
|
||||||
//var SeriesEditorLayout = require('./Series/Editor/SeriesEditorLayout');
|
//var SeriesEditorLayout = require('./Series/Editor/SeriesEditorLayout');
|
||||||
var ArtistEditorLayout = require('./Artist/Editor/ArtistEditorLayout');
|
var ArtistEditorLayout = require('./Artist/Editor/ArtistEditorLayout');
|
||||||
|
|
||||||
|
@ -49,9 +49,9 @@ module.exports = NzbDroneController.extend({
|
||||||
this.showMainRegion(new SystemLayout({ action : action }));
|
this.showMainRegion(new SystemLayout({ action : action }));
|
||||||
},
|
},
|
||||||
|
|
||||||
seasonPass : function() {
|
albumStudio : function() {
|
||||||
this.setTitle('Season Pass');
|
this.setTitle('Album Studio');
|
||||||
this.showMainRegion(new SeasonPassLayout());
|
this.showMainRegion(new AlbumStudioLayout());
|
||||||
},
|
},
|
||||||
|
|
||||||
artistEditor : function() {
|
artistEditor : function() {
|
||||||
|
|
|
@ -18,7 +18,7 @@ module.exports = Marionette.AppRouter.extend({
|
||||||
'rss' : 'rss',
|
'rss' : 'rss',
|
||||||
'system' : 'system',
|
'system' : 'system',
|
||||||
'system/:action' : 'system',
|
'system/:action' : 'system',
|
||||||
'seasonpass' : 'seasonPass',
|
'albumstudio' : 'albumStudio',
|
||||||
'artisteditor' : 'artistEditor',
|
'artisteditor' : 'artistEditor',
|
||||||
':whatever' : 'showNotFound'
|
':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'
|
className : 'x-search-selected'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title : 'Season Pass',
|
title : 'Album Studio',
|
||||||
icon : 'icon-lidarr-monitored',
|
icon : 'icon-lidarr-monitored',
|
||||||
route : 'seasonpass'
|
route : 'albumstudio'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
|
@ -126,9 +126,9 @@ module.exports = Marionette.Layout.extend({
|
||||||
className : 'x-unmonitor-selected'
|
className : 'x-unmonitor-selected'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title : 'Season Pass',
|
title : 'Album Studio',
|
||||||
icon : 'icon-lidarr-monitored',
|
icon : 'icon-lidarr-monitored',
|
||||||
route : 'seasonpass'
|
route : 'albumstudio'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title : 'Rescan Drone Factory Folder',
|
title : 'Rescan Drone Factory Folder',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue