You've already forked Sonarr
							
							
				mirror of
				https://github.com/Sonarr/Sonarr.git
				synced 2025-10-31 00:07:55 +02:00 
			
		
		
		
	Added season pass for toggling monitored status of seasons
Linked from missing
This commit is contained in:
		| @@ -14,13 +14,20 @@ namespace NzbDrone.Api.Seasons | ||||
|  | ||||
|             GetResourceAll = GetSeasons; | ||||
|             UpdateResource = SetMonitored; | ||||
|  | ||||
|             Post["/pass"] = x => SetSeasonPass(); | ||||
|         } | ||||
|  | ||||
|         private List<SeasonResource> GetSeasons() | ||||
|         { | ||||
|             var seriesId = Request.Query.SeriesId; | ||||
|  | ||||
|             return ToListResource<Season>(() => _seasonService.GetSeasonsBySeries(seriesId)); | ||||
|             if (seriesId.HasValue) | ||||
|             { | ||||
|                 return ToListResource<Season>(() => _seasonService.GetSeasonsBySeries(seriesId)); | ||||
|             } | ||||
|  | ||||
|             return ToListResource<Season>(() => _seasonService.GetAllSeasons()); | ||||
|         } | ||||
|  | ||||
|         private SeasonResource SetMonitored(SeasonResource seasonResource) | ||||
| @@ -29,5 +36,13 @@ namespace NzbDrone.Api.Seasons | ||||
|  | ||||
|             return seasonResource; | ||||
|         } | ||||
|  | ||||
|         private List<SeasonResource> SetSeasonPass() | ||||
|         { | ||||
|             var seriesId = Request.Form.SeriesId; | ||||
|             var seasonNumber = Request.Form.SeasonNumber; | ||||
|  | ||||
|             return ToListResource<Season>(() => _seasonService.SetSeasonPass(seriesId, seasonNumber)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
										
											Binary file not shown.
										
									
								
							| @@ -16,10 +16,11 @@ define( | ||||
|         'Logs/Files/Layout', | ||||
|         'Release/Layout', | ||||
|         'System/Layout', | ||||
|         'SeasonPass/Layout', | ||||
|         'Shared/NotFoundView', | ||||
|         'Shared/Modal/Region' | ||||
|     ], function (App, Marionette, HistoryLayout, SettingsLayout, AddSeriesLayout, SeriesIndexLayout, SeriesDetailsLayout, SeriesCollection, MissingLayout, SeriesModel, CalendarLayout, | ||||
|         LogsLayout, LogFileLayout, ReleaseLayout, SystemLayout, NotFoundView) { | ||||
|         LogsLayout, LogFileLayout, ReleaseLayout, SystemLayout, SeasonPassLayout, NotFoundView) { | ||||
|         return Marionette.Controller.extend({ | ||||
|  | ||||
|             series: function () { | ||||
| @@ -40,11 +41,6 @@ define( | ||||
|                 } | ||||
|             }, | ||||
|  | ||||
|  | ||||
|             _showSeriesDetail: function(seriesModel){ | ||||
|  | ||||
|             }, | ||||
|  | ||||
|             addSeries: function (action) { | ||||
|                 this._setTitle('Add Series'); | ||||
|                 App.mainRegion.show(new AddSeriesLayout({action: action})); | ||||
| @@ -55,7 +51,6 @@ define( | ||||
|                 App.mainRegion.show(new CalendarLayout()); | ||||
|             }, | ||||
|  | ||||
|  | ||||
|             settings: function (action) { | ||||
|                 this._setTitle('Settings'); | ||||
|                 App.mainRegion.show(new SettingsLayout({action: action})); | ||||
| @@ -95,6 +90,11 @@ define( | ||||
|                 App.mainRegion.show(new SystemLayout()); | ||||
|             }, | ||||
|  | ||||
|             seasonPass: function () { | ||||
|                 this._setTitle('Season Pass'); | ||||
|                 App.mainRegion.show(new SeasonPassLayout()); | ||||
|             }, | ||||
|  | ||||
|             notFound: function () { | ||||
|                 this._setTitle('Not Found'); | ||||
|                 App.mainRegion.show(new NotFoundView(this)); | ||||
|   | ||||
| @@ -9,8 +9,9 @@ define( | ||||
|         'Cells/EpisodeTitleCell', | ||||
|         'Cells/RelativeDateCell', | ||||
|         'Shared/Grid/Pager', | ||||
|         'Shared/Toolbar/ToolbarLayout', | ||||
|         'Shared/LoadingView' | ||||
|     ], function (Marionette, Backgrid, MissingCollection, SeriesTitleCell, EpisodeNumberCell, EpisodeTitleCell, RelativeDateCell, GridPager, LoadingView) { | ||||
|     ], function (Marionette, Backgrid, MissingCollection, SeriesTitleCell, EpisodeNumberCell, EpisodeTitleCell, RelativeDateCell, GridPager, ToolbarLayout, LoadingView) { | ||||
|         return Marionette.Layout.extend({ | ||||
|             template: 'Missing/MissingLayoutTemplate', | ||||
|  | ||||
| @@ -47,6 +48,19 @@ define( | ||||
|                     } | ||||
|                 ], | ||||
|  | ||||
|             leftSideButtons: { | ||||
|                 type      : 'default', | ||||
|                 storeState: false, | ||||
|                 items     : | ||||
|                     [ | ||||
|                         { | ||||
|                             title  : 'Season Pass', | ||||
|                             icon   : 'icon-bookmark', | ||||
|                             route  : 'seasonpass' | ||||
|                         } | ||||
|                     ] | ||||
|             }, | ||||
|  | ||||
|             _showTable: function () { | ||||
|                 this.missing.show(new Backgrid.Grid({ | ||||
|                     columns   : this.columns, | ||||
| @@ -69,6 +83,18 @@ define( | ||||
|                 this.missingCollection.fetch().done(function () { | ||||
|                     self._showTable(); | ||||
|                 }); | ||||
|  | ||||
|                 this._showToolbar(); | ||||
|             }, | ||||
|  | ||||
|             _showToolbar: function () { | ||||
|                 this.toolbar.show(new ToolbarLayout({ | ||||
|                     left   : | ||||
|                         [ | ||||
|                             this.leftSideButtons | ||||
|                         ], | ||||
|                     context: this | ||||
|                 })); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
|   | ||||
| @@ -26,6 +26,7 @@ require( | ||||
|                 'logs/:action'              : 'logs', | ||||
|                 'rss'                       : 'rss', | ||||
|                 'system'                    : 'system', | ||||
|                 'seasonpass'                : 'seasonPass', | ||||
|                 ':whatever'                 : 'notFound' | ||||
|             } | ||||
|         }); | ||||
|   | ||||
							
								
								
									
										39
									
								
								UI/SeasonPass/Layout.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								UI/SeasonPass/Layout.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| 'use strict'; | ||||
| define( | ||||
|     [ | ||||
|         'marionette', | ||||
|         'Series/SeriesCollection', | ||||
|         'Series/SeasonCollection', | ||||
|         'SeasonPass/SeriesCollectionView', | ||||
|         'Shared/LoadingView' | ||||
|     ], function (Marionette, | ||||
|                  SeriesCollection, | ||||
|                  SeasonCollection, | ||||
|                  SeriesCollectionView, | ||||
|                  LoadingView) { | ||||
|         return Marionette.Layout.extend({ | ||||
|             template: 'SeasonPass/LayoutTemplate', | ||||
|  | ||||
|             regions: { | ||||
|                 series: '#x-series' | ||||
|             }, | ||||
|  | ||||
|             onShow: function () { | ||||
|                 var self = this; | ||||
|  | ||||
|                 this.series.show(new LoadingView()); | ||||
|  | ||||
|                 this.seriesCollection = SeriesCollection; | ||||
|                 this.seasonCollection = new SeasonCollection(); | ||||
|  | ||||
|                 var promise = this.seasonCollection.fetch(); | ||||
|  | ||||
|                 promise.done(function () { | ||||
|                     self.series.show(new SeriesCollectionView({ | ||||
|                         collection: self.seriesCollection, | ||||
|                         seasonCollection: self.seasonCollection | ||||
|                     })); | ||||
|                 }); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
							
								
								
									
										11
									
								
								UI/SeasonPass/LayoutTemplate.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								UI/SeasonPass/LayoutTemplate.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <div class="row"> | ||||
|     <div class="span12"> | ||||
|         <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="span12"> | ||||
|         <div id="x-series"></div> | ||||
|     </div> | ||||
| </div> | ||||
							
								
								
									
										26
									
								
								UI/SeasonPass/SeriesCollectionView.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								UI/SeasonPass/SeriesCollectionView.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| 'use strict'; | ||||
| define( | ||||
|     [ | ||||
|         'marionette', | ||||
|         'SeasonPass/SeriesLayout' | ||||
|     ], function (Marionette, SeriesLayout) { | ||||
|         return Marionette.CollectionView.extend({ | ||||
|  | ||||
|             itemView: SeriesLayout, | ||||
|  | ||||
|             initialize: function (options) { | ||||
|  | ||||
|                 if (!options.seasonCollection) { | ||||
|                     throw 'seasonCollection is needed'; | ||||
|                 } | ||||
|  | ||||
|                 this.seasonCollection = options.seasonCollection; | ||||
|             }, | ||||
|  | ||||
|             itemViewOptions: function () { | ||||
|                 return { | ||||
|                     seasonCollection: this.seasonCollection | ||||
|                 }; | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
							
								
								
									
										117
									
								
								UI/SeasonPass/SeriesLayout.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								UI/SeasonPass/SeriesLayout.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| 'use strict'; | ||||
| define( | ||||
|     [ | ||||
|         'marionette', | ||||
|         'backgrid', | ||||
|         'Series/SeasonCollection', | ||||
|         'Cells/ToggleCell', | ||||
|         'Shared/Actioneer' | ||||
|     ], function (Marionette, Backgrid, SeasonCollection, ToggleCell, Actioneer) { | ||||
|         return Marionette.Layout.extend({ | ||||
|             template: 'SeasonPass/SeriesLayoutTemplate', | ||||
|  | ||||
|             ui: { | ||||
|                 seasonSelect: '.x-season-select', | ||||
|                 expander    : '.x-expander', | ||||
|                 seasonGrid  : '.x-season-grid' | ||||
|             }, | ||||
|  | ||||
|             events: { | ||||
|                 'change .x-season-select': '_seasonSelected', | ||||
|                 'click .x-expander'        : '_expand' | ||||
|             }, | ||||
|  | ||||
|             regions: { | ||||
|                 seasonGrid: '.x-season-grid' | ||||
|             }, | ||||
|  | ||||
|             columns: | ||||
|                 [ | ||||
|                     { | ||||
|                         name      : 'monitored', | ||||
|                         label     : '', | ||||
|                         cell      : ToggleCell, | ||||
|                         trueClass : 'icon-bookmark', | ||||
|                         falseClass: 'icon-bookmark-empty', | ||||
|                         tooltip   : 'Toggle monitored status', | ||||
|                         sortable  : false | ||||
|                     }, | ||||
|                     { | ||||
|                         name : 'seasonNumber', | ||||
|                         label: 'Season', | ||||
|                         cell : Backgrid.IntegerCell.extend({ | ||||
|                             className: 'season-number-cell' | ||||
|                         }) | ||||
|                     } | ||||
|                 ], | ||||
|  | ||||
|             initialize: function (options) { | ||||
|                 this.seasonCollection = options.seasonCollection.bySeries(this.model.get('id')); | ||||
|                 this.model.set('seasons', this.seasonCollection); | ||||
|                 this.expanded = false; | ||||
|             }, | ||||
|  | ||||
|             onRender: function () { | ||||
|                 this.seasonGrid.show(new Backgrid.Grid({ | ||||
|                     columns   : this.columns, | ||||
|                     collection: this.seasonCollection, | ||||
|                     className : 'table table-condensed season-grid span5' | ||||
|                 })); | ||||
|  | ||||
|                 if (!this.expanded) { | ||||
|                     this.seasonGrid.$el.hide(); | ||||
|                 } | ||||
|  | ||||
|                 this._setExpanderIcon(); | ||||
|             }, | ||||
|  | ||||
|             _seasonSelected: function () { | ||||
|                 var self = this; | ||||
|                 var seasonNumber = parseInt(this.ui.seasonSelect.val()); | ||||
|  | ||||
|                 if (seasonNumber == -1) { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 var promise = $.ajax({ | ||||
|                     url: this.seasonCollection.url + '/pass', | ||||
|                     type: 'POST', | ||||
|                     data: { | ||||
|                         seriesId: this.model.get('id'), | ||||
|                         seasonNumber: seasonNumber | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|                 promise.done(function (data) { | ||||
|                     self.seasonCollection = new SeasonCollection(data); | ||||
|                     self.render(); | ||||
|                 }); | ||||
|             }, | ||||
|  | ||||
|             _expand: function () { | ||||
|                 if (this.expanded) { | ||||
|                     this.ui.seasonGrid.slideUp(); | ||||
|                     this.expanded = false; | ||||
|                 } | ||||
|  | ||||
|                 else { | ||||
|                     this.ui.seasonGrid.slideDown(); | ||||
|                     this.expanded = true; | ||||
|                 } | ||||
|  | ||||
|                 this._setExpanderIcon(); | ||||
|             }, | ||||
|  | ||||
|             _setExpanderIcon: function () { | ||||
|                 if (this.expanded) { | ||||
|                     this.ui.expander.removeClass('icon-chevron-right'); | ||||
|                     this.ui.expander.addClass('icon-chevron-down'); | ||||
|                 } | ||||
|  | ||||
|                 else { | ||||
|                     this.ui.expander.removeClass('icon-chevron-down'); | ||||
|                     this.ui.expander.addClass('icon-chevron-right'); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
							
								
								
									
										32
									
								
								UI/SeasonPass/SeriesLayoutTemplate.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								UI/SeasonPass/SeriesLayoutTemplate.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| <div class="seasonpass-series"> | ||||
|     <div class="row"> | ||||
|         <div class="span11"> | ||||
|             <i class="icon-chevron-right x-expander expander pull-left"/> | ||||
|  | ||||
|             <span class="title span5"> | ||||
|                 <a href="{{route}}"> | ||||
|                     {{title}} | ||||
|                 </a> | ||||
|             </span> | ||||
|             <select class="x-season-select season-select"> | ||||
|                 <option value="-1">Select season...</option> | ||||
|                 {{#each seasons.models}} | ||||
|                     {{#if_eq attributes.seasonNumber compare="0"}} | ||||
|                         <option value="{{attributes.seasonumber}}">Specials</option> | ||||
|                     {{else}} | ||||
|                         <option value="{{attributes.seasonNumber}}">Season {{attributes.seasonNumber}}</option> | ||||
|                     {{/if_eq}} | ||||
|                 {{/each}} | ||||
|             </select> | ||||
|             <span class="help-inline"> | ||||
|                 <i class="icon-question-sign" title="Selecting a season will unmonitor all previous seasons"/> | ||||
|             </span> | ||||
|         </div> | ||||
|     </div> | ||||
|  | ||||
|     <div class="row"> | ||||
|         <div class="span11"> | ||||
|             <div class="x-season-grid season-grid"></div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| @@ -1,24 +1,25 @@ | ||||
| 'use strict'; | ||||
| define( | ||||
|     [ | ||||
|         'Series/SeasonModel', | ||||
|         'backbone.pageable' | ||||
|     ], function (SeasonModel, PageAbleCollection) { | ||||
|         return PageAbleCollection.extend({ | ||||
|         'backbone', | ||||
|         'Series/SeasonModel' | ||||
|     ], function (Backbone, SeasonModel) { | ||||
|         return Backbone.Collection.extend({ | ||||
|             url  : window.ApiRoot + '/season', | ||||
|             model: SeasonModel, | ||||
|  | ||||
|             mode: 'client', | ||||
|  | ||||
|             state: { | ||||
|                 sortKey : 'seasonNumber', | ||||
|                 order   : 1, | ||||
|                 pageSize: 1000000 | ||||
|             comparator: function (season) { | ||||
|                 return -season.get('seasonNumber'); | ||||
|             }, | ||||
|  | ||||
|             queryParams: { | ||||
|                 sortKey: null, | ||||
|                 order  : null | ||||
|             bySeries: function (series) { | ||||
|                 var filtered = this.filter(function (season) { | ||||
|                     return season.get('seriesId') === series; | ||||
|                 }); | ||||
|  | ||||
|                 var SeasonCollection = require('Series/SeasonCollection'); | ||||
|  | ||||
|                 return new SeasonCollection(filtered); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
|   | ||||
| @@ -246,4 +246,30 @@ | ||||
|  | ||||
| .series-legend { | ||||
|   padding-top: 5px; | ||||
| } | ||||
|  | ||||
| .seasonpass-series { | ||||
|   .card; | ||||
|   margin  : 20px 0px; | ||||
|  | ||||
|   .title { | ||||
|     font-weight: 300; | ||||
|     font-size: 24px; | ||||
|     line-height: 30px; | ||||
|     margin-left: 5px; | ||||
|   } | ||||
|  | ||||
|   .season-select { | ||||
|     margin-bottom: 0px; | ||||
|   } | ||||
|  | ||||
|   .expander { | ||||
|     .clickable; | ||||
|     line-height: 30px; | ||||
|     margin-left: 8px; | ||||
|   } | ||||
|  | ||||
|   .season-grid { | ||||
|     margin-top: 10px; | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user