mirror of https://github.com/Radarr/Radarr
Min availability (#816)
* availability specification to prevent downloading titles before their release * pull inCinamas status out of js handlebars and set it in SkyHook * minor code improvement * add incinemas to footer * typo * another typo * release date handling * still print cinema date out for announced titles * revert a minor change from before since its unnecessary * early implementation of minimumAvailability --> when does radarr consider a movie "available" should be specified by user default to "Physical release?" this isn't functional yet, but it has a skeleton + comments. I dont know how to have the minimumavailability attribute default to something or to have it actually populate the Movieinfo object could use some help with that * adding another comment for another location that might need to be updated to handle minimumAvailability * the implementation is now function; however, i still need to specify default values for minimumAvailability * missed these changes in the previous commit * fix rounded corners on new field in editmovie dialog * add minimum availability specification to the addMovie page * minor adjustment from last commit * handle the case where minimumavailability has never yet been set nullstring.. if its never been set, default to Released (Physical/Web) represented by integer value 3 * minAvailability specification on NetImport lists * add support for min availability to the movie editor * use enum MovieStatusType values directly makes for cleaner code * need to fix up the migration forgot in last commit * cleaning up code, proper case * erroneous code added in this feature needed to be removed * update "Wanted" page to take into account minimumAvailability * implement preDB minimumAvailability as default.. behaves same as Physical/Web a few comments with TODO for when preDB is implemented * minor adjustment * remove some unused code (leave commented for now) * improve code for minimumavailability and add option for availabilitydelay (but doesnt do anything yet) * improve isAvailable method * clean up and fix helper info on indexer configuration page * add buttons in Wanted/Missing view
This commit is contained in:
parent
731e607666
commit
140a220340
|
@ -8,6 +8,7 @@ namespace NzbDrone.Api.Config
|
|||
public int MinimumAge { get; set; }
|
||||
public int Retention { get; set; }
|
||||
public int RssSyncInterval { get; set; }
|
||||
public int AvailabilityDelay { get; set; }
|
||||
}
|
||||
|
||||
public static class IndexerConfigResourceMapper
|
||||
|
@ -19,6 +20,7 @@ namespace NzbDrone.Api.Config
|
|||
MinimumAge = model.MinimumAge,
|
||||
Retention = model.Retention,
|
||||
RssSyncInterval = model.RssSyncInterval,
|
||||
AvailabilityDelay = model.AvailabilityDelay,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace NzbDrone.Api.NetImport
|
|||
resource.ProfileId = definition.ProfileId;
|
||||
resource.RootFolderPath = definition.RootFolderPath;
|
||||
resource.ShouldMonitor = definition.ShouldMonitor;
|
||||
resource.MinimumAvailability = definition.MinimumAvailability;
|
||||
}
|
||||
|
||||
protected override void MapToModel(NetImportDefinition definition, NetImportResource resource)
|
||||
|
@ -33,6 +34,7 @@ namespace NzbDrone.Api.NetImport
|
|||
definition.ProfileId = resource.ProfileId;
|
||||
definition.RootFolderPath = resource.RootFolderPath;
|
||||
definition.ShouldMonitor = resource.ShouldMonitor;
|
||||
definition.MinimumAvailability = resource.MinimumAvailability;
|
||||
}
|
||||
|
||||
protected override void Validate(NetImportDefinition definition, bool includeWarnings)
|
||||
|
@ -41,4 +43,4 @@ namespace NzbDrone.Api.NetImport
|
|||
base.Validate(definition, includeWarnings);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using NzbDrone.Core.NetImport;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Api.NetImport
|
||||
{
|
||||
|
@ -9,5 +10,6 @@ namespace NzbDrone.Api.NetImport
|
|||
public bool ShouldMonitor { get; set; }
|
||||
public string RootFolderPath { get; set; }
|
||||
public int ProfileId { get; set; }
|
||||
public MovieStatusType MinimumAvailability { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,9 @@ namespace NzbDrone.Api.Movie
|
|||
|
||||
//Editing Only
|
||||
public bool Monitored { get; set; }
|
||||
public MovieStatusType MinimumAvailability { get; set; }
|
||||
public bool IsAvailable { get; set; }
|
||||
|
||||
public int Runtime { get; set; }
|
||||
public DateTime? LastInfoSync { get; set; }
|
||||
public string CleanTitle { get; set; }
|
||||
|
@ -129,6 +132,9 @@ namespace NzbDrone.Api.Movie
|
|||
ProfileId = model.ProfileId,
|
||||
|
||||
Monitored = model.Monitored,
|
||||
MinimumAvailability = model.MinimumAvailability,
|
||||
|
||||
IsAvailable = model.IsAvailable(),
|
||||
|
||||
SizeOnDisk = size,
|
||||
|
||||
|
@ -181,7 +187,8 @@ namespace NzbDrone.Api.Movie
|
|||
ProfileId = resource.ProfileId,
|
||||
|
||||
Monitored = resource.Monitored,
|
||||
|
||||
MinimumAvailability = resource.MinimumAvailability,
|
||||
|
||||
Runtime = resource.Runtime,
|
||||
LastInfoSync = resource.LastInfoSync,
|
||||
CleanTitle = resource.CleanTitle,
|
||||
|
@ -210,7 +217,8 @@ namespace NzbDrone.Api.Movie
|
|||
movie.ProfileId = resource.ProfileId;
|
||||
|
||||
movie.Monitored = resource.Monitored;
|
||||
|
||||
movie.MinimumAvailability = resource.MinimumAvailability;
|
||||
|
||||
movie.RootFolderPath = resource.RootFolderPath;
|
||||
movie.Tags = resource.Tags;
|
||||
movie.AddOptions = resource.AddOptions;
|
||||
|
|
|
@ -34,10 +34,31 @@ namespace NzbDrone.Api.Wanted
|
|||
{
|
||||
pagingSpec.FilterExpression = v => v.Monitored == false;
|
||||
}
|
||||
else
|
||||
else if (pagingResource.FilterKey == "monitored" && pagingResource.FilterValue == "true")
|
||||
{
|
||||
pagingSpec.FilterExpression = v => v.Monitored == true;
|
||||
}
|
||||
else if (pagingResource.FilterKey == "moviestatus" && pagingResource.FilterValue == "available")
|
||||
{
|
||||
//TODO: might need to handle PreDB here
|
||||
pagingSpec.FilterExpression = v =>
|
||||
(v.MinimumAvailability == MovieStatusType.Released && v.Status >= MovieStatusType.Released) ||
|
||||
(v.MinimumAvailability == MovieStatusType.InCinemas && v.Status >= MovieStatusType.InCinemas) ||
|
||||
(v.MinimumAvailability == MovieStatusType.Announced && v.Status >= MovieStatusType.Announced) ||
|
||||
(v.MinimumAvailability == MovieStatusType.PreDB && v.Status >= MovieStatusType.Released);
|
||||
}
|
||||
else if (pagingResource.FilterKey == "moviestatus" && pagingResource.FilterValue == "announced")
|
||||
{
|
||||
pagingSpec.FilterExpression = v => v.Status == MovieStatusType.Announced;
|
||||
}
|
||||
else if (pagingResource.FilterKey == "moviestatus" && pagingResource.FilterValue == "incinemas")
|
||||
{
|
||||
pagingSpec.FilterExpression = v => v.Status == MovieStatusType.InCinemas;
|
||||
}
|
||||
else if (pagingResource.FilterKey == "moviestatus" && pagingResource.FilterValue == "released")
|
||||
{
|
||||
pagingSpec.FilterExpression = v => v.Status == MovieStatusType.Released;
|
||||
}
|
||||
|
||||
var resource = ApplyToPage(_movieService.MoviesWithoutFiles, pagingSpec, v => MapToResource(v, true));
|
||||
|
||||
|
|
|
@ -105,6 +105,12 @@ namespace NzbDrone.Core.Configuration
|
|||
set { SetValue("RssSyncInterval", value); }
|
||||
}
|
||||
|
||||
public int AvailabilityDelay
|
||||
{
|
||||
get { return GetValueInt("AvailabilityDelay",0); }
|
||||
set { SetValue("AvailabilityDelay", value); }
|
||||
}
|
||||
|
||||
public int NetImportSyncInterval
|
||||
{
|
||||
get { return GetValueInt("NetImportSyncInterval", 60); }
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace NzbDrone.Core.Configuration
|
|||
int RssSyncInterval { get; set; }
|
||||
int MinimumAge { get; set; }
|
||||
|
||||
int AvailabilityDelay { get; set; }
|
||||
|
||||
int NetImportSyncInterval { get; set; }
|
||||
|
||||
//UI
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
using FluentMigrator;
|
||||
//using FluentMigrator.Expressions;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(133)]
|
||||
public class add_minimumavailability : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
if (!this.Schema.Schema("dbo").Table("NetImport").Column("MinimumAvailability").Exists())
|
||||
{
|
||||
Alter.Table("NetImport").AddColumn("MinimumAvailability").AsInt32().WithDefaultValue(MovieStatusType.PreDB);
|
||||
}
|
||||
if (!this.Schema.Schema("dbo").Table("Movies").Column("MinimumAvailability").Exists())
|
||||
{
|
||||
Alter.Table("Movies").AddColumn("MinimumAvailability").AsInt32().WithDefaultValue(MovieStatusType.PreDB);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||
{
|
||||
public class AvailabilitySpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly IConfigService _settingsService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public AvailabilitySpecification(IConfigService settingsService, Logger logger)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public RejectionType Type => RejectionType.Permanent;
|
||||
|
||||
public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
if (searchCriteria != null)
|
||||
{
|
||||
if (searchCriteria.UserInvokedSearch)
|
||||
{
|
||||
_logger.Debug("Skipping availability check during search");
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
if (!subject.Movie.IsAvailable(_settingsService.AvailabilityDelay))
|
||||
{
|
||||
return Decision.Reject("Movie {0} will only be considered available {1} days after {2}", subject.Movie, _settingsService.AvailabilityDelay, subject.Movie.MinimumAvailability.ToString());
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
if (searchCriteria != null)
|
||||
{
|
||||
if (!searchCriteria.MonitoredEpisodesOnly)
|
||||
{
|
||||
_logger.Debug("Skipping availability check during search");
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
|
||||
/*if (subject.Series.Status != MovieStatusType.Released)
|
||||
{
|
||||
_logger.Debug("{0} is present in the DB but not yet available. skipping.", subject.Series);
|
||||
return Decision.Reject("Series is not yet available");
|
||||
}
|
||||
|
||||
/*var monitoredCount = subject.Episodes.Count(episode => episode.Monitored);
|
||||
if (monitoredCount == subject.Episodes.Count)
|
||||
{
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
_logger.Debug("Only {0}/{1} episodes are monitored. skipping.", monitoredCount, subject.Episodes.Count);*/
|
||||
return Decision.Reject("Episode is not yet available");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -185,14 +185,71 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
|||
movie.Genres.Add(genre.name);
|
||||
}
|
||||
|
||||
if (resource.status == "Released")
|
||||
//this is the way it should be handled
|
||||
//but unfortunately it seems
|
||||
//tmdb lacks alot of release date info
|
||||
//omdbapi is actually quite good for this info
|
||||
//except omdbapi has been having problems recently
|
||||
//so i will just leave this in as a comment
|
||||
//and use the 3 month logic that we were using before
|
||||
/*var now = DateTime.Now;
|
||||
if (now < movie.InCinemas)
|
||||
movie.Status = MovieStatusType.Announced;
|
||||
if (now >= movie.InCinemas)
|
||||
movie.Status = MovieStatusType.InCinemas;
|
||||
if (now >= movie.PhysicalRelease)
|
||||
movie.Status = MovieStatusType.Released;
|
||||
*/
|
||||
|
||||
|
||||
var now = DateTime.Now;
|
||||
//handle the case when we have both theatrical and physical release dates
|
||||
if (movie.InCinemas.HasValue && movie.PhysicalRelease.HasValue)
|
||||
{
|
||||
if (now < movie.InCinemas)
|
||||
movie.Status = MovieStatusType.Announced;
|
||||
else if (now >= movie.InCinemas)
|
||||
movie.Status = MovieStatusType.InCinemas;
|
||||
if (now >= movie.PhysicalRelease)
|
||||
movie.Status = MovieStatusType.Released;
|
||||
}
|
||||
//handle the case when we have theatrical release dates but we dont know the physical release date
|
||||
else if (movie.InCinemas.HasValue && (now >= movie.InCinemas))
|
||||
{
|
||||
movie.Status = MovieStatusType.InCinemas;
|
||||
}
|
||||
//handle the case where we only have a physical release date
|
||||
else if (movie.PhysicalRelease.HasValue && (now >= movie.PhysicalRelease))
|
||||
{
|
||||
movie.Status = MovieStatusType.Released;
|
||||
}
|
||||
//otherwise the title has only been announced
|
||||
else
|
||||
{
|
||||
movie.Status = MovieStatusType.Announced;
|
||||
}
|
||||
//since TMDB lacks alot of information lets assume that stuff is released if its been in cinemas for longer than 3 months.
|
||||
if (!movie.PhysicalRelease.HasValue && (movie.Status == MovieStatusType.InCinemas) && (((DateTime.Now).Subtract(movie.InCinemas.Value)).TotalSeconds > 60*60*24*30*3))
|
||||
{
|
||||
movie.Status = MovieStatusType.Released;
|
||||
}
|
||||
|
||||
//this matches with the old behavior before the creation of the MovieStatusType.InCinemas
|
||||
/*if (resource.status == "Released")
|
||||
{
|
||||
if (movie.InCinemas.HasValue && (((DateTime.Now).Subtract(movie.InCinemas.Value)).TotalSeconds <= 60 * 60 * 24 * 30 * 3))
|
||||
{
|
||||
movie.Status = MovieStatusType.InCinemas;
|
||||
}
|
||||
else
|
||||
{
|
||||
movie.Status = MovieStatusType.Released;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
movie.Status = MovieStatusType.Announced;
|
||||
}*/
|
||||
|
||||
if (resource.videos != null)
|
||||
{
|
||||
|
@ -650,6 +707,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
|||
newMovie.ProfileId = movie.ProfileId;
|
||||
newMovie.Monitored = movie.Monitored;
|
||||
newMovie.MovieFile = movie.MovieFile;
|
||||
newMovie.MinimumAvailability = movie.MinimumAvailability;
|
||||
|
||||
return newMovie;
|
||||
}
|
||||
|
|
|
@ -112,6 +112,7 @@ namespace NzbDrone.Core.NetImport
|
|||
m.RootFolderPath = ((NetImportDefinition) Definition).RootFolderPath;
|
||||
m.ProfileId = ((NetImportDefinition) Definition).ProfileId;
|
||||
m.Monitored = ((NetImportDefinition) Definition).ShouldMonitor;
|
||||
m.MinimumAvailability = ((NetImportDefinition) Definition).MinimumAvailability;
|
||||
return m;
|
||||
}).ToList();
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace NzbDrone.Core.NetImport
|
|||
Enabled = config.Validate().IsValid && Enabled,
|
||||
EnableAuto = true,
|
||||
ProfileId = 1,
|
||||
MinimumAvailability = MovieStatusType.PreDB,
|
||||
Implementation = GetType().Name,
|
||||
Settings = config
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using Marr.Data;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.NetImport
|
||||
{
|
||||
|
@ -9,6 +10,7 @@ namespace NzbDrone.Core.NetImport
|
|||
public bool Enabled { get; set; }
|
||||
public bool EnableAuto { get; set; }
|
||||
public bool ShouldMonitor { get; set; }
|
||||
public MovieStatusType MinimumAvailability { get; set; }
|
||||
public int ProfileId { get; set; }
|
||||
public LazyLoaded<Profile> Profile { get; set; }
|
||||
public string RootFolderPath { get; set; }
|
||||
|
|
|
@ -128,6 +128,7 @@
|
|||
<Compile Include="Datastore\Migration\128_remove_kickass.cs" />
|
||||
<Compile Include="Datastore\Migration\130_remove_wombles_kickass.cs" />
|
||||
<Compile Include="Datastore\Migration\132_rename_torrent_downloadstation.cs" />
|
||||
<Compile Include="Datastore\Migration\133_add_minimumavailability.cs" />
|
||||
<Compile Include="NetImport\TMDb\TMDbLanguageCodes.cs" />
|
||||
<Compile Include="NetImport\TMDb\TMDbSettings.cs" />
|
||||
<Compile Include="NetImport\TMDb\TMDbListType.cs" />
|
||||
|
@ -394,6 +395,7 @@
|
|||
<Compile Include="DecisionEngine\Specifications\RssSync\DelaySpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\RssSync\HistorySpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\RssSync\MonitoredEpisodeSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\RssSync\AvailabilitySpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\RssSync\ProperSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\Search\DailyEpisodeMatchSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\Search\EpisodeRequestedSpecification.cs" />
|
||||
|
@ -1341,4 +1343,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace NzbDrone.Core.Tv
|
|||
public MovieStatusType Status { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
public MovieStatusType MinimumAvailability { get; set; }
|
||||
public int ProfileId { get; set; }
|
||||
public DateTime? LastInfoSync { get; set; }
|
||||
public int Runtime { get; set; }
|
||||
|
@ -53,6 +54,35 @@ namespace NzbDrone.Core.Tv
|
|||
|
||||
public bool HasFile => MovieFileId > 0;
|
||||
|
||||
public bool IsAvailable(int delay = 0)
|
||||
{
|
||||
//the below line is what was used before delay was implemented, could still be used for cases when delay==0
|
||||
//return (Status >= MinimumAvailability || (MinimumAvailability == MovieStatusType.PreDB && Status >= MovieStatusType.Released));
|
||||
|
||||
//This more complex sequence handles the delay
|
||||
DateTime MinimumAvailabilityDate;
|
||||
switch (MinimumAvailability)
|
||||
{
|
||||
case MovieStatusType.TBA:
|
||||
case MovieStatusType.Announced:
|
||||
MinimumAvailabilityDate = DateTime.MinValue;
|
||||
break;
|
||||
case MovieStatusType.InCinemas:
|
||||
if (InCinemas.HasValue)
|
||||
MinimumAvailabilityDate = InCinemas.Value;
|
||||
else
|
||||
MinimumAvailabilityDate = DateTime.MaxValue;
|
||||
break;
|
||||
//TODO: might need to handle PreDB but for now treat the same as Released
|
||||
case MovieStatusType.Released:
|
||||
case MovieStatusType.PreDB:
|
||||
default:
|
||||
MinimumAvailabilityDate = PhysicalRelease.HasValue ? PhysicalRelease.Value : (InCinemas.HasValue ? InCinemas.Value.AddDays(90) : DateTime.MaxValue);
|
||||
break;
|
||||
}
|
||||
return DateTime.Now >= MinimumAvailabilityDate.AddDays(delay);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[{0}][{1}]", ImdbId, Title.NullSafe());
|
||||
|
@ -63,4 +93,4 @@ namespace NzbDrone.Core.Tv
|
|||
{
|
||||
public bool SearchForMovie { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,7 +196,6 @@ namespace NzbDrone.Core.Tv
|
|||
{
|
||||
return Query.Where(pagingSpec.FilterExpression)
|
||||
.AndWhere(m => m.MovieFileId == 0)
|
||||
.AndWhere(m => m.Status == MovieStatusType.Released)
|
||||
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
|
||||
.Skip(pagingSpec.PagingOffset())
|
||||
.Take(pagingSpec.PageSize);
|
||||
|
@ -242,4 +241,4 @@ namespace NzbDrone.Core.Tv
|
|||
return Query.Where(m => m.TmdbId == tmdbid).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
{
|
||||
public enum MovieStatusType
|
||||
{
|
||||
TBA = 0, //Nothing yet announced, only rumors, but still IMDb page
|
||||
Announced = 1, //AirDate is announced
|
||||
Released = 2 //Has at least one PreDB release
|
||||
TBA = 0, //Nothing yet announced, only rumors, but still IMDb page (this might not be used)
|
||||
Announced = 1, //Movie is announced but Cinema date is in the future or unknown
|
||||
InCinemas = 2, //Been in Cinemas for less than 3 months (since TMDB lacks complete information)
|
||||
Released = 3, //Physical or Web Release or been in cinemas for > 3 months (since TMDB lacks complete information)
|
||||
PreDB = 4 //this is only used for MinimumAvailability. Movie items should never be in this state.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<dl class="minimumavailability-tooltip-contents">
|
||||
<dt>Announced</dt>
|
||||
<dd>Consider the movie available after it has been announced</dd>
|
||||
<dt>In Cinemas</dt>
|
||||
<dd>Consider the movie available once it is In Cinemas</dd>
|
||||
<dt>Physical/Web</dt>
|
||||
<dd>Consider the movie available after Physical/Web release</dd>
|
||||
<dt>PreDB</dt>
|
||||
<dd>Consider the movie available if preDB contains at least one entry</dd>
|
||||
</dl>
|
|
@ -22,6 +22,8 @@ var view = Marionette.ItemView.extend({
|
|||
rootFolder : '.x-root-folder',
|
||||
seasonFolder : '.x-season-folder',
|
||||
monitor : '.x-monitor',
|
||||
minimumAvailability : '.x-minimumavailability',
|
||||
minimumAvailabilityTooltip : '.x-minimumavailability-tooltip',
|
||||
monitorTooltip : '.x-monitor-tooltip',
|
||||
addButton : '.x-add',
|
||||
addSearchButton : '.x-add-search',
|
||||
|
@ -70,6 +72,7 @@ var view = Marionette.ItemView.extend({
|
|||
|
||||
this.ui.seasonFolder.prop('checked', useSeasonFolder);
|
||||
this.ui.monitor.val(defaultMonitorEpisodes);
|
||||
this.ui.minimumAvailability.val("preDB");
|
||||
|
||||
//TODO: make this work via onRender, FM?
|
||||
//works with onShow, but stops working after the first render
|
||||
|
@ -88,6 +91,18 @@ var view = Marionette.ItemView.extend({
|
|||
placement : 'right',
|
||||
container : this.$el
|
||||
});
|
||||
|
||||
this.templateFunction = Marionette.TemplateCache.get('AddMovies/MinimumAvailabilityTooltipTemplate');
|
||||
var content1 = this.templateFunction();
|
||||
|
||||
this.ui.minimumAvailabilityTooltip.popover({
|
||||
content : content1,
|
||||
html :true,
|
||||
trigger : 'hover',
|
||||
title : 'When to Consider a Movie Available',
|
||||
placement : 'right',
|
||||
container : this.$el
|
||||
});
|
||||
},
|
||||
|
||||
_configureTemplateHelpers : function() {
|
||||
|
@ -168,6 +183,7 @@ var view = Marionette.ItemView.extend({
|
|||
var profile = this.ui.profile.val();
|
||||
var rootFolderPath = this.ui.rootFolder.children(':selected').text();
|
||||
var monitor = this.ui.monitor.val();
|
||||
var minAvail = this.ui.minimumAvailability.val();
|
||||
|
||||
var options = this._getAddMoviesOptions();
|
||||
options.searchForMovie = searchForMovie;
|
||||
|
@ -177,6 +193,7 @@ var view = Marionette.ItemView.extend({
|
|||
profileId : profile,
|
||||
rootFolderPath : rootFolderPath,
|
||||
addOptions : options,
|
||||
minimumAvailability : minAvail,
|
||||
monitored : (monitor === 'all' ? true : false)
|
||||
}, { silent : true });
|
||||
|
||||
|
|
|
@ -47,6 +47,16 @@
|
|||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-2">
|
||||
<label>Min Availability <i class="icon-sonarr-form-info minimumavailability-tooltip x-minimumavailability-tooltip"></i></label>
|
||||
<select class="form-control col-md-2 x-minimumavailability">
|
||||
<option value="announced">Announced</option>
|
||||
<option value="inCinemas">In Cinemas</option>
|
||||
<option value="released">Physical/Web</option>
|
||||
<option value="preDB">PreDB</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-2">
|
||||
<label>Profile</label>
|
||||
{{> ProfileSelectionPartial profiles}}
|
||||
|
|
|
@ -117,6 +117,9 @@
|
|||
.monitor-tooltip {
|
||||
margin-left : 5px;
|
||||
}
|
||||
.minimumavailability-tooltip {
|
||||
margin-left : 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-folders {
|
||||
|
@ -136,6 +139,13 @@
|
|||
padding-bottom : 8px;
|
||||
}
|
||||
}
|
||||
.minimumavailability-tooltip-contents {
|
||||
padding-bottom : 0px;
|
||||
|
||||
dd {
|
||||
padding-bottom :8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
li.add-new {
|
||||
|
|
|
@ -17,12 +17,7 @@ module.exports = NzbDroneCell.extend({
|
|||
this._setStatusWeight(3);
|
||||
}
|
||||
|
||||
if (numOfMonths > 3) {
|
||||
this.$el.html('<i class="icon-sonarr-movie-released grid-icon" title="Released"></i>');//TODO: Update for PreDB.me
|
||||
this._setStatusWeight(2);
|
||||
}
|
||||
|
||||
if (numOfMonths < 3) {
|
||||
if (status === 'inCinemas') {
|
||||
this.$el.html('<i class="icon-sonarr-movie-cinemas grid-icon" title="In Cinemas"></i>');
|
||||
this._setStatusWeight(2);
|
||||
}
|
||||
|
@ -32,11 +27,6 @@ module.exports = NzbDroneCell.extend({
|
|||
this._setStatusWeight(1);
|
||||
}
|
||||
|
||||
// else if (!monitored) {
|
||||
// this.$el.html('<i class="icon-sonarr-series-unmonitored grid-icon" title="Not Monitored"></i>');
|
||||
// this._setStatusWeight(0);
|
||||
// }
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
|
@ -18,12 +18,7 @@ module.exports = NzbDroneCell.extend({
|
|||
this._setStatusWeight(3);
|
||||
}
|
||||
|
||||
if (numOfMonths > 3) {
|
||||
this.$el.html('<div class="released-banner"><i class="icon-sonarr-movie-released grid-icon" title=""></i> Released</div>');//TODO: Update for PreDB.me
|
||||
this._setStatusWeight(2);
|
||||
}
|
||||
|
||||
if (numOfMonths < 3) {
|
||||
if (status ==='inCinemas') {
|
||||
this.$el.html('<div class="cinemas-banner"><i class="icon-sonarr-movie-cinemas grid-icon" title=""></i> In Cinemas</div>');
|
||||
this._setStatusWeight(2);
|
||||
}
|
||||
|
|
|
@ -60,6 +60,10 @@
|
|||
.fa-icon-color(@brand-warning);
|
||||
}
|
||||
|
||||
.icon-sonarr-available {
|
||||
.fa-icon-content(@fa-var-clock-o);
|
||||
}
|
||||
|
||||
.icon-sonarr-edit {
|
||||
.fa-icon-content(@fa-var-wrench);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,9 @@ Handlebars.registerHelper('tmdbUrl', function() {
|
|||
Handlebars.registerHelper('youTubeTrailerUrl', function() {
|
||||
return 'https://www.youtube.com/watch?v=' + this.youTubeTrailerId;
|
||||
});
|
||||
Handlebars.registerHelper('allFlicksUrl', function() {
|
||||
return this.allFlicksUrl;
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('homepage', function() {
|
||||
return this.website;
|
||||
|
@ -73,25 +76,21 @@ Handlebars.registerHelper('alternativeTitlesString', function() {
|
|||
Handlebars.registerHelper('GetStatus', function() {
|
||||
var monitored = this.monitored;
|
||||
var status = this.status;
|
||||
var inCinemas = this.inCinemas;
|
||||
var date = new Date(inCinemas);
|
||||
var timeSince = new Date().getTime() - date.getTime();
|
||||
var numOfMonths = timeSince / 1000 / 60 / 60 / 24 / 30;
|
||||
//var inCinemas = this.inCinemas;
|
||||
//var date = new Date(inCinemas);
|
||||
//var timeSince = new Date().getTime() - date.getTime();
|
||||
//var numOfMonths = timeSince / 1000 / 60 / 60 / 24 / 30;
|
||||
|
||||
|
||||
if (status === "announced") {
|
||||
return new Handlebars.SafeString('<i class="icon-sonarr-movie-announced grid-icon" title=""></i> Announced');
|
||||
}
|
||||
|
||||
|
||||
if (numOfMonths < 3) {
|
||||
|
||||
if (status ==="inCinemas") {
|
||||
return new Handlebars.SafeString('<i class="icon-sonarr-movie-cinemas grid-icon" title=""></i> In Cinemas');
|
||||
}
|
||||
|
||||
if (numOfMonths > 3) {
|
||||
return new Handlebars.SafeString('<i class="icon-sonarr-movie-released grid-icon" title=""></i> Released');//TODO: Update for PreDB.me
|
||||
}
|
||||
|
||||
|
||||
if (status === 'released') {
|
||||
return new Handlebars.SafeString('<i class="icon-sonarr-movie-released grid-icon" title=""></i> Released');
|
||||
}
|
||||
|
@ -104,30 +103,22 @@ Handlebars.registerHelper('GetStatus', function() {
|
|||
Handlebars.registerHelper('GetBannerStatus', function() {
|
||||
var monitored = this.monitored;
|
||||
var status = this.status;
|
||||
var inCinemas = this.inCinemas;
|
||||
var date = new Date(inCinemas);
|
||||
var timeSince = new Date().getTime() - date.getTime();
|
||||
var numOfMonths = timeSince / 1000 / 60 / 60 / 24 / 30;
|
||||
//var inCinemas = this.inCinemas;
|
||||
//var date = new Date(inCinemas);
|
||||
//var timeSince = new Date().getTime() - date.getTime();
|
||||
//var numOfMonths = timeSince / 1000 / 60 / 60 / 24 / 30;
|
||||
|
||||
if (status === "announced") {
|
||||
return new Handlebars.SafeString('<div class="announced-banner"><i class="icon-sonarr-movie-announced grid-icon" title=""></i> Announced</div>');
|
||||
}
|
||||
|
||||
if (numOfMonths < 3) {
|
||||
if (status === "inCinemas") {
|
||||
return new Handlebars.SafeString('<div class="cinemas-banner"><i class="icon-sonarr-movie-cinemas grid-icon" title=""></i> In Cinemas</div>');
|
||||
}
|
||||
|
||||
if (status === 'released') {
|
||||
return new Handlebars.SafeString('<div class="released-banner"><i class="icon-sonarr-movie-released grid-icon" title=""></i> Released</div>');
|
||||
}
|
||||
|
||||
if (numOfMonths > 3) {
|
||||
return new Handlebars.SafeString('<div class="released-banner"><i class="icon-sonarr-movie-released grid-icon" title=""></i> Released</div>');//TODO: Update for PreDB.me
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
else if (!monitored) {
|
||||
return new Handlebars.SafeString('<div class="announced-banner"><i class="icon-sonarr-series-unmonitored grid-icon" title=""></i> Not Monitored</div>');
|
||||
}
|
||||
|
@ -145,7 +136,7 @@ Handlebars.registerHelper('DownloadedStatusColor', function() {
|
|||
return "success";
|
||||
}
|
||||
|
||||
if (this.status != "released") {
|
||||
if (!this.isAvailable){
|
||||
return "primary";
|
||||
}
|
||||
|
||||
|
@ -160,8 +151,6 @@ Handlebars.registerHelper('DownloadedStatus', function() {
|
|||
if (!this.monitored) {
|
||||
return "Not Monitored";
|
||||
}
|
||||
|
||||
|
||||
return "Missing";
|
||||
});
|
||||
|
||||
|
|
|
@ -17,12 +17,11 @@
|
|||
{{/if}}
|
||||
|
||||
<span class="label label-info">{{Bytes sizeOnDisk}}</span>
|
||||
|
||||
{{#if_eq status compare="released"}}
|
||||
{{#if_eq status compare="announced"}}
|
||||
<span class="label label-default">{{inCinemas}}</span>
|
||||
{{else}}
|
||||
<span class="label label-info">{{inCinemas}}</span>
|
||||
{{else}}
|
||||
<span class="label label-default">Announced</span>
|
||||
{{/if_eq}}
|
||||
{{/if_eq}}
|
||||
<span class="label label-{{DownloadedStatusColor}}" title="{{DownloadedQuality}}">{{DownloadedStatus}}</span>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
|
@ -40,6 +39,10 @@
|
|||
{{#if youTubeTrailerId}}
|
||||
<a href="{{youTubeTrailerUrl}}" class="label label-info">Trailer</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if allFlicksUrl}}
|
||||
<a href="{{allFlicksUrl}}" class="label label-info">AllFlicks</a>
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -32,6 +32,20 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">Minimum Availability</label>
|
||||
<div class="col-sm-1 col-sm-push-4 help-inline">
|
||||
<i class="icon-sonarr-form-info" title="When the movie is considered Available"/>
|
||||
</div>
|
||||
<div class="col-sm-4 col-sm-pull-1">
|
||||
<select class="form-control x-minimumavailability" name="minimumAvailability">
|
||||
<option value="announced">Announced</option>
|
||||
<option value="inCinemas">In Cinemas</option>
|
||||
<option value="released">Physical/Web</option>
|
||||
<option value="preDB">PreDB</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--<div class="form-group">
|
||||
<label class="col-sm-4 control-label">Use Season Folder</label>
|
||||
|
|
|
@ -13,6 +13,7 @@ module.exports = Marionette.ItemView.extend({
|
|||
ui : {
|
||||
monitored : '.x-monitored',
|
||||
profile : '.x-profiles',
|
||||
minimumAvailability : '.x-minimumavailability',
|
||||
seasonFolder : '.x-season-folder',
|
||||
rootFolder : '.x-root-folder',
|
||||
selectedCount : '.x-selected-count',
|
||||
|
@ -53,6 +54,7 @@ module.exports = Marionette.ItemView.extend({
|
|||
var selected = this.editorGrid.getSelectedModels();
|
||||
|
||||
var monitored = this.ui.monitored.val();
|
||||
var minAvail = this.ui.minimumAvailability.val();
|
||||
var profile = this.ui.profile.val();
|
||||
var seasonFolder = this.ui.seasonFolder.val();
|
||||
var rootFolder = this.ui.rootFolder.val();
|
||||
|
@ -64,6 +66,10 @@ module.exports = Marionette.ItemView.extend({
|
|||
model.set('monitored', false);
|
||||
}
|
||||
|
||||
if (minAvail !=='noChange') {
|
||||
model.set('minimumAvailability', minAvail);
|
||||
}
|
||||
|
||||
if (profile !== 'noChange') {
|
||||
model.set('profileId', parseInt(profile, 10));
|
||||
}
|
||||
|
@ -123,4 +129,4 @@ module.exports = Marionette.ItemView.extend({
|
|||
|
||||
vent.trigger(vent.Commands.OpenModalCommand, updateFilesMoviesView);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,6 +10,18 @@
|
|||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-2">
|
||||
<label>Min Availability</label>
|
||||
|
||||
<select class="form-control x-action x-minimumavailability">
|
||||
<option value="noChange">No change</option>
|
||||
<option value="announced">Announced</option>
|
||||
<option value="inCinemas">In Cinemas</option>
|
||||
<option value="released">Physical/Web</option>
|
||||
<option value="preDB">PreDB</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-2">
|
||||
<label>Profile</label>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="row">
|
||||
<div class="series-legend legend col-xs-6 col-sm-4">
|
||||
<ul class='legend-labels'>
|
||||
<li><span class="progress-bar"></span>Missing, but not yet available.</li>
|
||||
<li><span class="progress-bar"></span>Missing, but not yet considered availabile</li>
|
||||
<li><span class="progress-bar-success"></span>Downloaded and imported.</li>
|
||||
<li><span class="progress-bar-danger"></span>Missing and monitored.</li>
|
||||
<li><span class="progress-bar-warning"></span>Missing, but not monitored.</li>
|
||||
|
@ -17,6 +17,9 @@
|
|||
<dt>Released</dt>
|
||||
<dd>{{released}}</dd>
|
||||
|
||||
<dt>In Cinemas</dt>
|
||||
<dd>{{incinemas}}</dd>
|
||||
|
||||
<dt>Announced</dt>
|
||||
<dd>{{announced}}</dd>
|
||||
</dl>
|
||||
|
|
|
@ -328,6 +328,7 @@ module.exports = Marionette.Layout.extend({
|
|||
var episodeFiles = 0;
|
||||
var announced = 0;
|
||||
var released = 0;
|
||||
var incinemas = 0;
|
||||
var monitored = 0;
|
||||
|
||||
_.each(MoviesCollection.models, function(model) {
|
||||
|
@ -336,6 +337,8 @@ module.exports = Marionette.Layout.extend({
|
|||
|
||||
if (model.get('status').toLowerCase() === 'released') {
|
||||
released++;
|
||||
} else if (model.get('status').toLowerCase() === 'incinemas') {
|
||||
incinemas++;
|
||||
} else {
|
||||
announced++;
|
||||
}
|
||||
|
@ -348,6 +351,7 @@ module.exports = Marionette.Layout.extend({
|
|||
footerModel.set({
|
||||
series : series,
|
||||
released : released,
|
||||
incinemas : incinemas,
|
||||
announced : announced,
|
||||
monitored : monitored,
|
||||
unmonitored : series - monitored,
|
||||
|
|
|
@ -14,16 +14,16 @@ module.exports = Backbone.Model.extend({
|
|||
getStatus : function() {
|
||||
var monitored = this.get("monitored");
|
||||
var status = this.get("status");
|
||||
var inCinemas = this.get("inCinemas");
|
||||
var date = new Date(inCinemas);
|
||||
var timeSince = new Date().getTime() - date.getTime();
|
||||
var numOfMonths = timeSince / 1000 / 60 / 60 / 24 / 30;
|
||||
//var inCinemas = this.get("inCinemas");
|
||||
//var date = new Date(inCinemas);
|
||||
//var timeSince = new Date().getTime() - date.getTime();
|
||||
//var numOfMonths = timeSince / 1000 / 60 / 60 / 24 / 30;
|
||||
|
||||
if (status === "announced") {
|
||||
return "announced"
|
||||
}
|
||||
|
||||
if (numOfMonths < 3 && numOfMonths > 0) {
|
||||
if (status === "inCinemas") {
|
||||
|
||||
return "inCinemas";
|
||||
}
|
||||
|
@ -31,9 +31,5 @@ module.exports = Backbone.Model.extend({
|
|||
if (status === 'released') {
|
||||
return "released";
|
||||
}
|
||||
|
||||
if (numOfMonths > 3) {
|
||||
return "released";//TODO: Update for PreDB.me
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -113,11 +113,14 @@ var Collection = PageableCollection.extend({
|
|||
statusWeight : {
|
||||
sortValue : function(model, attr) {
|
||||
if (model.getStatus() == "released") {
|
||||
return 1;
|
||||
return 3;
|
||||
}
|
||||
if (model.getStatus() == "inCinemas") {
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
if (mode.getStatus() == "announced") {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
},
|
||||
|
@ -190,4 +193,4 @@ Collection = AsPersistedStateCollection.call(Collection);
|
|||
|
||||
var data = ApiData.get('movie');
|
||||
|
||||
module.exports = new Collection(data, { full : true }).bindSignalR();
|
||||
module.exports = new Collection(data, { full : true }).bindSignalR();
|
||||
|
|
|
@ -37,4 +37,15 @@
|
|||
<input type="number" name="rssSyncInterval" class="form-control" min="0" max="720"/>
|
||||
</div>
|
||||
</div>
|
||||
<legend>Availability Options</legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Availability Delay</label>
|
||||
<div class="col-sm-1 col-sm-push-2 help-inline">
|
||||
<i class="icon-sonarr-form-info" title="A movie will be considered available during RssSync this many days after(or before) the Min Availability has been satisfied. (can be negative)"/>
|
||||
<i class="icon-sonarr-form-info" title="This only effects RssSyncs, It does not effect how movies are displayed or what is shown in the Wanted/Missing View"/>
|
||||
</div>
|
||||
<div class="col-sm-2 col-sm-pull-1">
|
||||
<input type="number" name="availabilityDelay" class="form-control" min="-365" max="365"/>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
|
|
@ -19,6 +19,7 @@ var view = Marionette.ItemView.extend({
|
|||
|
||||
ui : {
|
||||
profile : '.x-profile',
|
||||
minimumAvailability : '.x-minimumavailability',
|
||||
rootFolder : '.x-root-folder',
|
||||
},
|
||||
|
||||
|
@ -48,10 +49,12 @@ var view = Marionette.ItemView.extend({
|
|||
|
||||
_onBeforeSave : function() {
|
||||
var profile = this.ui.profile.val();
|
||||
var minAvail = this.ui.minimumAvailability.val();
|
||||
var rootFolderPath = this.ui.rootFolder.children(':selected').text();
|
||||
this.model.set({
|
||||
profileId : profile,
|
||||
rootFolderPath : rootFolderPath,
|
||||
minimumAvailability : minAvail,
|
||||
})
|
||||
},
|
||||
|
||||
|
|
|
@ -60,7 +60,18 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Minimum Availability</label>
|
||||
|
||||
<div class="col-sm-5">
|
||||
<select class="form-control x-minimumavailability" name="minimumAvailability">
|
||||
<option value="announced">Announced</option>
|
||||
<option value="inCinemas">In Cinemas</option>
|
||||
<option value="released">Physical/Web</option>
|
||||
<option value="preDB">PreDB</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Quality Profile</label>
|
||||
|
|
|
@ -36,7 +36,23 @@ var Collection = PagableCollection.extend({
|
|||
'unmonitored' : [
|
||||
'monitored',
|
||||
'false'
|
||||
]
|
||||
],
|
||||
'announced' : [
|
||||
'moviestatus',
|
||||
'announced'
|
||||
],
|
||||
'incinemas' : [
|
||||
'moviestatus',
|
||||
'incinemas'
|
||||
],
|
||||
'released' : [
|
||||
'moviestatus',
|
||||
'released'
|
||||
],
|
||||
'available' : [
|
||||
'moviestatus',
|
||||
'available',
|
||||
]
|
||||
},
|
||||
|
||||
parseState : function(resp) {
|
||||
|
|
|
@ -132,7 +132,7 @@ module.exports = Marionette.Layout.extend({
|
|||
};
|
||||
var filterOptions = {
|
||||
type : 'radio',
|
||||
storeState : false,
|
||||
storeState : true,
|
||||
menuKey : 'wanted.filterMode',
|
||||
defaultAction : 'monitored',
|
||||
items : [
|
||||
|
@ -149,9 +149,37 @@ module.exports = Marionette.Layout.extend({
|
|||
tooltip : 'Unmonitored Only',
|
||||
icon : 'icon-sonarr-unmonitored',
|
||||
callback : this._setFilter
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
{
|
||||
key : 'announced',
|
||||
title : '',
|
||||
tooltip : 'Announced Only',
|
||||
icon : 'icon-sonarr-movie-announced',
|
||||
callback : this._setFilter
|
||||
},
|
||||
{
|
||||
key : 'incinemas',
|
||||
title : '',
|
||||
tooltip : 'In Cinemas Only',
|
||||
icon : 'icon-sonarr-movie-cinemas',
|
||||
callback : this._setFilter
|
||||
},
|
||||
{
|
||||
key : 'released',
|
||||
title : '',
|
||||
tooltip : 'Released Only',
|
||||
icon : 'icon-sonarr-movie-released',
|
||||
callback : this._setFilter
|
||||
},
|
||||
{
|
||||
key : 'available',
|
||||
title : '',
|
||||
tooltip : 'Available Only',
|
||||
icon : 'icon-sonarr-available',
|
||||
callback : this._setFilter
|
||||
}
|
||||
]
|
||||
};
|
||||
this.toolbar.show(new ToolbarLayout({
|
||||
left : [leftSideButtons],
|
||||
right : [filterOptions],
|
||||
|
|
Loading…
Reference in New Issue