mirror of
https://github.com/Radarr/Radarr.git
synced 2024-09-11 12:02:35 +02:00
Cleanup Series Code from UI (#2525)
This commit is contained in:
parent
1dbb856ced
commit
e70e76adcb
@ -1,16 +1,9 @@
|
||||
var Backbone = require('backbone');
|
||||
var SeriesModel = require('../../Series/SeriesModel');
|
||||
var EpisodeModel = require('../../Series/EpisodeModel');
|
||||
var MovieModel = require('../../Movies/MovieModel');
|
||||
var MoviesCollection = require('../../Movies/FullMovieCollection');
|
||||
|
||||
module.exports = Backbone.Model.extend({
|
||||
parse : function(model) {
|
||||
if (model.series) {
|
||||
model.series = new SeriesModel(model.series);
|
||||
model.episode = new EpisodeModel(model.episode);
|
||||
model.episode.set('series', model.series);
|
||||
}
|
||||
|
||||
//if (model.movie) {
|
||||
// model.movie = new MovieModel(model.movie);
|
||||
|
@ -1,16 +1,8 @@
|
||||
var Backbone = require('backbone');
|
||||
var SeriesModel = require('../../Series/SeriesModel');
|
||||
var EpisodeModel = require('../../Series/EpisodeModel');
|
||||
var MovieModel = require('../../Movies/MovieModel');
|
||||
|
||||
module.exports = Backbone.Model.extend({
|
||||
parse : function(model) {
|
||||
if (model.series) {
|
||||
model.series = new SeriesModel(model.series);
|
||||
model.episode = new EpisodeModel(model.episode);
|
||||
model.episode.set('series', model.series);
|
||||
}
|
||||
|
||||
if (model.movie) {
|
||||
model.movie = new MovieModel(model.movie);
|
||||
}
|
||||
|
@ -1,13 +1,8 @@
|
||||
var Backbone = require('backbone');
|
||||
var SeriesModel = require('../../Series/SeriesModel');
|
||||
var EpisodeModel = require('../../Series/EpisodeModel');
|
||||
var MovieModel = require('../../Movies/MovieModel');
|
||||
|
||||
module.exports = Backbone.Model.extend({
|
||||
parse : function(model) {
|
||||
model.series = new SeriesModel(model.series);
|
||||
model.episode = new EpisodeModel(model.episode);
|
||||
model.episode.set('series', model.series);
|
||||
model.movie = new MovieModel(model.movie);
|
||||
return model;
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
var Backbone = require('backbone');
|
||||
var SeriesModel = require('../Series/SeriesModel');
|
||||
var _ = require('underscore');
|
||||
|
||||
module.exports = Backbone.Collection.extend({
|
||||
url : window.NzbDrone.ApiRoot + '/series/lookup',
|
||||
model : SeriesModel,
|
||||
|
||||
parse : function(response) {
|
||||
var self = this;
|
||||
|
||||
_.each(response, function(model) {
|
||||
model.id = undefined;
|
||||
|
||||
if (self.unmappedFolderModel) {
|
||||
model.path = self.unmappedFolderModel.get('folder').path;
|
||||
}
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
});
|
@ -1,53 +0,0 @@
|
||||
var vent = require('vent');
|
||||
var AppLayout = require('../AppLayout');
|
||||
var Marionette = require('marionette');
|
||||
var RootFolderLayout = require('./RootFolders/RootFolderLayout');
|
||||
var ExistingSeriesCollectionView = require('./Existing/AddExistingSeriesCollectionView');
|
||||
var AddSeriesView = require('./AddSeriesView');
|
||||
var ProfileCollection = require('../Profile/ProfileCollection');
|
||||
var RootFolderCollection = require('./RootFolders/RootFolderCollection');
|
||||
require('../Series/SeriesCollection');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'AddSeries/AddSeriesLayoutTemplate',
|
||||
|
||||
regions : {
|
||||
workspace : '#add-series-workspace'
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-import' : '_importSeries',
|
||||
'click .x-add-new' : '_addSeries'
|
||||
},
|
||||
|
||||
attributes : {
|
||||
id : 'add-series-screen'
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
ProfileCollection.fetch();
|
||||
RootFolderCollection.fetch().done(function() {
|
||||
RootFolderCollection.synced = true;
|
||||
});
|
||||
},
|
||||
|
||||
onShow : function() {
|
||||
this.workspace.show(new AddSeriesView());
|
||||
},
|
||||
|
||||
_folderSelected : function(options) {
|
||||
vent.trigger(vent.Commands.CloseModalCommand);
|
||||
|
||||
this.workspace.show(new ExistingSeriesCollectionView({ model : options.model }));
|
||||
},
|
||||
|
||||
_importSeries : function() {
|
||||
this.rootFolderLayout = new RootFolderLayout();
|
||||
this.listenTo(this.rootFolderLayout, 'folderSelected', this._folderSelected);
|
||||
AppLayout.modalRegion.show(this.rootFolderLayout);
|
||||
},
|
||||
|
||||
_addSeries : function() {
|
||||
this.workspace.show(new AddSeriesView());
|
||||
}
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="btn-group add-series-btn-group btn-group-lg btn-block">
|
||||
<button type="button" class="btn btn-default col-md-10 col-xs-8 add-series-import-btn x-import">
|
||||
<i class="icon-sonarr-hdd"/>
|
||||
Import existing series on disk
|
||||
</button>
|
||||
<button class="btn btn-default col-md-2 col-xs-4 x-add-new"><i class="icon-sonarr-active hidden-xs"></i> Add New Movie</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="add-series-workspace"></div>
|
||||
</div>
|
||||
</div>
|
@ -1,182 +0,0 @@
|
||||
var _ = require('underscore');
|
||||
var vent = require('vent');
|
||||
var Marionette = require('marionette');
|
||||
var AddSeriesCollection = require('./AddSeriesCollection');
|
||||
var SearchResultCollectionView = require('./SearchResultCollectionView');
|
||||
var EmptyView = require('./EmptyView');
|
||||
var NotFoundView = require('./NotFoundView');
|
||||
var ErrorView = require('./ErrorView');
|
||||
var LoadingView = require('../Shared/LoadingView');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'AddSeries/AddSeriesViewTemplate',
|
||||
|
||||
regions : {
|
||||
searchResult : '#search-result'
|
||||
},
|
||||
|
||||
ui : {
|
||||
seriesSearch : '.x-series-search',
|
||||
searchBar : '.x-search-bar',
|
||||
loadMore : '.x-load-more'
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-load-more' : '_onLoadMore'
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
this.isExisting = options.isExisting;
|
||||
this.collection = new AddSeriesCollection();
|
||||
|
||||
if (this.isExisting) {
|
||||
this.collection.unmappedFolderModel = this.model;
|
||||
}
|
||||
|
||||
if (this.isExisting) {
|
||||
this.className = 'existing-series';
|
||||
} else {
|
||||
this.className = 'new-series';
|
||||
}
|
||||
|
||||
this.listenTo(vent, vent.Events.SeriesAdded, this._onSeriesAdded);
|
||||
this.listenTo(this.collection, 'sync', this._showResults);
|
||||
|
||||
this.resultCollectionView = new SearchResultCollectionView({
|
||||
collection : this.collection,
|
||||
isExisting : this.isExisting
|
||||
});
|
||||
|
||||
this.throttledSearch = _.debounce(this.search, 1000, { trailing : true }).bind(this);
|
||||
},
|
||||
|
||||
onRender : function() {
|
||||
var self = this;
|
||||
|
||||
this.$el.addClass(this.className);
|
||||
|
||||
this.ui.seriesSearch.keyup(function(e) {
|
||||
|
||||
if (_.contains([
|
||||
9,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
37,
|
||||
38,
|
||||
39,
|
||||
40,
|
||||
91,
|
||||
92,
|
||||
93
|
||||
], e.keyCode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
self._abortExistingSearch();
|
||||
self.throttledSearch({
|
||||
term : self.ui.seriesSearch.val()
|
||||
});
|
||||
});
|
||||
|
||||
this._clearResults();
|
||||
|
||||
if (this.isExisting) {
|
||||
this.ui.searchBar.hide();
|
||||
}
|
||||
},
|
||||
|
||||
onShow : function() {
|
||||
this.ui.seriesSearch.focus();
|
||||
},
|
||||
|
||||
search : function(options) {
|
||||
var self = this;
|
||||
|
||||
this.collection.reset();
|
||||
|
||||
if (!options.term || options.term === this.collection.term) {
|
||||
return Marionette.$.Deferred().resolve();
|
||||
}
|
||||
|
||||
this.searchResult.show(new LoadingView());
|
||||
this.collection.term = options.term;
|
||||
this.currentSearchPromise = this.collection.fetch({
|
||||
data : { term : options.term }
|
||||
});
|
||||
|
||||
this.currentSearchPromise.fail(function() {
|
||||
self._showError();
|
||||
});
|
||||
|
||||
return this.currentSearchPromise;
|
||||
},
|
||||
|
||||
_onSeriesAdded : function(options) {
|
||||
if (this.isExisting && options.series.get('path') === this.model.get('folder').path) {
|
||||
this.close();
|
||||
}
|
||||
|
||||
else if (!this.isExisting) {
|
||||
this.collection.term = '';
|
||||
this.collection.reset();
|
||||
this._clearResults();
|
||||
this.ui.seriesSearch.val('');
|
||||
this.ui.seriesSearch.focus();
|
||||
}
|
||||
},
|
||||
|
||||
_onLoadMore : function() {
|
||||
var showingAll = this.resultCollectionView.showMore();
|
||||
this.ui.searchBar.show();
|
||||
|
||||
if (showingAll) {
|
||||
this.ui.loadMore.hide();
|
||||
}
|
||||
},
|
||||
|
||||
_clearResults : function() {
|
||||
if (!this.isExisting) {
|
||||
this.searchResult.show(new EmptyView());
|
||||
} else {
|
||||
this.searchResult.close();
|
||||
}
|
||||
},
|
||||
|
||||
_showResults : function() {
|
||||
if (!this.isClosed) {
|
||||
if (this.collection.length === 0) {
|
||||
this.ui.searchBar.show();
|
||||
this.searchResult.show(new NotFoundView({ term : this.collection.term }));
|
||||
} else {
|
||||
this.searchResult.show(this.resultCollectionView);
|
||||
if (!this.showingAll && this.isExisting) {
|
||||
this.ui.loadMore.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_abortExistingSearch : function() {
|
||||
if (this.currentSearchPromise && this.currentSearchPromise.readyState > 0 && this.currentSearchPromise.readyState < 4) {
|
||||
console.log('aborting previous pending search request.');
|
||||
this.currentSearchPromise.abort();
|
||||
} else {
|
||||
this._clearResults();
|
||||
}
|
||||
},
|
||||
|
||||
_showError : function() {
|
||||
if (!this.isClosed) {
|
||||
this.ui.searchBar.show();
|
||||
this.searchResult.show(new ErrorView({ term : this.collection.term }));
|
||||
this.collection.term = '';
|
||||
}
|
||||
}
|
||||
});
|
@ -1,24 +0,0 @@
|
||||
{{#if folder.path}}
|
||||
<div class="unmapped-folder-path">
|
||||
<div class="col-md-12">
|
||||
{{folder.path}}
|
||||
</div>
|
||||
</div>{{/if}}
|
||||
<div class="x-search-bar">
|
||||
<div class="input-group input-group-lg add-series-search">
|
||||
<span class="input-group-addon"><i class="icon-sonarr-search"/></span>
|
||||
|
||||
{{#if folder}}
|
||||
<input type="text" class="form-control x-series-search" value="{{folder.name}}">
|
||||
{{else}}
|
||||
<input type="text" class="form-control x-series-search" placeholder="Start typing the name of the movie you want to add ...">
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div id="search-result" class="result-list col-md-12"/>
|
||||
</div>
|
||||
<div class="btn btn-block text-center new-series-loadmore x-load-more" style="display: none;">
|
||||
<i class="icon-sonarr-load-more"/>
|
||||
more
|
||||
</div>
|
@ -1,5 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.CompositeView.extend({
|
||||
template : 'AddSeries/EmptyViewTemplate'
|
||||
});
|
@ -1,3 +0,0 @@
|
||||
<div class="text-center hint col-md-12">
|
||||
<span>You can also search by tvdbid using the tvdb: prefixes.</span>
|
||||
</div>
|
@ -1,13 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.CompositeView.extend({
|
||||
template : 'AddSeries/ErrorViewTemplate',
|
||||
|
||||
initialize : function(options) {
|
||||
this.options = options;
|
||||
},
|
||||
|
||||
templateHelpers : function() {
|
||||
return this.options;
|
||||
}
|
||||
});
|
@ -1,7 +0,0 @@
|
||||
<div class="text-center col-md-12">
|
||||
<h3>
|
||||
There was an error searching for '{{term}}'.
|
||||
</h3>
|
||||
|
||||
If the series title contains non-alphanumeric characters try removing them, otherwise try your search again later.
|
||||
</div>
|
@ -1,51 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
var AddSeriesView = require('../AddSeriesView');
|
||||
var UnmappedFolderCollection = require('./UnmappedFolderCollection');
|
||||
|
||||
module.exports = Marionette.CompositeView.extend({
|
||||
itemView : AddSeriesView,
|
||||
itemViewContainer : '.x-loading-folders',
|
||||
template : 'AddSeries/Existing/AddExistingSeriesCollectionViewTemplate',
|
||||
|
||||
ui : {
|
||||
loadingFolders : '.x-loading-folders'
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
this.collection = new UnmappedFolderCollection();
|
||||
this.collection.importItems(this.model);
|
||||
},
|
||||
|
||||
showCollection : function() {
|
||||
this._showAndSearch(0);
|
||||
},
|
||||
|
||||
appendHtml : function(collectionView, itemView, index) {
|
||||
collectionView.ui.loadingFolders.before(itemView.el);
|
||||
},
|
||||
|
||||
_showAndSearch : function(index) {
|
||||
var self = this;
|
||||
var model = this.collection.at(index);
|
||||
|
||||
if (model) {
|
||||
var currentIndex = index;
|
||||
var folderName = model.get('folder').name;
|
||||
this.addItemView(model, this.getItemView(), index);
|
||||
this.children.findByModel(model).search({ term : folderName }).always(function() {
|
||||
if (!self.isClosed) {
|
||||
self._showAndSearch(currentIndex + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else {
|
||||
this.ui.loadingFolders.hide();
|
||||
}
|
||||
},
|
||||
|
||||
itemViewOptions : {
|
||||
isExisting : true
|
||||
}
|
||||
|
||||
});
|
@ -1,5 +0,0 @@
|
||||
<div class="x-existing-folders">
|
||||
<div class="loading-folders x-loading-folders">
|
||||
Loading search results from TheTVDB for your series, this may take a few minutes.
|
||||
</div>
|
||||
</div>
|
@ -1,20 +0,0 @@
|
||||
var Backbone = require('backbone');
|
||||
var UnmappedFolderModel = require('./UnmappedFolderModel');
|
||||
var _ = require('underscore');
|
||||
|
||||
module.exports = Backbone.Collection.extend({
|
||||
model : UnmappedFolderModel,
|
||||
|
||||
importItems : function(rootFolderModel) {
|
||||
|
||||
this.reset();
|
||||
var rootFolder = rootFolderModel;
|
||||
|
||||
_.each(rootFolderModel.get('unmappedFolders'), function(folder) {
|
||||
this.push(new UnmappedFolderModel({
|
||||
rootFolder : rootFolder,
|
||||
folder : folder
|
||||
}));
|
||||
}, this);
|
||||
}
|
||||
});
|
@ -1,3 +0,0 @@
|
||||
var Backbone = require('backbone');
|
||||
|
||||
module.exports = Backbone.Model.extend({});
|
@ -1,18 +0,0 @@
|
||||
<dl class="monitor-tooltip-contents">
|
||||
<dt>All</dt>
|
||||
<dd>Monitor all episodes except specials</dd>
|
||||
<dt>Future</dt>
|
||||
<dd>Monitor episodes that have not aired yet</dd>
|
||||
<dt>Missing</dt>
|
||||
<dd>Monitor episodes that do not have files or have not aired yet</dd>
|
||||
<dt>Existing</dt>
|
||||
<dd>Monitor episodes that have files or have not aired yet</dd>
|
||||
<dt>First Season</dt>
|
||||
<dd>Monitor all episodes of the first season. All other seasons will be ignored</dd>
|
||||
<dt>Latest Season</dt>
|
||||
<dd>Monitor all episodes of the latest season and future seasons</dd>
|
||||
<dt>None</dt>
|
||||
<dd>No episodes will be monitored.</dd>
|
||||
{{!--<dt>Latest Season</dt>-->
|
||||
<dd>Monitor all episodes the latest season only, previous seasons will be ignored</dd>--}}
|
||||
</dl>
|
@ -1,13 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.CompositeView.extend({
|
||||
template : 'AddSeries/NotFoundViewTemplate',
|
||||
|
||||
initialize : function(options) {
|
||||
this.options = options;
|
||||
},
|
||||
|
||||
templateHelpers : function() {
|
||||
return this.options;
|
||||
}
|
||||
});
|
@ -1,7 +0,0 @@
|
||||
<div class="text-center col-md-12">
|
||||
<h3>
|
||||
Sorry. We couldn't find any series matching '{{term}}'
|
||||
</h3>
|
||||
<a href="https://github.com/NzbDrone/NzbDrone/wiki/FAQ#wiki-why-cant-i-add-a-new-show-to-nzbdrone-its-on-thetvdb">Why can't I find my show?</a>
|
||||
|
||||
</div>
|
@ -1,10 +0,0 @@
|
||||
var Backbone = require('backbone');
|
||||
var RootFolderModel = require('./RootFolderModel');
|
||||
require('../../Mixins/backbone.signalr.mixin');
|
||||
|
||||
var RootFolderCollection = Backbone.Collection.extend({
|
||||
url : window.NzbDrone.ApiRoot + '/rootfolder',
|
||||
model : RootFolderModel
|
||||
});
|
||||
|
||||
module.exports = new RootFolderCollection();
|
@ -1,8 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
var RootFolderItemView = require('./RootFolderItemView');
|
||||
|
||||
module.exports = Marionette.CompositeView.extend({
|
||||
template : 'AddSeries/RootFolders/RootFolderCollectionViewTemplate',
|
||||
itemViewContainer : '.x-root-folders',
|
||||
itemView : RootFolderItemView
|
||||
});
|
@ -1,13 +0,0 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-10 ">
|
||||
Path
|
||||
</th>
|
||||
<th class="col-md-3">
|
||||
Free Space
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="x-root-folders"></tbody>
|
||||
</table>
|
@ -1,28 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.ItemView.extend({
|
||||
template : 'AddSeries/RootFolders/RootFolderItemViewTemplate',
|
||||
className : 'recent-folder',
|
||||
tagName : 'tr',
|
||||
|
||||
initialize : function() {
|
||||
this.listenTo(this.model, 'change', this.render);
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-delete' : 'removeFolder',
|
||||
'click .x-folder' : 'folderSelected'
|
||||
},
|
||||
|
||||
removeFolder : function() {
|
||||
var self = this;
|
||||
|
||||
this.model.destroy().success(function() {
|
||||
self.close();
|
||||
});
|
||||
},
|
||||
|
||||
folderSelected : function() {
|
||||
this.trigger('folderSelected', this.model);
|
||||
}
|
||||
});
|
@ -1,9 +0,0 @@
|
||||
<td class="col-md-10 x-folder folder-path">
|
||||
{{path}}
|
||||
</td>
|
||||
<td class="col-md-3 x-folder folder-free-space">
|
||||
<span>{{Bytes freeSpace}}</span>
|
||||
</td>
|
||||
<td class="col-md-1">
|
||||
<i class="icon-sonarr-delete x-delete"></i>
|
||||
</td>
|
@ -1,77 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
var RootFolderCollectionView = require('./RootFolderCollectionView');
|
||||
var RootFolderCollection = require('./RootFolderCollection');
|
||||
var RootFolderModel = require('./RootFolderModel');
|
||||
var LoadingView = require('../../Shared/LoadingView');
|
||||
var AsValidatedView = require('../../Mixins/AsValidatedView');
|
||||
require('../../Mixins/FileBrowser');
|
||||
|
||||
var Layout = Marionette.Layout.extend({
|
||||
template : 'AddSeries/RootFolders/RootFolderLayoutTemplate',
|
||||
|
||||
ui : {
|
||||
pathInput : '.x-path'
|
||||
},
|
||||
|
||||
regions : {
|
||||
currentDirs : '#current-dirs'
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-add' : '_addFolder',
|
||||
'keydown .x-path input' : '_keydown'
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
this.collection = RootFolderCollection;
|
||||
this.rootfolderListView = new RootFolderCollectionView({ collection : RootFolderCollection });
|
||||
|
||||
this.listenTo(this.rootfolderListView, 'itemview:folderSelected', this._onFolderSelected);
|
||||
},
|
||||
|
||||
onShow : function() {
|
||||
this.listenTo(RootFolderCollection, 'sync', this._showCurrentDirs);
|
||||
this.currentDirs.show(new LoadingView());
|
||||
|
||||
if (RootFolderCollection.synced) {
|
||||
this._showCurrentDirs();
|
||||
}
|
||||
|
||||
this.ui.pathInput.fileBrowser();
|
||||
},
|
||||
|
||||
_onFolderSelected : function(options) {
|
||||
this.trigger('folderSelected', options);
|
||||
},
|
||||
|
||||
_addFolder : function() {
|
||||
var self = this;
|
||||
|
||||
var newDir = new RootFolderModel({
|
||||
Path : this.ui.pathInput.val()
|
||||
});
|
||||
|
||||
this.bindToModelValidation(newDir);
|
||||
|
||||
newDir.save().done(function() {
|
||||
RootFolderCollection.add(newDir);
|
||||
self.trigger('folderSelected', { model : newDir });
|
||||
});
|
||||
},
|
||||
|
||||
_showCurrentDirs : function() {
|
||||
this.currentDirs.show(this.rootfolderListView);
|
||||
},
|
||||
|
||||
_keydown : function(e) {
|
||||
if (e.keyCode !== 13) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._addFolder();
|
||||
}
|
||||
});
|
||||
|
||||
var Layout = AsValidatedView.apply(Layout);
|
||||
|
||||
module.exports = Layout;
|
@ -1,36 +0,0 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>Select Folder</h3>
|
||||
</div>
|
||||
<div class="modal-body root-folders-modal">
|
||||
<div class="validation-errors"></div>
|
||||
<div class="alert alert-info">Enter the path that contains some or all of your TV series, you will be able to choose which series you want to import<button type="button" class="close" data-dismiss="alert">×</button></div>
|
||||
|
||||
<div class="row">
|
||||
<div class="form-group">
|
||||
|
||||
<div class="col-md-12">
|
||||
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"> <i class="icon-sonarr-folder-open"></i></span>
|
||||
<input class="form-control x-path" type="text" validation-name="path" placeholder="Enter path to folder that contains your shows">
|
||||
<span class="input-group-btn"><button class="btn btn-success x-add"><i class="icon-sonarr-ok"/></button></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row root-folders">
|
||||
<div class="col-md-12">
|
||||
{{#if items}}
|
||||
<h4>Recent Folders</h4>
|
||||
{{/if}}
|
||||
<div id="current-dirs" class="root-folders-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
@ -1,8 +0,0 @@
|
||||
var Backbone = require('backbone');
|
||||
|
||||
module.exports = Backbone.Model.extend({
|
||||
urlRoot : window.NzbDrone.ApiRoot + '/rootfolder',
|
||||
defaults : {
|
||||
freeSpace : 0
|
||||
}
|
||||
});
|
@ -1,11 +0,0 @@
|
||||
<select class="col-md-4 form-control x-root-folder" validation-name="RootFolderPath">
|
||||
{{#if this}}
|
||||
{{#each this}}
|
||||
<option value="{{id}}">{{path}}</option>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<option value="">Select Path</option>
|
||||
{{/if}}
|
||||
<option value="addNew">Add a different path</option>
|
||||
</select>
|
||||
|
@ -1,29 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
var SearchResultView = require('./SearchResultView');
|
||||
|
||||
module.exports = Marionette.CollectionView.extend({
|
||||
itemView : SearchResultView,
|
||||
|
||||
initialize : function(options) {
|
||||
this.isExisting = options.isExisting;
|
||||
this.showing = 1;
|
||||
},
|
||||
|
||||
showAll : function() {
|
||||
this.showingAll = true;
|
||||
this.render();
|
||||
},
|
||||
|
||||
showMore : function() {
|
||||
this.showing += 5;
|
||||
this.render();
|
||||
|
||||
return this.showing >= this.collection.length;
|
||||
},
|
||||
|
||||
appendHtml : function(collectionView, itemView, index) {
|
||||
if (!this.isExisting || index < this.showing || index === 0) {
|
||||
collectionView.$el.append(itemView.el);
|
||||
}
|
||||
}
|
||||
});
|
@ -1,288 +0,0 @@
|
||||
var _ = require('underscore');
|
||||
var vent = require('vent');
|
||||
var AppLayout = require('../AppLayout');
|
||||
var Backbone = require('backbone');
|
||||
var Marionette = require('marionette');
|
||||
var Profiles = require('../Profile/ProfileCollection');
|
||||
var RootFolders = require('./RootFolders/RootFolderCollection');
|
||||
var RootFolderLayout = require('./RootFolders/RootFolderLayout');
|
||||
var SeriesCollection = require('../Series/SeriesCollection');
|
||||
var Config = require('../Config');
|
||||
var Messenger = require('../Shared/Messenger');
|
||||
var AsValidatedView = require('../Mixins/AsValidatedView');
|
||||
|
||||
require('jquery.dotdotdot');
|
||||
|
||||
var view = Marionette.ItemView.extend({
|
||||
|
||||
template : 'AddSeries/SearchResultViewTemplate',
|
||||
|
||||
ui : {
|
||||
profile : '.x-profile',
|
||||
rootFolder : '.x-root-folder',
|
||||
seasonFolder : '.x-season-folder',
|
||||
seriesType : '.x-series-type',
|
||||
monitor : '.x-monitor',
|
||||
monitorTooltip : '.x-monitor-tooltip',
|
||||
addButton : '.x-add',
|
||||
addSearchButton : '.x-add-search',
|
||||
overview : '.x-overview'
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-add' : '_addWithoutSearch',
|
||||
'click .x-add-search' : '_addAndSearch',
|
||||
'change .x-profile' : '_profileChanged',
|
||||
'change .x-root-folder' : '_rootFolderChanged',
|
||||
'change .x-season-folder' : '_seasonFolderChanged',
|
||||
'change .x-series-type' : '_seriesTypeChanged',
|
||||
'change .x-monitor' : '_monitorChanged'
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
|
||||
if (!this.model) {
|
||||
throw 'model is required';
|
||||
}
|
||||
|
||||
this.templateHelpers = {};
|
||||
this._configureTemplateHelpers();
|
||||
|
||||
this.listenTo(vent, Config.Events.ConfigUpdatedEvent, this._onConfigUpdated);
|
||||
this.listenTo(this.model, 'change', this.render);
|
||||
this.listenTo(RootFolders, 'all', this._rootFoldersUpdated);
|
||||
},
|
||||
|
||||
onRender : function() {
|
||||
|
||||
var defaultProfile = Config.getValue(Config.Keys.DefaultProfileId);
|
||||
var defaultRoot = Config.getValue(Config.Keys.DefaultRootFolderId);
|
||||
var useSeasonFolder = Config.getValueBoolean(Config.Keys.UseSeasonFolder, true);
|
||||
var defaultSeriesType = Config.getValue(Config.Keys.DefaultSeriesType, 'standard');
|
||||
var defaultMonitorEpisodes = Config.getValue(Config.Keys.MonitorEpisodes, 'missing');
|
||||
|
||||
if (Profiles.get(defaultProfile)) {
|
||||
this.ui.profile.val(defaultProfile);
|
||||
}
|
||||
|
||||
if (RootFolders.get(defaultRoot)) {
|
||||
this.ui.rootFolder.val(defaultRoot);
|
||||
}
|
||||
|
||||
this.ui.seasonFolder.prop('checked', useSeasonFolder);
|
||||
this.ui.seriesType.val(defaultSeriesType);
|
||||
this.ui.monitor.val(defaultMonitorEpisodes);
|
||||
|
||||
//TODO: make this work via onRender, FM?
|
||||
//works with onShow, but stops working after the first render
|
||||
this.ui.overview.dotdotdot({
|
||||
height : 120
|
||||
});
|
||||
|
||||
this.templateFunction = Marionette.TemplateCache.get('AddSeries/MonitoringTooltipTemplate');
|
||||
var content = this.templateFunction();
|
||||
|
||||
this.ui.monitorTooltip.popover({
|
||||
content : content,
|
||||
html : true,
|
||||
trigger : 'hover',
|
||||
title : 'Episode Monitoring Options',
|
||||
placement : 'right',
|
||||
container : this.$el
|
||||
});
|
||||
},
|
||||
|
||||
_configureTemplateHelpers : function() {
|
||||
var existingSeries = SeriesCollection.where({ tvdbId : this.model.get('tvdbId') });
|
||||
|
||||
if (existingSeries.length > 0) {
|
||||
this.templateHelpers.existing = existingSeries[0].toJSON();
|
||||
}
|
||||
|
||||
this.templateHelpers.profiles = Profiles.toJSON();
|
||||
|
||||
if (!this.model.get('isExisting')) {
|
||||
this.templateHelpers.rootFolders = RootFolders.toJSON();
|
||||
}
|
||||
},
|
||||
|
||||
_onConfigUpdated : function(options) {
|
||||
if (options.key === Config.Keys.DefaultProfileId) {
|
||||
this.ui.profile.val(options.value);
|
||||
}
|
||||
|
||||
else if (options.key === Config.Keys.DefaultRootFolderId) {
|
||||
this.ui.rootFolder.val(options.value);
|
||||
}
|
||||
|
||||
else if (options.key === Config.Keys.UseSeasonFolder) {
|
||||
this.ui.seasonFolder.prop('checked', options.value);
|
||||
}
|
||||
|
||||
else if (options.key === Config.Keys.DefaultSeriesType) {
|
||||
this.ui.seriesType.val(options.value);
|
||||
}
|
||||
|
||||
else if (options.key === Config.Keys.MonitorEpisodes) {
|
||||
this.ui.monitor.val(options.value);
|
||||
}
|
||||
},
|
||||
|
||||
_profileChanged : function() {
|
||||
Config.setValue(Config.Keys.DefaultProfileId, this.ui.profile.val());
|
||||
},
|
||||
|
||||
_seasonFolderChanged : function() {
|
||||
Config.setValue(Config.Keys.UseSeasonFolder, this.ui.seasonFolder.prop('checked'));
|
||||
},
|
||||
|
||||
_rootFolderChanged : function() {
|
||||
var rootFolderValue = this.ui.rootFolder.val();
|
||||
if (rootFolderValue === 'addNew') {
|
||||
var rootFolderLayout = new RootFolderLayout();
|
||||
this.listenToOnce(rootFolderLayout, 'folderSelected', this._setRootFolder);
|
||||
AppLayout.modalRegion.show(rootFolderLayout);
|
||||
} else {
|
||||
Config.setValue(Config.Keys.DefaultRootFolderId, rootFolderValue);
|
||||
}
|
||||
},
|
||||
|
||||
_seriesTypeChanged : function() {
|
||||
Config.setValue(Config.Keys.DefaultSeriesType, this.ui.seriesType.val());
|
||||
},
|
||||
|
||||
_monitorChanged : function() {
|
||||
Config.setValue(Config.Keys.MonitorEpisodes, this.ui.monitor.val());
|
||||
},
|
||||
|
||||
_setRootFolder : function(options) {
|
||||
vent.trigger(vent.Commands.CloseModalCommand);
|
||||
this.ui.rootFolder.val(options.model.id);
|
||||
this._rootFolderChanged();
|
||||
},
|
||||
|
||||
_addWithoutSearch : function() {
|
||||
this._addSeries(false);
|
||||
},
|
||||
|
||||
_addAndSearch : function() {
|
||||
this._addSeries(true);
|
||||
},
|
||||
|
||||
_addSeries : function(searchForMissingEpisodes) {
|
||||
var addButton = this.ui.addButton;
|
||||
var addSearchButton = this.ui.addSearchButton;
|
||||
|
||||
addButton.addClass('disabled');
|
||||
addSearchButton.addClass('disabled');
|
||||
|
||||
var profile = this.ui.profile.val();
|
||||
var rootFolderPath = this.ui.rootFolder.children(':selected').text();
|
||||
var seriesType = this.ui.seriesType.val();
|
||||
var seasonFolder = this.ui.seasonFolder.prop('checked');
|
||||
|
||||
var options = this._getAddSeriesOptions();
|
||||
options.searchForMissingEpisodes = searchForMissingEpisodes;
|
||||
|
||||
this.model.set({
|
||||
profileId : profile,
|
||||
rootFolderPath : rootFolderPath,
|
||||
seasonFolder : seasonFolder,
|
||||
seriesType : seriesType,
|
||||
addOptions : options,
|
||||
monitored : true
|
||||
}, { silent : true });
|
||||
|
||||
var self = this;
|
||||
var promise = this.model.save();
|
||||
|
||||
if (searchForMissingEpisodes) {
|
||||
this.ui.addSearchButton.spinForPromise(promise);
|
||||
}
|
||||
|
||||
else {
|
||||
this.ui.addButton.spinForPromise(promise);
|
||||
}
|
||||
|
||||
promise.always(function() {
|
||||
addButton.removeClass('disabled');
|
||||
addSearchButton.removeClass('disabled');
|
||||
});
|
||||
|
||||
promise.done(function() {
|
||||
SeriesCollection.add(self.model);
|
||||
|
||||
self.close();
|
||||
|
||||
Messenger.show({
|
||||
message : 'Added: ' + self.model.get('title'),
|
||||
actions : {
|
||||
goToSeries : {
|
||||
label : 'Go to Series',
|
||||
action : function() {
|
||||
Backbone.history.navigate('/series/' + self.model.get('titleSlug'), { trigger : true });
|
||||
}
|
||||
}
|
||||
},
|
||||
hideAfter : 8,
|
||||
hideOnNavigate : true
|
||||
});
|
||||
|
||||
vent.trigger(vent.Events.SeriesAdded, { series : self.model });
|
||||
});
|
||||
},
|
||||
|
||||
_rootFoldersUpdated : function() {
|
||||
this._configureTemplateHelpers();
|
||||
this.render();
|
||||
},
|
||||
|
||||
_getAddSeriesOptions : function() {
|
||||
var monitor = this.ui.monitor.val();
|
||||
var lastSeason = _.max(this.model.get('seasons'), 'seasonNumber');
|
||||
var firstSeason = _.min(_.reject(this.model.get('seasons'), { seasonNumber : 0 }), 'seasonNumber');
|
||||
|
||||
this.model.setSeasonPass(firstSeason.seasonNumber);
|
||||
|
||||
var options = {
|
||||
ignoreEpisodesWithFiles : false,
|
||||
ignoreEpisodesWithoutFiles : false
|
||||
};
|
||||
|
||||
if (monitor === 'all') {
|
||||
return options;
|
||||
}
|
||||
|
||||
else if (monitor === 'future') {
|
||||
options.ignoreEpisodesWithFiles = true;
|
||||
options.ignoreEpisodesWithoutFiles = true;
|
||||
}
|
||||
|
||||
else if (monitor === 'latest') {
|
||||
this.model.setSeasonPass(lastSeason.seasonNumber);
|
||||
}
|
||||
|
||||
else if (monitor === 'first') {
|
||||
this.model.setSeasonPass(lastSeason.seasonNumber + 1);
|
||||
this.model.setSeasonMonitored(firstSeason.seasonNumber);
|
||||
}
|
||||
|
||||
else if (monitor === 'missing') {
|
||||
options.ignoreEpisodesWithFiles = true;
|
||||
}
|
||||
|
||||
else if (monitor === 'existing') {
|
||||
options.ignoreEpisodesWithoutFiles = true;
|
||||
}
|
||||
|
||||
else if (monitor === 'none') {
|
||||
this.model.setSeasonPass(lastSeason.seasonNumber + 1);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
});
|
||||
|
||||
AsValidatedView.apply(view);
|
||||
|
||||
module.exports = view;
|
@ -1,111 +0,0 @@
|
||||
<div class="search-item {{#unless isExisting}}search-item-new{{/unless}}">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<a href="{{tvdbUrl}}" target="_blank">
|
||||
{{poster}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2 class="series-title">
|
||||
{{titleWithYear}}
|
||||
|
||||
<span class="labels">
|
||||
<span class="label label-default">{{network}}</span>
|
||||
{{#unless_eq status compare="continuing"}}
|
||||
<span class="label label-danger">Ended</span>
|
||||
{{/unless_eq}}
|
||||
</span>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row new-series-overview x-overview">
|
||||
<div class="col-md-12 overview-internal">
|
||||
{{overview}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
{{#unless existing}}
|
||||
{{#unless path}}
|
||||
<div class="form-group col-md-4">
|
||||
<label>Path</label>
|
||||
{{> RootFolderSelectionPartial rootFolders}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
<div class="form-group col-md-2">
|
||||
<label>Monitor <i class="icon-sonarr-form-info monitor-tooltip x-monitor-tooltip"></i></label>
|
||||
<select class="form-control col-md-2 x-monitor">
|
||||
<option value="all">All</option>
|
||||
<option value="future">Future</option>
|
||||
<option value="missing">Missing</option>
|
||||
<option value="existing">Existing</option>
|
||||
<option value="first">First Season</option>
|
||||
<option value="latest">Latest Season</option>
|
||||
<option value="none">None</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-2">
|
||||
<label>Profile</label>
|
||||
{{> ProfileSelectionPartial profiles}}
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-2">
|
||||
<label>Series Type</label>
|
||||
{{> SeriesTypeSelectionPartial}}
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-2">
|
||||
<label>Season Folders</label>
|
||||
|
||||
<div class="input-group">
|
||||
<label class="checkbox toggle well">
|
||||
<input type="checkbox" class="x-season-folder"/>
|
||||
<p>
|
||||
<span>Yes</span>
|
||||
<span>No</span>
|
||||
</p>
|
||||
<div class="btn btn-primary slide-button"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{{/unless}}
|
||||
</div>
|
||||
<div class="row">
|
||||
{{#unless existing}}
|
||||
{{#if title}}
|
||||
<div class="form-group col-md-2 col-md-offset-10">
|
||||
{{!--
|
||||
Uncomment if we need to add even more controls to add series
|
||||
<label style="visibility: hidden">Add</label>
|
||||
--}}
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-success add x-add" title="Add">
|
||||
<i class="icon-sonarr-add"></i>
|
||||
</button>
|
||||
|
||||
<button class="btn btn-success add x-add-search" title="Add and Search for missing episodes">
|
||||
<i class="icon-sonarr-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="col-md-2 col-md-offset-10" title="Series requires an English title">
|
||||
<button class="btn add-series disabled">
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class="col-md-2 col-md-offset-10">
|
||||
<a class="btn btn-default" href="{{route}}">
|
||||
Already Exists
|
||||
</a>
|
||||
</div>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,5 +0,0 @@
|
||||
<select class="form-control col-md-2 x-series-type" name="seriesType">
|
||||
<option value="standard">Standard</option>
|
||||
<option value="daily">Daily</option>
|
||||
<option value="anime">Anime</option>
|
||||
</select>
|
@ -1,13 +0,0 @@
|
||||
<select class="form-control col-md-2 starting-season x-starting-season">
|
||||
|
||||
|
||||
{{#each this}}
|
||||
{{#if_eq seasonNumber compare="0"}}
|
||||
<option value="{{seasonNumber}}">Specials</option>
|
||||
{{else}}
|
||||
<option value="{{seasonNumber}}">Season {{seasonNumber}}</option>
|
||||
{{/if_eq}}
|
||||
{{/each}}
|
||||
|
||||
<option value="5000000">None</option>
|
||||
</select>
|
@ -1,173 +0,0 @@
|
||||
@import "../Shared/Styles/card.less";
|
||||
@import "../Shared/Styles/clickable.less";
|
||||
|
||||
#add-series-screen {
|
||||
.existing-series {
|
||||
|
||||
.card();
|
||||
margin : 30px 0;
|
||||
|
||||
.unmapped-folder-path {
|
||||
padding: 20px;
|
||||
margin-left : 0;
|
||||
font-weight : 100;
|
||||
font-size : 25px;
|
||||
text-align : center;
|
||||
}
|
||||
|
||||
.new-series-loadmore {
|
||||
font-size : 30px;
|
||||
font-weight : 300;
|
||||
padding-top : 10px;
|
||||
padding-bottom : 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.new-series {
|
||||
.search-item {
|
||||
.card();
|
||||
margin : 40px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.add-series-search {
|
||||
margin-top : 20px;
|
||||
margin-bottom : 20px;
|
||||
}
|
||||
|
||||
.search-item {
|
||||
|
||||
padding-bottom : 20px;
|
||||
|
||||
.series-title {
|
||||
margin-top : 5px;
|
||||
|
||||
.labels {
|
||||
margin-left : 10px;
|
||||
|
||||
.label {
|
||||
font-size : 12px;
|
||||
vertical-align : middle;
|
||||
}
|
||||
}
|
||||
|
||||
.year {
|
||||
font-style : italic;
|
||||
color : #aaaaaa;
|
||||
}
|
||||
}
|
||||
|
||||
.new-series-overview {
|
||||
overflow : hidden;
|
||||
height : 103px;
|
||||
|
||||
.overview-internal {
|
||||
overflow : hidden;
|
||||
height : 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.series-poster {
|
||||
min-width : 138px;
|
||||
min-height : 203px;
|
||||
max-width : 138px;
|
||||
max-height : 203px;
|
||||
margin : 10px;
|
||||
}
|
||||
|
||||
a {
|
||||
color : #343434;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration : none;
|
||||
}
|
||||
|
||||
select {
|
||||
font-size : 14px;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
margin-top : 0;
|
||||
}
|
||||
|
||||
.add {
|
||||
i {
|
||||
&:before {
|
||||
color : #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.monitor-tooltip {
|
||||
margin-left : 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-folders {
|
||||
margin : 30px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hint {
|
||||
color : #999999;
|
||||
font-style : italic;
|
||||
}
|
||||
|
||||
.monitor-tooltip-contents {
|
||||
padding-bottom : 0;
|
||||
|
||||
dd {
|
||||
padding-bottom : 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
li.add-new {
|
||||
.clickable;
|
||||
|
||||
display: block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: normal;
|
||||
line-height: 20px;
|
||||
color: rgb(51, 51, 51);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
li.add-new:hover {
|
||||
text-decoration: none;
|
||||
color: rgb(255, 255, 255);
|
||||
background-color: rgb(0, 129, 194);
|
||||
}
|
||||
|
||||
.root-folders-modal {
|
||||
overflow : visible;
|
||||
|
||||
.root-folders-list {
|
||||
overflow-y : auto;
|
||||
max-height : 300px;
|
||||
|
||||
i {
|
||||
.clickable();
|
||||
}
|
||||
}
|
||||
|
||||
.validation-errors {
|
||||
display : none;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
.form-control {
|
||||
background-color : white;
|
||||
}
|
||||
}
|
||||
|
||||
.root-folders {
|
||||
margin-top : 20px;
|
||||
}
|
||||
|
||||
.recent-folder {
|
||||
.clickable();
|
||||
}
|
||||
}
|
@ -20,7 +20,6 @@
|
||||
@import "../Shared/FileBrowser/filebrowser";
|
||||
@import "badges";
|
||||
@import "../ManualImport/manualimport";
|
||||
@import "../SeasonPass/seasonpass";
|
||||
|
||||
.main-region {
|
||||
@media (min-width : @screen-lg-min) {
|
||||
|
@ -3,22 +3,14 @@ var AppLayout = require('./AppLayout');
|
||||
var Marionette = require('marionette');
|
||||
var ActivityLayout = require('./Activity/ActivityLayout');
|
||||
var SettingsLayout = require('./Settings/SettingsLayout');
|
||||
var AddSeriesLayout = require('./AddSeries/AddSeriesLayout');
|
||||
var AddMoviesLayout = require('./AddMovies/AddMoviesLayout');
|
||||
var WantedLayout = require('./Wanted/WantedLayout');
|
||||
var CalendarLayout = require('./Calendar/CalendarLayout');
|
||||
var ReleaseLayout = require('./Release/ReleaseLayout');
|
||||
var SystemLayout = require('./System/SystemLayout');
|
||||
var SeasonPassLayout = require('./SeasonPass/SeasonPassLayout');
|
||||
var SeriesEditorLayout = require('./Series/Editor/SeriesEditorLayout');
|
||||
var MovieEditorLayout = require('./Movies/Editor/MovieEditorLayout');
|
||||
|
||||
module.exports = NzbDroneController.extend({
|
||||
addSeries : function(action) {
|
||||
this.setTitle('Add Movie');
|
||||
this.showMainRegion(new AddSeriesLayout({ action : action }));
|
||||
},
|
||||
|
||||
addMovies : function(action, query) {
|
||||
this.setTitle("Add Movie");
|
||||
this.showMainRegion(new AddMoviesLayout({ action : action, query : query }));
|
||||
@ -54,16 +46,6 @@ module.exports = NzbDroneController.extend({
|
||||
this.showMainRegion(new SystemLayout({ action : action }));
|
||||
},
|
||||
|
||||
seasonPass : function() {
|
||||
this.setTitle('Season Pass');
|
||||
this.showMainRegion(new SeasonPassLayout());
|
||||
},
|
||||
|
||||
seriesEditor : function() {
|
||||
this.setTitle('Series Editor');
|
||||
this.showMainRegion(new SeriesEditorLayout());
|
||||
},
|
||||
|
||||
movieEditor : function() {
|
||||
this.setTitle('Movie Editor');
|
||||
this.showMainRegion(new MovieEditorLayout());
|
||||
|
@ -1,130 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
var SummaryLayout = require('./Summary/EpisodeSummaryLayout');
|
||||
var SearchLayout = require('./Search/EpisodeSearchLayout');
|
||||
var EpisodeHistoryLayout = require('./History/EpisodeHistoryLayout');
|
||||
var SeriesCollection = require('../Series/SeriesCollection');
|
||||
var Messenger = require('../Shared/Messenger');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
className : 'modal-lg',
|
||||
template : 'Episode/EpisodeDetailsLayoutTemplate',
|
||||
|
||||
regions : {
|
||||
summary : '#episode-summary',
|
||||
history : '#episode-history',
|
||||
search : '#episode-search'
|
||||
},
|
||||
|
||||
ui : {
|
||||
summary : '.x-episode-summary',
|
||||
history : '.x-episode-history',
|
||||
search : '.x-episode-search',
|
||||
monitored : '.x-episode-monitored'
|
||||
},
|
||||
|
||||
events : {
|
||||
|
||||
'click .x-episode-summary' : '_showSummary',
|
||||
'click .x-episode-history' : '_showHistory',
|
||||
'click .x-episode-search' : '_showSearch',
|
||||
'click .x-episode-monitored' : '_toggleMonitored'
|
||||
},
|
||||
|
||||
templateHelpers : {},
|
||||
|
||||
initialize : function(options) {
|
||||
this.templateHelpers.hideSeriesLink = options.hideSeriesLink;
|
||||
|
||||
this.series = SeriesCollection.get(this.model.get('seriesId'));
|
||||
this.templateHelpers.series = this.series.toJSON();
|
||||
this.openingTab = options.openingTab || 'summary';
|
||||
|
||||
this.listenTo(this.model, 'sync', this._setMonitoredState);
|
||||
},
|
||||
|
||||
onShow : function() {
|
||||
this.searchLayout = new SearchLayout({ model : this.model });
|
||||
|
||||
if (this.openingTab === 'search') {
|
||||
this.searchLayout.startManualSearch = true;
|
||||
this._showSearch();
|
||||
}
|
||||
|
||||
else {
|
||||
this._showSummary();
|
||||
}
|
||||
|
||||
this._setMonitoredState();
|
||||
|
||||
if (this.series.get('monitored')) {
|
||||
this.$el.removeClass('series-not-monitored');
|
||||
}
|
||||
|
||||
else {
|
||||
this.$el.addClass('series-not-monitored');
|
||||
}
|
||||
},
|
||||
|
||||
_showSummary : function(e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
this.ui.summary.tab('show');
|
||||
this.summary.show(new SummaryLayout({
|
||||
model : this.model,
|
||||
series : this.series
|
||||
}));
|
||||
},
|
||||
|
||||
_showHistory : function(e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
this.ui.history.tab('show');
|
||||
this.history.show(new EpisodeHistoryLayout({
|
||||
model : this.model,
|
||||
series : this.series
|
||||
}));
|
||||
},
|
||||
|
||||
_showSearch : function(e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
this.ui.search.tab('show');
|
||||
this.search.show(this.searchLayout);
|
||||
},
|
||||
|
||||
_toggleMonitored : function() {
|
||||
if (!this.series.get('monitored')) {
|
||||
|
||||
Messenger.show({
|
||||
message : 'Unable to change monitored state when series is not monitored',
|
||||
type : 'error'
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var name = 'monitored';
|
||||
this.model.set(name, !this.model.get(name), { silent : true });
|
||||
|
||||
this.ui.monitored.addClass('icon-sonarr-spinner fa-spin');
|
||||
this.model.save();
|
||||
},
|
||||
|
||||
_setMonitoredState : function() {
|
||||
this.ui.monitored.removeClass('fa-spin icon-sonarr-spinner');
|
||||
|
||||
if (this.model.get('monitored')) {
|
||||
this.ui.monitored.addClass('icon-sonarr-monitored');
|
||||
this.ui.monitored.removeClass('icon-sonarr-unmonitored');
|
||||
} else {
|
||||
this.ui.monitored.addClass('icon-sonarr-unmonitored');
|
||||
this.ui.monitored.removeClass('icon-sonarr-monitored');
|
||||
}
|
||||
}
|
||||
});
|
@ -1,35 +0,0 @@
|
||||
<div class="modal-content">
|
||||
<div class="episode-detail-modal">
|
||||
<div class="modal-header">
|
||||
<span class="hidden-series-title x-series-title">{{series.title}}</span>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
|
||||
<h3>
|
||||
<i class="icon-sonarr-monitored x-episode-monitored episode-monitored" title="Toggle monitored status" />
|
||||
{{series.title}} - {{EpisodeNumber}} - {{title}}
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ul class="nav nav-tabs" id="myTab">
|
||||
<li><a href="#episode-summary" class="x-episode-summary">Summary</a></li>
|
||||
<li><a href="#episode-history" class="x-episode-history">History</a></li>
|
||||
<li><a href="#episode-search" class="x-episode-search">Search</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane" id="episode-summary"/>
|
||||
<div class="tab-pane" id="episode-history"/>
|
||||
<div class="tab-pane" id="episode-search"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
{{#unless hideSeriesLink}}
|
||||
{{#with series}}
|
||||
<a href="{{route}}" class="btn btn-default pull-left" data-dismiss="modal">Go to Series</a>
|
||||
{{/with}}
|
||||
{{/unless}}
|
||||
|
||||
<button class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,35 +0,0 @@
|
||||
var $ = require('jquery');
|
||||
var vent = require('vent');
|
||||
var Marionette = require('marionette');
|
||||
var NzbDroneCell = require('../../Cells/NzbDroneCell');
|
||||
|
||||
module.exports = NzbDroneCell.extend({
|
||||
className : 'episode-actions-cell',
|
||||
|
||||
events : {
|
||||
'click .x-failed' : '_markAsFailed'
|
||||
},
|
||||
|
||||
render : function() {
|
||||
this.$el.empty();
|
||||
|
||||
if (this.model.get('eventType') === 'grabbed') {
|
||||
this.$el.html('<i class="icon-sonarr-delete x-failed" title="Mark download as failed"></i>');
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_markAsFailed : function() {
|
||||
var url = window.NzbDrone.ApiRoot + '/history/failed';
|
||||
var data = {
|
||||
id : this.model.get('id')
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url : url,
|
||||
type : 'POST',
|
||||
data : data
|
||||
});
|
||||
}
|
||||
});
|
@ -1,28 +0,0 @@
|
||||
var $ = require('jquery');
|
||||
var vent = require('vent');
|
||||
var Marionette = require('marionette');
|
||||
var NzbDroneCell = require('../../Cells/NzbDroneCell');
|
||||
var HistoryDetailsView = require('../../Activity/History/Details/HistoryDetailsView');
|
||||
require('bootstrap');
|
||||
|
||||
module.exports = NzbDroneCell.extend({
|
||||
className : 'episode-history-details-cell',
|
||||
|
||||
render : function() {
|
||||
this.$el.empty();
|
||||
this.$el.html('<i class="icon-sonarr-form-info"></i>');
|
||||
|
||||
var html = new HistoryDetailsView({ model : this.model }).render().$el;
|
||||
|
||||
this.$el.popover({
|
||||
content : html,
|
||||
html : true,
|
||||
trigger : 'hover',
|
||||
title : 'Details',
|
||||
placement : 'left',
|
||||
container : this.$el
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
@ -1,84 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
var Backgrid = require('backgrid');
|
||||
var HistoryCollection = require('../../Activity/History/HistoryCollection');
|
||||
var EventTypeCell = require('../../Cells/EventTypeCell');
|
||||
var QualityCell = require('../../Cells/QualityCell');
|
||||
var RelativeDateCell = require('../../Cells/RelativeDateCell');
|
||||
var EpisodeHistoryActionsCell = require('./EpisodeHistoryActionsCell');
|
||||
var EpisodeHistoryDetailsCell = require('./EpisodeHistoryDetailsCell');
|
||||
var NoHistoryView = require('./NoHistoryView');
|
||||
var LoadingView = require('../../Shared/LoadingView');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'Episode/History/EpisodeHistoryLayoutTemplate',
|
||||
|
||||
regions : {
|
||||
historyTable : '.history-table'
|
||||
},
|
||||
|
||||
columns : [
|
||||
{
|
||||
name : 'eventType',
|
||||
label : '',
|
||||
cell : EventTypeCell,
|
||||
cellValue : 'this'
|
||||
},
|
||||
{
|
||||
name : 'sourceTitle',
|
||||
label : 'Source Title',
|
||||
cell : 'string'
|
||||
},
|
||||
{
|
||||
name : 'quality',
|
||||
label : 'Quality',
|
||||
cell : QualityCell
|
||||
},
|
||||
{
|
||||
name : 'date',
|
||||
label : 'Date',
|
||||
cell : RelativeDateCell
|
||||
},
|
||||
{
|
||||
name : 'this',
|
||||
label : '',
|
||||
cell : EpisodeHistoryDetailsCell,
|
||||
sortable : false
|
||||
},
|
||||
{
|
||||
name : 'this',
|
||||
label : '',
|
||||
cell : EpisodeHistoryActionsCell,
|
||||
sortable : false
|
||||
}
|
||||
],
|
||||
|
||||
initialize : function(options) {
|
||||
this.model = options.model;
|
||||
this.series = options.series;
|
||||
|
||||
this.collection = new HistoryCollection({
|
||||
episodeId : this.model.id,
|
||||
tableName : 'episodeHistory'
|
||||
});
|
||||
this.collection.fetch();
|
||||
this.listenTo(this.collection, 'sync', this._showTable);
|
||||
},
|
||||
|
||||
onRender : function() {
|
||||
this.historyTable.show(new LoadingView());
|
||||
},
|
||||
|
||||
_showTable : function() {
|
||||
if (this.collection.any()) {
|
||||
this.historyTable.show(new Backgrid.Grid({
|
||||
collection : this.collection,
|
||||
columns : this.columns,
|
||||
className : 'table table-hover table-condensed'
|
||||
}));
|
||||
}
|
||||
|
||||
else {
|
||||
this.historyTable.show(new NoHistoryView());
|
||||
}
|
||||
}
|
||||
});
|
@ -1 +0,0 @@
|
||||
<div class="history-table table-responsive"></div>
|
@ -1,5 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.ItemView.extend({
|
||||
template : 'Episode/History/NoHistoryViewTemplate'
|
||||
});
|
@ -1,3 +0,0 @@
|
||||
<p class="text-warning">
|
||||
No history for this episode.
|
||||
</p>
|
@ -1,5 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.ItemView.extend({
|
||||
template : 'Episode/Search/ButtonsViewTemplate'
|
||||
});
|
@ -1,4 +0,0 @@
|
||||
<div class="search-buttons">
|
||||
<button class="btn btn-lg btn-block x-search-auto"><i class="icon-sonarr-search-automatic"/> Automatic Search</button>
|
||||
<button class="btn btn-lg btn-block btn-primary x-search-manual"><i class="icon-sonarr-search-manual"/> Manual Search</button>
|
||||
</div>
|
@ -1,82 +0,0 @@
|
||||
var vent = require('vent');
|
||||
var Marionette = require('marionette');
|
||||
var ButtonsView = require('./ButtonsView');
|
||||
var ManualSearchLayout = require('./ManualLayout');
|
||||
var ReleaseCollection = require('../../Release/ReleaseCollection');
|
||||
var CommandController = require('../../Commands/CommandController');
|
||||
var LoadingView = require('../../Shared/LoadingView');
|
||||
var NoResultsView = require('./NoResultsView');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'Episode/Search/EpisodeSearchLayoutTemplate',
|
||||
|
||||
regions : {
|
||||
main : '#episode-search-region'
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-search-auto' : '_searchAuto',
|
||||
'click .x-search-manual' : '_searchManual',
|
||||
'click .x-search-back' : '_showButtons'
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
this.mainView = new ButtonsView();
|
||||
this.releaseCollection = new ReleaseCollection();
|
||||
|
||||
this.listenTo(this.releaseCollection, 'sync', this._showSearchResults);
|
||||
},
|
||||
|
||||
onShow : function() {
|
||||
if (this.startManualSearch) {
|
||||
this._searchManual();
|
||||
}
|
||||
|
||||
else {
|
||||
this._showMainView();
|
||||
}
|
||||
},
|
||||
|
||||
_searchAuto : function(e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
CommandController.Execute('episodeSearch', {
|
||||
episodeIds : [this.model.get('id')]
|
||||
});
|
||||
|
||||
vent.trigger(vent.Commands.CloseModalCommand);
|
||||
},
|
||||
|
||||
_searchManual : function(e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
this.mainView = new LoadingView();
|
||||
this._showMainView();
|
||||
this.releaseCollection.fetchEpisodeReleases(this.model.id);
|
||||
},
|
||||
|
||||
_showMainView : function() {
|
||||
this.main.show(this.mainView);
|
||||
},
|
||||
|
||||
_showButtons : function() {
|
||||
this.mainView = new ButtonsView();
|
||||
this._showMainView();
|
||||
},
|
||||
|
||||
_showSearchResults : function() {
|
||||
if (this.releaseCollection.length === 0) {
|
||||
this.mainView = new NoResultsView();
|
||||
}
|
||||
|
||||
else {
|
||||
this.mainView = new ManualSearchLayout({ collection : this.releaseCollection });
|
||||
}
|
||||
|
||||
this._showMainView();
|
||||
}
|
||||
});
|
@ -1 +0,0 @@
|
||||
<div id="episode-search-region"></div>
|
@ -1,93 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
var Backgrid = require('backgrid');
|
||||
var ReleaseTitleCell = require('../../Cells/ReleaseTitleCell');
|
||||
var FileSizeCell = require('../../Cells/FileSizeCell');
|
||||
var QualityCell = require('../../Cells/QualityCell');
|
||||
var ApprovalStatusCell = require('../../Cells/ApprovalStatusCell');
|
||||
var DownloadReportCell = require('../../Release/DownloadReportCell');
|
||||
var AgeCell = require('../../Release/AgeCell');
|
||||
var ProtocolCell = require('../../Release/ProtocolCell');
|
||||
var PeersCell = require('../../Release/PeersCell');
|
||||
var EditionCell = require('../../Cells/EditionCell');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'Episode/Search/ManualLayoutTemplate',
|
||||
|
||||
regions : {
|
||||
grid : '#episode-release-grid'
|
||||
},
|
||||
|
||||
columns : [
|
||||
{
|
||||
name : 'protocol',
|
||||
label : 'Source',
|
||||
cell : ProtocolCell
|
||||
},
|
||||
{
|
||||
name : 'age',
|
||||
label : 'Age',
|
||||
cell : AgeCell
|
||||
},
|
||||
{
|
||||
name : 'title',
|
||||
label : 'Title',
|
||||
cell : ReleaseTitleCell
|
||||
},
|
||||
{
|
||||
name : 'edition',
|
||||
label : 'Edition',
|
||||
cell : EditionCell,
|
||||
title : "Edition"
|
||||
},
|
||||
{
|
||||
name : 'indexer',
|
||||
label : 'Indexer',
|
||||
cell : Backgrid.StringCell
|
||||
},
|
||||
{
|
||||
name : 'size',
|
||||
label : 'Size',
|
||||
cell : FileSizeCell
|
||||
},
|
||||
{
|
||||
name : 'seeders',
|
||||
label : 'Peers',
|
||||
cell : PeersCell
|
||||
},
|
||||
{
|
||||
name : 'quality',
|
||||
label : 'Quality',
|
||||
cell : QualityCell
|
||||
},
|
||||
{
|
||||
name : 'rejections',
|
||||
label : '<i class="icon-sonarr-header-rejections" />',
|
||||
tooltip : 'Rejections',
|
||||
cell : ApprovalStatusCell,
|
||||
sortable : true,
|
||||
sortType : 'fixed',
|
||||
direction : 'ascending',
|
||||
title : 'Release Rejected'
|
||||
},
|
||||
{
|
||||
name : 'download',
|
||||
label : '<i class="icon-sonarr-download" />',
|
||||
tooltip : 'Auto-Search Prioritization',
|
||||
cell : DownloadReportCell,
|
||||
sortable : true,
|
||||
sortType : 'fixed',
|
||||
direction : 'ascending'
|
||||
}
|
||||
],
|
||||
|
||||
onShow : function() {
|
||||
if (!this.isClosed) {
|
||||
this.grid.show(new Backgrid.Grid({
|
||||
row : Backgrid.Row,
|
||||
columns : this.columns,
|
||||
collection : this.collection,
|
||||
className : 'table table-hover'
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
@ -1,2 +0,0 @@
|
||||
<div id="episode-release-grid" class="table-responsive"></div>
|
||||
<button class="btn x-search-back">Back</button>
|
@ -1,5 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.ItemView.extend({
|
||||
template : 'Episode/Search/NoResultsViewTemplate'
|
||||
});
|
@ -1 +0,0 @@
|
||||
<div>No results found</div>
|
@ -1,119 +0,0 @@
|
||||
var reqres = require('../../reqres');
|
||||
var Marionette = require('marionette');
|
||||
var Backgrid = require('backgrid');
|
||||
var EpisodeFileModel = require('../../Series/EpisodeFileModel');
|
||||
var EpisodeFileCollection = require('../../Series/EpisodeFileCollection');
|
||||
var FileSizeCell = require('../../Cells/FileSizeCell');
|
||||
var QualityCell = require('../../Cells/QualityCell');
|
||||
var DeleteEpisodeFileCell = require('../../Cells/DeleteEpisodeFileCell');
|
||||
var NoFileView = require('./NoFileView');
|
||||
var LoadingView = require('../../Shared/LoadingView');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'Episode/Summary/EpisodeSummaryLayoutTemplate',
|
||||
|
||||
regions : {
|
||||
overview : '.episode-overview',
|
||||
activity : '.episode-file-info'
|
||||
},
|
||||
|
||||
columns : [
|
||||
{
|
||||
name : 'path',
|
||||
label : 'Path',
|
||||
cell : 'string',
|
||||
sortable : false
|
||||
},
|
||||
{
|
||||
name : 'size',
|
||||
label : 'Size',
|
||||
cell : FileSizeCell,
|
||||
sortable : false
|
||||
},
|
||||
{
|
||||
name : 'quality',
|
||||
label : 'Quality',
|
||||
cell : QualityCell,
|
||||
sortable : false,
|
||||
editable : true
|
||||
},
|
||||
{
|
||||
name : 'this',
|
||||
label : '',
|
||||
cell : DeleteEpisodeFileCell,
|
||||
sortable : false
|
||||
}
|
||||
],
|
||||
|
||||
templateHelpers : {},
|
||||
|
||||
initialize : function(options) {
|
||||
if (!this.model.series) {
|
||||
this.templateHelpers.series = options.series.toJSON();
|
||||
}
|
||||
},
|
||||
|
||||
onShow : function() {
|
||||
if (this.model.get('hasFile')) {
|
||||
var episodeFileId = this.model.get('episodeFileId');
|
||||
|
||||
if (reqres.hasHandler(reqres.Requests.GetEpisodeFileById)) {
|
||||
var episodeFile = reqres.request(reqres.Requests.GetEpisodeFileById, episodeFileId);
|
||||
this.episodeFileCollection = new EpisodeFileCollection(episodeFile, { seriesId : this.model.get('seriesId') });
|
||||
this.listenTo(episodeFile, 'destroy', this._episodeFileDeleted);
|
||||
|
||||
this._showTable();
|
||||
}
|
||||
|
||||
else {
|
||||
this.activity.show(new LoadingView());
|
||||
|
||||
var self = this;
|
||||
var newEpisodeFile = new EpisodeFileModel({ id : episodeFileId });
|
||||
this.episodeFileCollection = new EpisodeFileCollection(newEpisodeFile, { seriesId : this.model.get('seriesId') });
|
||||
var promise = newEpisodeFile.fetch();
|
||||
this.listenTo(newEpisodeFile, 'destroy', this._episodeFileDeleted);
|
||||
|
||||
promise.done(function() {
|
||||
self._showTable();
|
||||
});
|
||||
}
|
||||
|
||||
this.listenTo(this.episodeFileCollection, 'add remove', this._collectionChanged);
|
||||
}
|
||||
|
||||
else {
|
||||
this._showNoFileView();
|
||||
}
|
||||
},
|
||||
|
||||
_showTable : function() {
|
||||
this.activity.show(new Backgrid.Grid({
|
||||
collection : this.episodeFileCollection,
|
||||
columns : this.columns,
|
||||
className : 'table table-bordered',
|
||||
emptyText : 'Nothing to see here!'
|
||||
}));
|
||||
},
|
||||
|
||||
_showNoFileView : function() {
|
||||
this.activity.show(new NoFileView());
|
||||
},
|
||||
|
||||
_collectionChanged : function() {
|
||||
if (!this.episodeFileCollection.any()) {
|
||||
this._showNoFileView();
|
||||
}
|
||||
|
||||
else {
|
||||
this._showTable();
|
||||
}
|
||||
},
|
||||
|
||||
_episodeFileDeleted : function() {
|
||||
this.model.set({
|
||||
episodeFileId : 0,
|
||||
hasFile : false
|
||||
});
|
||||
}
|
||||
});
|
@ -1,14 +0,0 @@
|
||||
<div class="episode-info">
|
||||
{{#with series}}
|
||||
{{profile profileId}}
|
||||
<span class="label label-info">{{network}}</span>
|
||||
{{/with}}
|
||||
<span class="label label-info">{{StartTime airDateUtc}}</span>
|
||||
<span class="label label-info">{{RelativeDate airDateUtc}}</span>
|
||||
</div>
|
||||
|
||||
<div class="episode-overview">
|
||||
{{overview}}
|
||||
</div>
|
||||
|
||||
<div class="episode-file-info"></div>
|
@ -1,5 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.ItemView.extend({
|
||||
template : 'Episode/Summary/NoFileViewTemplate'
|
||||
});
|
@ -1,3 +0,0 @@
|
||||
<p class="text-warning">
|
||||
No file available for this episode.
|
||||
</p>
|
@ -1,5 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.CompositeView.extend({
|
||||
template : 'EpisodeFile/Editor/EmptyViewTemplate'
|
||||
});
|
@ -1,5 +0,0 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
No episode files
|
||||
</div>
|
||||
</div>
|
@ -1,200 +0,0 @@
|
||||
var _ = require('underscore');
|
||||
var reqres = require('../../reqres');
|
||||
var Marionette = require('marionette');
|
||||
var Backgrid = require('backgrid');
|
||||
var FormatHelpers = require('../../Shared/FormatHelpers');
|
||||
var SelectAllCell = require('../../Cells/SelectAllCell');
|
||||
var EpisodeNumberCell = require('../../Series/Details/EpisodeNumberCell');
|
||||
var SeasonEpisodeNumberCell = require('../../Cells/EpisodeNumberCell');
|
||||
var EpisodeFilePathCell = require('../../Cells/EpisodeFilePathCell');
|
||||
var EpisodeStatusCell = require('../../Cells/EpisodeStatusCell');
|
||||
var RelativeDateCell = require('../../Cells/RelativeDateCell');
|
||||
var EpisodeCollection = require('../../Series/EpisodeCollection');
|
||||
var ProfileSchemaCollection = require('../../Settings/Profile/ProfileSchemaCollection');
|
||||
var QualitySelectView = require('./QualitySelectView');
|
||||
var EmptyView = require('./EmptyView');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
className : 'modal-lg',
|
||||
template : 'EpisodeFile/Editor/EpisodeFileEditorLayoutTemplate',
|
||||
|
||||
regions : {
|
||||
episodeGrid : '.x-episode-list',
|
||||
quality : '.x-quality'
|
||||
},
|
||||
|
||||
ui : {
|
||||
seasonMonitored : '.x-season-monitored'
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-season-monitored' : '_seasonMonitored',
|
||||
'click .x-delete-files' : '_deleteFiles'
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
if (!options.series) {
|
||||
throw 'series is required';
|
||||
}
|
||||
|
||||
if (!options.episodeCollection) {
|
||||
throw 'episodeCollection is required';
|
||||
}
|
||||
|
||||
var filtered = options.episodeCollection.filter(function(episode) {
|
||||
return episode.get('episodeFileId') > 0;
|
||||
});
|
||||
|
||||
this.series = options.series;
|
||||
this.episodeCollection = options.episodeCollection;
|
||||
this.filteredEpisodes = new EpisodeCollection(filtered);
|
||||
|
||||
this.templateHelpers = {};
|
||||
this.templateHelpers.series = this.series.toJSON();
|
||||
|
||||
this._getColumns();
|
||||
},
|
||||
|
||||
onRender : function() {
|
||||
this._getQualities();
|
||||
this._showEpisodes();
|
||||
},
|
||||
|
||||
_getColumns : function () {
|
||||
var episodeCell = {};
|
||||
|
||||
if (this.model) {
|
||||
episodeCell.name = 'episodeNumber';
|
||||
episodeCell.label = '#';
|
||||
episodeCell.cell = EpisodeNumberCell;
|
||||
}
|
||||
|
||||
else {
|
||||
episodeCell.name = 'seasonEpisode';
|
||||
episodeCell.cellValue = 'this';
|
||||
episodeCell.label = 'Episode';
|
||||
episodeCell.cell = SeasonEpisodeNumberCell;
|
||||
episodeCell.sortValue = this._seasonEpisodeSorter;
|
||||
}
|
||||
|
||||
this.columns = [
|
||||
{
|
||||
name : '',
|
||||
cell : SelectAllCell,
|
||||
headerCell : 'select-all',
|
||||
sortable : false
|
||||
},
|
||||
episodeCell,
|
||||
{
|
||||
name : 'episodeNumber',
|
||||
label : 'Relative Path',
|
||||
cell : EpisodeFilePathCell,
|
||||
sortable : false
|
||||
},
|
||||
{
|
||||
name : 'airDateUtc',
|
||||
label : 'Air Date',
|
||||
cell : RelativeDateCell
|
||||
},
|
||||
{
|
||||
name : 'status',
|
||||
label : 'Quality',
|
||||
cell : EpisodeStatusCell,
|
||||
sortable : false
|
||||
}
|
||||
];
|
||||
},
|
||||
|
||||
_showEpisodes : function() {
|
||||
if (this.filteredEpisodes.length === 0) {
|
||||
this.episodeGrid.show(new EmptyView());
|
||||
return;
|
||||
}
|
||||
|
||||
this._setInitialSort();
|
||||
|
||||
this.episodeGridView = new Backgrid.Grid({
|
||||
columns : this.columns,
|
||||
collection : this.filteredEpisodes,
|
||||
className : 'table table-hover season-grid'
|
||||
});
|
||||
|
||||
this.episodeGrid.show(this.episodeGridView);
|
||||
},
|
||||
|
||||
_setInitialSort : function () {
|
||||
if (!this.model) {
|
||||
this.filteredEpisodes.setSorting('seasonEpisode', 1, { sortValue: this._seasonEpisodeSorter });
|
||||
this.filteredEpisodes.fullCollection.sort();
|
||||
}
|
||||
},
|
||||
|
||||
_getQualities : function() {
|
||||
var self = this;
|
||||
|
||||
var profileSchemaCollection = new ProfileSchemaCollection();
|
||||
var promise = profileSchemaCollection.fetch();
|
||||
|
||||
promise.done(function() {
|
||||
var profile = profileSchemaCollection.first();
|
||||
|
||||
self.qualitySelectView = new QualitySelectView({ qualities: _.map(profile.get('items'), 'quality') });
|
||||
self.listenTo(self.qualitySelectView, 'seasonedit:quality', self._changeQuality);
|
||||
|
||||
self.quality.show(self.qualitySelectView);
|
||||
});
|
||||
},
|
||||
|
||||
_changeQuality : function(options) {
|
||||
var newQuality = {
|
||||
quality : options.selected,
|
||||
revision : {
|
||||
version : 1,
|
||||
real : 0
|
||||
}
|
||||
};
|
||||
|
||||
var selected = this._getSelectedEpisodeFileIds();
|
||||
|
||||
_.each(selected, function(episodeFileId) {
|
||||
if (reqres.hasHandler(reqres.Requests.GetEpisodeFileById)) {
|
||||
var episodeFile = reqres.request(reqres.Requests.GetEpisodeFileById, episodeFileId);
|
||||
episodeFile.set('quality', newQuality);
|
||||
episodeFile.save();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_deleteFiles : function() {
|
||||
if (!window.confirm('Are you sure you want to delete the episode files for the selected episodes?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var selected = this._getSelectedEpisodeFileIds();
|
||||
|
||||
_.each(selected, function(episodeFileId) {
|
||||
if (reqres.hasHandler(reqres.Requests.GetEpisodeFileById)) {
|
||||
var episodeFile = reqres.request(reqres.Requests.GetEpisodeFileById, episodeFileId);
|
||||
|
||||
episodeFile.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
_.each(this.episodeGridView.getSelectedModels(), function(episode) {
|
||||
this.episodeGridView.removeRow(episode);
|
||||
}, this);
|
||||
},
|
||||
|
||||
_getSelectedEpisodeFileIds: function () {
|
||||
return _.uniq(_.map(this.episodeGridView.getSelectedModels(), function (episode) {
|
||||
return episode.get('episodeFileId');
|
||||
}));
|
||||
},
|
||||
|
||||
_seasonEpisodeSorter : function (model, attr) {
|
||||
var seasonNumber = FormatHelpers.pad(model.get('seasonNumber'), 4, 0);
|
||||
var episodeNumber = FormatHelpers.pad(model.get('episodeNumber'), 4, 0);
|
||||
|
||||
return seasonNumber + episodeNumber;
|
||||
}
|
||||
});
|
@ -1,28 +0,0 @@
|
||||
<div class="modal-content">
|
||||
<div class="edit-season-modal">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
|
||||
<h3>
|
||||
{{#if seasonNumber}}
|
||||
{{#if_eq seasonNumber compare="0"}}
|
||||
{{series.title}} - Specials
|
||||
{{else}}
|
||||
{{series.title}} - Season {{seasonNumber}}
|
||||
{{/if_eq}}
|
||||
{{else}}
|
||||
{{series.title}}
|
||||
{{/if}}
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="x-episode-list"></div>
|
||||
<div class="x-quality"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-danger x-delete-files">Delete Files</button>
|
||||
<button class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,35 +0,0 @@
|
||||
var _ = require('underscore');
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.ItemView.extend({
|
||||
template : 'EpisodeFile/Editor/QualitySelectViewTemplate',
|
||||
|
||||
ui : {
|
||||
select : '.x-select'
|
||||
},
|
||||
|
||||
events : {
|
||||
'change .x-select' : '_changeSelect'
|
||||
},
|
||||
|
||||
initialize : function (options) {
|
||||
this.qualities = options.qualities;
|
||||
|
||||
this.templateHelpers = {
|
||||
qualities : this.qualities
|
||||
};
|
||||
},
|
||||
|
||||
_changeSelect : function () {
|
||||
var value = this.ui.select.val();
|
||||
|
||||
if (value === 'choose') {
|
||||
return;
|
||||
}
|
||||
|
||||
var quality = _.find(this.qualities, { 'id': parseInt(value) });
|
||||
|
||||
this.trigger('seasonedit:quality', { selected : quality });
|
||||
this.ui.select.val('choose');
|
||||
}
|
||||
});
|
@ -1,10 +0,0 @@
|
||||
<div class="row">
|
||||
<div class="form-group col-md-3 col-md-offset-9">
|
||||
<select class="form-control x-select">
|
||||
<option value="choose">Select quality</option>
|
||||
{{#eachReverse qualities}}
|
||||
<option value="{{id}}">{{name}}</option>
|
||||
{{/eachReverse}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
@ -1,46 +0,0 @@
|
||||
var _ = require('underscore');
|
||||
var vent = require('../../vent');
|
||||
var NzbDroneCell = require('../../Cells/NzbDroneCell');
|
||||
var SelectEpisodeLayout = require('../Episode/SelectEpisodeLayout');
|
||||
|
||||
module.exports = NzbDroneCell.extend({
|
||||
className : 'episodes-cell',
|
||||
|
||||
events : {
|
||||
'click' : '_onClick'
|
||||
},
|
||||
|
||||
render : function() {
|
||||
this.$el.empty();
|
||||
|
||||
var episodes = this.model.get('episodes');
|
||||
|
||||
if (episodes)
|
||||
{
|
||||
var episodeNumbers = _.map(episodes, 'episodeNumber');
|
||||
|
||||
this.$el.html(episodeNumbers.join(', '));
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_onClick : function () {
|
||||
var series = this.model.get('series');
|
||||
var seasonNumber = this.model.get('seasonNumber');
|
||||
|
||||
if (series === undefined || seasonNumber === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
var view = new SelectEpisodeLayout({ series: series, seasonNumber: seasonNumber });
|
||||
|
||||
this.listenTo(view, 'manualimport:selected:episodes', this._setEpisodes);
|
||||
|
||||
vent.trigger(vent.Commands.OpenModal2Command, view);
|
||||
},
|
||||
|
||||
_setEpisodes : function (e) {
|
||||
this.model.set('episodes', e.episodes);
|
||||
}
|
||||
});
|
@ -1,47 +0,0 @@
|
||||
var vent = require('../../vent');
|
||||
var NzbDroneCell = require('../../Cells/NzbDroneCell');
|
||||
var SelectSeasonLayout = require('../Season/SelectSeasonLayout');
|
||||
|
||||
module.exports = NzbDroneCell.extend({
|
||||
className : 'season-cell',
|
||||
|
||||
events : {
|
||||
'click' : '_onClick'
|
||||
},
|
||||
|
||||
render : function() {
|
||||
this.$el.empty();
|
||||
|
||||
if (this.model.has('seasonNumber')) {
|
||||
this.$el.html(this.model.get('seasonNumber'));
|
||||
}
|
||||
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
},
|
||||
|
||||
_onClick : function () {
|
||||
var series = this.model.get('series');
|
||||
|
||||
if (!series) {
|
||||
return;
|
||||
}
|
||||
|
||||
var view = new SelectSeasonLayout({ seasons: series.seasons });
|
||||
|
||||
this.listenTo(view, 'manualimport:selected:season', this._setSeason);
|
||||
|
||||
vent.trigger(vent.Commands.OpenModal2Command, view);
|
||||
},
|
||||
|
||||
_setSeason : function (e) {
|
||||
if (this.model.has('seasonNumber') && e.seasonNumber === this.model.get('seasonNumber')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.model.set({
|
||||
seasonNumber : e.seasonNumber,
|
||||
episodes : []
|
||||
});
|
||||
}
|
||||
});
|
@ -1,45 +0,0 @@
|
||||
var vent = require('../../vent');
|
||||
var NzbDroneCell = require('../../Cells/NzbDroneCell');
|
||||
var SelectSeriesLayout = require('../Series/SelectSeriesLayout');
|
||||
|
||||
module.exports = NzbDroneCell.extend({
|
||||
className : 'series-title-cell editable',
|
||||
|
||||
events : {
|
||||
'click' : '_onClick'
|
||||
},
|
||||
|
||||
render : function() {
|
||||
this.$el.empty();
|
||||
|
||||
var series = this.model.get('series');
|
||||
|
||||
if (series)
|
||||
{
|
||||
this.$el.html(series.title);
|
||||
}
|
||||
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
},
|
||||
|
||||
_onClick : function () {
|
||||
var view = new SelectSeriesLayout();
|
||||
|
||||
this.listenTo(view, 'manualimport:selected:series', this._setSeries);
|
||||
|
||||
vent.trigger(vent.Commands.OpenModal2Command, view);
|
||||
},
|
||||
|
||||
_setSeries : function (e) {
|
||||
if (this.model.has('series') && e.model.id === this.model.get('series').id) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.model.set({
|
||||
series : e.model.toJSON(),
|
||||
seasonNumber : undefined,
|
||||
episodes : []
|
||||
});
|
||||
}
|
||||
});
|
@ -1,81 +0,0 @@
|
||||
var _ = require('underscore');
|
||||
var vent = require('vent');
|
||||
var Marionette = require('marionette');
|
||||
var Backgrid = require('backgrid');
|
||||
var EpisodeCollection = require('../../Series/EpisodeCollection');
|
||||
var LoadingView = require('../../Shared/LoadingView');
|
||||
var SelectAllCell = require('../../Cells/SelectAllCell');
|
||||
var EpisodeNumberCell = require('../../Series/Details/EpisodeNumberCell');
|
||||
var RelativeDateCell = require('../../Cells/RelativeDateCell');
|
||||
var SelectEpisodeRow = require('./SelectEpisodeRow');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'ManualImport/Episode/SelectEpisodeLayoutTemplate',
|
||||
|
||||
regions : {
|
||||
episodes : '.x-episodes'
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-select' : '_selectEpisodes'
|
||||
},
|
||||
|
||||
columns : [
|
||||
{
|
||||
name : '',
|
||||
cell : SelectAllCell,
|
||||
headerCell : 'select-all',
|
||||
sortable : false
|
||||
},
|
||||
{
|
||||
name : 'episodeNumber',
|
||||
label : '#',
|
||||
cell : EpisodeNumberCell
|
||||
},
|
||||
{
|
||||
name : 'title',
|
||||
label : 'Title',
|
||||
hideSeriesLink : true,
|
||||
cell : 'string',
|
||||
sortable : false
|
||||
},
|
||||
{
|
||||
name : 'airDateUtc',
|
||||
label : 'Air Date',
|
||||
cell : RelativeDateCell
|
||||
}
|
||||
],
|
||||
|
||||
initialize : function(options) {
|
||||
this.series = options.series;
|
||||
this.seasonNumber = options.seasonNumber;
|
||||
},
|
||||
|
||||
onRender : function() {
|
||||
this.episodes.show(new LoadingView());
|
||||
|
||||
this.episodeCollection = new EpisodeCollection({ seriesId : this.series.id });
|
||||
this.episodeCollection.fetch();
|
||||
|
||||
this.listenToOnce(this.episodeCollection, 'sync', function () {
|
||||
|
||||
this.episodeView = new Backgrid.Grid({
|
||||
columns : this.columns,
|
||||
collection : this.episodeCollection.bySeason(this.seasonNumber),
|
||||
className : 'table table-hover season-grid',
|
||||
row : SelectEpisodeRow
|
||||
});
|
||||
|
||||
this.episodes.show(this.episodeView);
|
||||
});
|
||||
},
|
||||
|
||||
_selectEpisodes : function () {
|
||||
var episodes = _.map(this.episodeView.getSelectedModels(), function (episode) {
|
||||
return episode.toJSON();
|
||||
});
|
||||
|
||||
this.trigger('manualimport:selected:episodes', { episodes: episodes });
|
||||
vent.trigger(vent.Commands.CloseModal2Command);
|
||||
}
|
||||
});
|
@ -1,21 +0,0 @@
|
||||
<div class="modal-content">
|
||||
<div class="manual-import-modal">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
|
||||
<h3>
|
||||
Manual Import - Select Episode(s)
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12 x-episodes"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
<button class="btn btn-success x-select" data-dismiss="modal">Select Episodes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,20 +0,0 @@
|
||||
var Backgrid = require('backgrid');
|
||||
|
||||
module.exports = Backgrid.Row.extend({
|
||||
className : 'select-episode-row',
|
||||
|
||||
events : {
|
||||
'click' : '_toggle'
|
||||
},
|
||||
|
||||
_toggle : function(e) {
|
||||
|
||||
if (e.target.type === 'checkbox') {
|
||||
return;
|
||||
}
|
||||
|
||||
var checked = this.$el.find('.select-row-cell :checkbox').prop('checked');
|
||||
|
||||
this.model.trigger('backgrid:select', this.model, !checked);
|
||||
}
|
||||
});
|
@ -9,9 +9,6 @@ var LoadingView = require('../Shared/LoadingView');
|
||||
var ManualImportRow = require('./ManualImportRow');
|
||||
var SelectAllCell = require('../Cells/SelectAllCell');
|
||||
var PathCell = require('./Cells/PathCell');
|
||||
var SeriesCell = require('./Cells/SeriesCell');
|
||||
var SeasonCell = require('./Cells/SeasonCell');
|
||||
var EpisodesCell = require('./Cells/EpisodesCell');
|
||||
var QualityCell = require('./Cells/QualityCell');
|
||||
var FileSizeCell = require('../Cells/FileSizeCell');
|
||||
var ApprovalStatusCell = require('../Cells/ApprovalStatusCell');
|
||||
@ -55,24 +52,6 @@ module.exports = Marionette.Layout.extend({
|
||||
cell : MovieCell,
|
||||
sortable : true
|
||||
},
|
||||
// {
|
||||
// name : 'series',
|
||||
// label : 'Series',
|
||||
// cell : SeriesCell,
|
||||
// sortable : true
|
||||
// },
|
||||
// {
|
||||
// name : 'seasonNumber',
|
||||
// label : 'Season',
|
||||
// cell : SeasonCell,
|
||||
// sortable : true
|
||||
// },
|
||||
// {
|
||||
// name : 'episodes',
|
||||
// label : 'Episode(s)',
|
||||
// cell : EpisodesCell,
|
||||
// sortable : false
|
||||
// },
|
||||
{
|
||||
name : 'quality',
|
||||
label : 'Quality',
|
||||
@ -190,30 +169,6 @@ module.exports = Marionette.Layout.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
// if (_.any(selected, function (model) {
|
||||
// return !model.has('series');
|
||||
// })) {
|
||||
|
||||
// this._showErrorMessage('Series must be chosen for each selected file');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (_.any(selected, function (model) {
|
||||
// return !model.has('seasonNumber');
|
||||
// })) {
|
||||
|
||||
// this._showErrorMessage('Season must be chosen for each selected file');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (_.any(selected, function (model) {
|
||||
// return !model.has('episodes') || model.get('episodes').length === 0;
|
||||
// })) {
|
||||
|
||||
// this._showErrorMessage('One or more episodes must be chosen for each selected file');
|
||||
// return;
|
||||
// }
|
||||
|
||||
var importMode = this.ui.importMode.val();
|
||||
|
||||
CommandController.Execute('manualImport', {
|
||||
@ -222,8 +177,6 @@ module.exports = Marionette.Layout.extend({
|
||||
return {
|
||||
path : file.get('path'),
|
||||
movieId : file.get('movie').id,
|
||||
// seriesId : file.get('series').id,
|
||||
// episodeIds : _.map(file.get('episodes'), 'id'),
|
||||
quality : file.get('quality'),
|
||||
downloadId : file.get('downloadId')
|
||||
};
|
||||
|
@ -34,6 +34,5 @@ module.exports = Backgrid.Row.extend({
|
||||
|
||||
_setClasses : function () {
|
||||
this.$el.toggleClass('has-movie', this.model.has('movie'));
|
||||
//this.$el.toggleClass('has-season', this.model.has('seasonNumber'));
|
||||
}
|
||||
});
|
||||
|
@ -1,28 +0,0 @@
|
||||
var vent = require('vent');
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'ManualImport/Season/SelectSeasonLayoutTemplate',
|
||||
|
||||
events : {
|
||||
'change .x-select-season' : '_selectSeason'
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
|
||||
this.templateHelpers = {
|
||||
seasons : options.seasons
|
||||
};
|
||||
},
|
||||
|
||||
_selectSeason : function (e) {
|
||||
var seasonNumber = parseInt(e.target.value, 10);
|
||||
|
||||
if (seasonNumber === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.trigger('manualimport:selected:season', { seasonNumber: seasonNumber });
|
||||
vent.trigger(vent.Commands.CloseModal2Command);
|
||||
}
|
||||
});
|
@ -1,29 +0,0 @@
|
||||
<div class="modal-content">
|
||||
<div class="manual-import-modal">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
|
||||
<h3>
|
||||
Manual Import - Select Season
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="form-group col-md-4 col-md-offset-4">
|
||||
<select class="form-control x-select-season">
|
||||
<option value="-1">Select Season</option>
|
||||
{{#each seasons}}
|
||||
<option value="{{seasonNumber}}">Season {{seasonNumber}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,101 +0,0 @@
|
||||
var _ = require('underscore');
|
||||
var vent = require('vent');
|
||||
var Marionette = require('marionette');
|
||||
var Backgrid = require('backgrid');
|
||||
var SeriesCollection = require('../../Series/SeriesCollection');
|
||||
var SelectRow = require('./SelectSeriesRow');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'ManualImport/Series/SelectSeriesLayoutTemplate',
|
||||
|
||||
regions : {
|
||||
series : '.x-series'
|
||||
},
|
||||
|
||||
ui : {
|
||||
filter : '.x-filter'
|
||||
},
|
||||
|
||||
columns : [
|
||||
{
|
||||
name : 'title',
|
||||
label : 'Title',
|
||||
cell : 'String',
|
||||
sortValue : 'sortTitle'
|
||||
}
|
||||
],
|
||||
|
||||
initialize : function() {
|
||||
this.seriesCollection = SeriesCollection.clone();
|
||||
this._setModelCollection();
|
||||
|
||||
this.listenTo(this.seriesCollection, 'row:selected', this._onSelected);
|
||||
this.listenTo(this, 'modal:afterShow', this._setFocus);
|
||||
},
|
||||
|
||||
onRender : function() {
|
||||
this.seriesView = new Backgrid.Grid({
|
||||
columns : this.columns,
|
||||
collection : this.seriesCollection,
|
||||
className : 'table table-hover season-grid',
|
||||
row : SelectRow
|
||||
});
|
||||
|
||||
this.series.show(this.seriesView);
|
||||
this._setupFilter();
|
||||
},
|
||||
|
||||
_setupFilter : function () {
|
||||
var self = this;
|
||||
|
||||
//TODO: This should be a mixin (same as Add Series searching)
|
||||
this.ui.filter.keyup(function(e) {
|
||||
if (_.contains([
|
||||
9,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
37,
|
||||
38,
|
||||
39,
|
||||
40,
|
||||
91,
|
||||
92,
|
||||
93
|
||||
], e.keyCode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
self._filter(self.ui.filter.val());
|
||||
});
|
||||
},
|
||||
|
||||
_filter : function (term) {
|
||||
this.seriesCollection.setFilter(['title', term, 'contains']);
|
||||
this._setModelCollection();
|
||||
},
|
||||
|
||||
_onSelected : function (e) {
|
||||
this.trigger('manualimport:selected:series', { model: e.model });
|
||||
|
||||
vent.trigger(vent.Commands.CloseModal2Command);
|
||||
},
|
||||
|
||||
_setFocus : function () {
|
||||
this.ui.filter.focus();
|
||||
},
|
||||
|
||||
_setModelCollection: function () {
|
||||
var self = this;
|
||||
|
||||
_.each(this.seriesCollection.models, function (model) {
|
||||
model.collection = self.seriesCollection;
|
||||
});
|
||||
}
|
||||
});
|
@ -1,30 +0,0 @@
|
||||
<div class="modal-content">
|
||||
<div class="manual-import-modal">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
|
||||
<h3>
|
||||
Manual Import - Select Series
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control x-filter" placeholder="Filter series" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12 x-series"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
var Backgrid = require('backgrid');
|
||||
|
||||
module.exports = Backgrid.Row.extend({
|
||||
className : 'select-row select-series-row',
|
||||
|
||||
events : {
|
||||
'click' : '_onClick'
|
||||
},
|
||||
|
||||
_onClick : function() {
|
||||
this.model.collection.trigger('row:selected', { model: this.model });
|
||||
}
|
||||
});
|
@ -4,20 +4,6 @@ var Marionette = require('marionette');
|
||||
module.exports = Marionette.ItemView.extend({
|
||||
template : 'ManualImport/Summary/ManualImportSummaryViewTemplate',
|
||||
|
||||
// initialize : function (options) {
|
||||
// var episodes = _.map(options.episodes, function (episode) {
|
||||
// return episode.toJSON();
|
||||
// });
|
||||
|
||||
// this.templateHelpers = {
|
||||
// file : options.file,
|
||||
// series : options.series,
|
||||
// season : options.season,
|
||||
// episodes : episodes,
|
||||
// quality : options.quality
|
||||
// };
|
||||
// }
|
||||
|
||||
initialize : function (options) {
|
||||
|
||||
this.templateHelpers = {
|
||||
|
@ -8,7 +8,7 @@ var MoviesCollection = require('../MoviesCollection');
|
||||
var InfoView = require('./InfoView');
|
||||
var CommandController = require('../../Commands/CommandController');
|
||||
var LoadingView = require('../../Shared/LoadingView');
|
||||
var EpisodeFileEditorLayout = require('../../EpisodeFile/Editor/EpisodeFileEditorLayout');
|
||||
// var EpisodeFileEditorLayout = require('../../EpisodeFile/Editor/EpisodeFileEditorLayout');
|
||||
var HistoryLayout = require('../History/MovieHistoryLayout');
|
||||
var SearchLayout = require('../Search/MovieSearchLayout');
|
||||
var AllFilesLayout = require("../Files/AllFilesLayout");
|
||||
@ -251,14 +251,14 @@ module.exports = Marionette.Layout.extend({
|
||||
this._showInfo();
|
||||
},
|
||||
|
||||
_openEpisodeFileEditor : function() {
|
||||
var view = new EpisodeFileEditorLayout({
|
||||
movies : this.model,
|
||||
episodeCollection : this.episodeCollection
|
||||
});
|
||||
// _openEpisodeFileEditor : function() {
|
||||
// var view = new EpisodeFileEditorLayout({
|
||||
// movies : this.model,
|
||||
// episodeCollection : this.episodeCollection
|
||||
// });
|
||||
|
||||
vent.trigger(vent.Commands.OpenModalCommand, view);
|
||||
},
|
||||
// vent.trigger(vent.Commands.OpenModalCommand, view);
|
||||
// },
|
||||
|
||||
_updateImages : function () {
|
||||
var poster = this._getImage('poster');
|
||||
|
@ -4,5 +4,5 @@ var PosterItemView = require('./SeriesPostersItemView');
|
||||
module.exports = Marionette.CompositeView.extend({
|
||||
itemView : PosterItemView,
|
||||
itemViewContainer : '#x-series-posters',
|
||||
template : 'Series/Index/Posters/SeriesPostersCollectionViewTemplate'
|
||||
template : 'Movies/Index/Posters/SeriesPostersCollectionViewTemplate'
|
||||
});
|
@ -4,8 +4,6 @@ var Controller = require('./Controller');
|
||||
module.exports = Marionette.AppRouter.extend({
|
||||
controller : new Controller(),
|
||||
appRoutes : {
|
||||
'addseries' : 'addSeries',
|
||||
'addseries/:action(/:query)' : 'addSeries',
|
||||
'addmovies' : 'addMovies',
|
||||
'addmovies/:action(/:query)' : 'addMovies',
|
||||
'calendar' : 'calendar',
|
||||
@ -20,7 +18,6 @@ module.exports = Marionette.AppRouter.extend({
|
||||
'rss' : 'rss',
|
||||
'system' : 'system',
|
||||
'system/:action' : 'system',
|
||||
'seasonpass' : 'seasonPass',
|
||||
'movieeditor' : 'movieEditor',
|
||||
':whatever' : 'showNotFound'
|
||||
}
|
||||
|
@ -1,139 +0,0 @@
|
||||
var _ = require('underscore');
|
||||
var $ = require('jquery');
|
||||
var Marionette = require('marionette');
|
||||
var vent = require('vent');
|
||||
var RootFolders = require('../AddSeries/RootFolders/RootFolderCollection');
|
||||
|
||||
module.exports = Marionette.ItemView.extend({
|
||||
template : 'SeasonPass/SeasonPassFooterViewTemplate',
|
||||
|
||||
ui : {
|
||||
seriesMonitored : '.x-series-monitored',
|
||||
monitor : '.x-monitor',
|
||||
selectedCount : '.x-selected-count',
|
||||
container : '.series-editor-footer',
|
||||
actions : '.x-action',
|
||||
indicator : '.x-indicator',
|
||||
indicatorIcon : '.x-indicator-icon'
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-update' : '_update'
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
this.seriesCollection = options.collection;
|
||||
|
||||
RootFolders.fetch().done(function() {
|
||||
RootFolders.synced = true;
|
||||
});
|
||||
|
||||
this.editorGrid = options.editorGrid;
|
||||
this.listenTo(this.seriesCollection, 'backgrid:selected', this._updateInfo);
|
||||
},
|
||||
|
||||
onRender : function() {
|
||||
this._updateInfo();
|
||||
},
|
||||
|
||||
_update : function() {
|
||||
var self = this;
|
||||
var selected = this.editorGrid.getSelectedModels();
|
||||
var seriesMonitored = this.ui.seriesMonitored.val();
|
||||
var monitoringOptions;
|
||||
|
||||
_.each(selected, function(model) {
|
||||
if (seriesMonitored === 'true') {
|
||||
model.set('monitored', true);
|
||||
} else if (seriesMonitored === 'false') {
|
||||
model.set('monitored', false);
|
||||
}
|
||||
|
||||
monitoringOptions = self._getMonitoringOptions(model);
|
||||
model.set('addOptions', monitoringOptions);
|
||||
});
|
||||
|
||||
var promise = $.ajax({
|
||||
url : window.NzbDrone.ApiRoot + '/seasonpass',
|
||||
type : 'POST',
|
||||
data : JSON.stringify({
|
||||
series : _.map(selected, function (model) {
|
||||
return model.toJSON();
|
||||
}),
|
||||
monitoringOptions : monitoringOptions
|
||||
})
|
||||
});
|
||||
|
||||
this.ui.indicator.show();
|
||||
|
||||
promise.always(function () {
|
||||
self.ui.indicator.hide();
|
||||
});
|
||||
|
||||
promise.done(function () {
|
||||
self.seriesCollection.trigger('seasonpass:saved');
|
||||
});
|
||||
},
|
||||
|
||||
_updateInfo : function() {
|
||||
var selected = this.editorGrid.getSelectedModels();
|
||||
var selectedCount = selected.length;
|
||||
|
||||
this.ui.selectedCount.html('{0} series selected'.format(selectedCount));
|
||||
|
||||
if (selectedCount === 0) {
|
||||
this.ui.actions.attr('disabled', 'disabled');
|
||||
} else {
|
||||
this.ui.actions.removeAttr('disabled');
|
||||
}
|
||||
},
|
||||
|
||||
_getMonitoringOptions : function(model) {
|
||||
var monitor = this.ui.monitor.val();
|
||||
var lastSeason = _.max(model.get('seasons'), 'seasonNumber');
|
||||
var firstSeason = _.min(_.reject(model.get('seasons'), { seasonNumber : 0 }), 'seasonNumber');
|
||||
|
||||
if (monitor === 'noChange') {
|
||||
return null;
|
||||
}
|
||||
|
||||
model.setSeasonPass(firstSeason.seasonNumber);
|
||||
|
||||
var options = {
|
||||
ignoreEpisodesWithFiles : false,
|
||||
ignoreEpisodesWithoutFiles : false
|
||||
};
|
||||
|
||||
if (monitor === 'all') {
|
||||
return options;
|
||||
}
|
||||
|
||||
else if (monitor === 'future') {
|
||||
options.ignoreEpisodesWithFiles = true;
|
||||
options.ignoreEpisodesWithoutFiles = true;
|
||||
}
|
||||
|
||||
else if (monitor === 'latest') {
|
||||
model.setSeasonPass(lastSeason.seasonNumber);
|
||||
}
|
||||
|
||||
else if (monitor === 'first') {
|
||||
model.setSeasonPass(lastSeason.seasonNumber + 1);
|
||||
model.setSeasonMonitored(firstSeason.seasonNumber);
|
||||
}
|
||||
|
||||
else if (monitor === 'missing') {
|
||||
options.ignoreEpisodesWithFiles = true;
|
||||
}
|
||||
|
||||
else if (monitor === 'existing') {
|
||||
options.ignoreEpisodesWithoutFiles = true;
|
||||
}
|
||||
|
||||
else if (monitor === 'none') {
|
||||
model.setSeasonPass(lastSeason.seasonNumber + 1);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
});
|
@ -1,36 +0,0 @@
|
||||
<div class="series-editor-footer">
|
||||
<div class="row">
|
||||
<div class="form-group col-md-2">
|
||||
<label>Monitor series</label>
|
||||
|
||||
<select class="form-control x-action x-series-monitored">
|
||||
<option value="noChange">No change</option>
|
||||
<option value="true">Monitored</option>
|
||||
<option value="false">Unmonitored</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-2">
|
||||
<label>Monitor episodes</label>
|
||||
|
||||
<select class="form-control x-action x-monitor">
|
||||
<option value="noChange">No change</option>
|
||||
<option value="all">All</option>
|
||||
<option value="future">Future</option>
|
||||
<option value="missing">Missing</option>
|
||||
<option value="existing">Existing</option>
|
||||
<option value="first">First Season</option>
|
||||
<option value="latest">Latest Season</option>
|
||||
<option value="none">None</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-3 actions">
|
||||
<label class="x-selected-count">0 series selected</label>
|
||||
<div>
|
||||
<button class="btn btn-primary x-action x-update">Update Selected Series</button>
|
||||
<span class="indicator x-indicator"><i class="icon-sonarr-spinner fa-spin"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,152 +0,0 @@
|
||||
var _ = require('underscore');
|
||||
var vent = require('vent');
|
||||
var Backgrid = require('backgrid');
|
||||
var Marionette = require('marionette');
|
||||
var EmptyView = require('../Series/Index/EmptyView');
|
||||
var SeriesCollection = require('../Series/SeriesCollection');
|
||||
var ToolbarLayout = require('../Shared/Toolbar/ToolbarLayout');
|
||||
var FooterView = require('./SeasonPassFooterView');
|
||||
var SelectAllCell = require('../Cells/SelectAllCell');
|
||||
var SeriesStatusCell = require('../Cells/SeriesStatusCell');
|
||||
var SeriesTitleCell = require('../Cells/SeriesTitleCell');
|
||||
var SeriesMonitoredCell = require('../Cells/ToggleCell');
|
||||
var SeasonsCell = require('./SeasonsCell');
|
||||
require('../Mixins/backbone.signalr.mixin');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'SeasonPass/SeasonPassLayoutTemplate',
|
||||
|
||||
regions : {
|
||||
toolbar : '#x-toolbar',
|
||||
series : '#x-series'
|
||||
},
|
||||
|
||||
columns : [
|
||||
{
|
||||
name : '',
|
||||
cell : SelectAllCell,
|
||||
headerCell : 'select-all',
|
||||
sortable : false
|
||||
},
|
||||
{
|
||||
name : 'statusWeight',
|
||||
label : '',
|
||||
cell : SeriesStatusCell
|
||||
},
|
||||
{
|
||||
name : 'title',
|
||||
label : 'Title',
|
||||
cell : SeriesTitleCell,
|
||||
cellValue : 'this'
|
||||
},
|
||||
{
|
||||
name : 'monitored',
|
||||
label : '',
|
||||
cell : SeriesMonitoredCell,
|
||||
trueClass : 'icon-sonarr-monitored',
|
||||
falseClass : 'icon-sonarr-unmonitored',
|
||||
tooltip : 'Toggle series monitored status',
|
||||
sortable : false
|
||||
},
|
||||
{
|
||||
name : 'seasons',
|
||||
label : 'Seasons',
|
||||
cell : SeasonsCell,
|
||||
cellValue : 'this'
|
||||
}
|
||||
],
|
||||
|
||||
initialize : function() {
|
||||
this.seriesCollection = SeriesCollection.clone();
|
||||
this.seriesCollection.shadowCollection.bindSignalR();
|
||||
|
||||
// this.listenTo(this.seriesCollection, 'sync', this.render);
|
||||
this.listenTo(this.seriesCollection, 'seasonpass:saved', this.render);
|
||||
|
||||
this.filteringOptions = {
|
||||
type : 'radio',
|
||||
storeState : true,
|
||||
menuKey : 'seasonpass.filterMode',
|
||||
defaultAction : 'all',
|
||||
items : [
|
||||
{
|
||||
key : 'all',
|
||||
title : '',
|
||||
tooltip : 'All',
|
||||
icon : 'icon-sonarr-all',
|
||||
callback : this._setFilter
|
||||
},
|
||||
{
|
||||
key : 'monitored',
|
||||
title : '',
|
||||
tooltip : 'Monitored Only',
|
||||
icon : 'icon-sonarr-monitored',
|
||||
callback : this._setFilter
|
||||
},
|
||||
{
|
||||
key : 'continuing',
|
||||
title : '',
|
||||
tooltip : 'Continuing Only',
|
||||
icon : 'icon-sonarr-series-continuing',
|
||||
callback : this._setFilter
|
||||
},
|
||||
{
|
||||
key : 'ended',
|
||||
title : '',
|
||||
tooltip : 'Ended Only',
|
||||
icon : 'icon-sonarr-series-ended',
|
||||
callback : this._setFilter
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
|
||||
onRender : function() {
|
||||
this._showTable();
|
||||
this._showToolbar();
|
||||
this._showFooter();
|
||||
},
|
||||
|
||||
onClose : function() {
|
||||
vent.trigger(vent.Commands.CloseControlPanelCommand);
|
||||
},
|
||||
|
||||
_showToolbar : function() {
|
||||
this.toolbar.show(new ToolbarLayout({
|
||||
right : [this.filteringOptions],
|
||||
context : this
|
||||
}));
|
||||
},
|
||||
|
||||
_showTable : function() {
|
||||
if (this.seriesCollection.shadowCollection.length === 0) {
|
||||
this.series.show(new EmptyView());
|
||||
this.toolbar.close();
|
||||
return;
|
||||
}
|
||||
|
||||
this.columns[0].sortedCollection = this.seriesCollection;
|
||||
|
||||
this.editorGrid = new Backgrid.Grid({
|
||||
collection : this.seriesCollection,
|
||||
columns : this.columns,
|
||||
className : 'table table-hover'
|
||||
});
|
||||
|
||||
this.series.show(this.editorGrid);
|
||||
this._showFooter();
|
||||
},
|
||||
|
||||
_showFooter : function() {
|
||||
vent.trigger(vent.Commands.OpenControlPanelCommand, new FooterView({
|
||||
editorGrid : this.editorGrid,
|
||||
collection : this.seriesCollection
|
||||
}));
|
||||
},
|
||||
|
||||
_setFilter : function(buttonContext) {
|
||||
var mode = buttonContext.model.get('key');
|
||||
|
||||
this.seriesCollection.setFilterMode(mode);
|
||||
}
|
||||
});
|
@ -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-sonarr-monitored{{else}}icon-sonarr-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}}
|
@ -1,54 +0,0 @@
|
||||
@import "../Content/badges.less";
|
||||
@import "../Shared/Styles/clickable.less";
|
||||
|
||||
.season {
|
||||
display : inline-block;
|
||||
margin-bottom : 4px;
|
||||
|
||||
.label {
|
||||
.badge-inverse();
|
||||
|
||||
display : inline-block;
|
||||
padding : 4px;
|
||||
|
||||
font-size : 14px;
|
||||
height : 25px;
|
||||
}
|
||||
|
||||
.label:first-child {
|
||||
border-right : 0;
|
||||
border-top-right-radius : 0.0em;
|
||||
border-bottom-right-radius : 0.0em;
|
||||
color : #777;
|
||||
background-color : #eee;
|
||||
}
|
||||
|
||||
.label:last-child {
|
||||
border-left : 0;
|
||||
border-top-left-radius : 0.0em;
|
||||
border-bottom-left-radius : 0.0em;
|
||||
color : #999;
|
||||
background-color : #f7f7f7;
|
||||
}
|
||||
|
||||
&.season-all .label:last-child {
|
||||
background-color : #e0ffe0;
|
||||
}
|
||||
|
||||
.season-monitored {
|
||||
width : 16px;
|
||||
|
||||
i {
|
||||
.clickable();
|
||||
}
|
||||
}
|
||||
|
||||
.season-number {
|
||||
font-size : 12px;
|
||||
}
|
||||
|
||||
.season-status {
|
||||
display : inline-block;
|
||||
vertical-align : baseline !important;
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>Delete {{title}}</h3>
|
||||
</div>
|
||||
<div class="modal-body delete-series-modal">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-3 hidden-xs">
|
||||
{{poster}}
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<div class="form-horizontal">
|
||||
<h3 class="path">{{path}}</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">Delete all files</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<label class="checkbox toggle well">
|
||||
<input type="checkbox" class="x-delete-files"/>
|
||||
<p>
|
||||
<span>Yes</span>
|
||||
<span>No</span>
|
||||
</p>
|
||||
|
||||
<div class="btn slide-button btn-danger"/>
|
||||
</label>
|
||||
|
||||
<span class="help-inline-checkbox">
|
||||
<i class="icon-sonarr-form-info" title="Do you want to delete all files from disk?"/>
|
||||
<i class="icon-sonarr-form-warning" title="This option is irreversible, use with extreme caution"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-offset-1 col-md-5 delete-files-info x-delete-files-info">
|
||||
{{episodeFileCount}} episode files will be deleted
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<span class="indicator x-indicator"><i class="icon-sonarr-spinner fa-spin"></i></span>
|
||||
<button class="btn" data-dismiss="modal">Cancel</button>
|
||||
<button class="btn btn-danger x-confirm-delete">Delete</button>
|
||||
</div>
|
||||
</div>
|
@ -1,41 +0,0 @@
|
||||
var vent = require('vent');
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.ItemView.extend({
|
||||
template : 'Series/Delete/DeleteSeriesTemplate',
|
||||
|
||||
events : {
|
||||
'click .x-confirm-delete' : 'removeSeries',
|
||||
'change .x-delete-files' : 'changeDeletedFiles'
|
||||
},
|
||||
|
||||
ui : {
|
||||
deleteFiles : '.x-delete-files',
|
||||
deleteFilesInfo : '.x-delete-files-info',
|
||||
indicator : '.x-indicator'
|
||||
},
|
||||
|
||||
removeSeries : function() {
|
||||
var self = this;
|
||||
var deleteFiles = this.ui.deleteFiles.prop('checked');
|
||||
this.ui.indicator.show();
|
||||
|
||||
this.model.destroy({
|
||||
data : { 'deleteFiles' : deleteFiles },
|
||||
wait : true
|
||||
}).done(function() {
|
||||
vent.trigger(vent.Events.SeriesDeleted, { series : self.model });
|
||||
vent.trigger(vent.Commands.CloseModalCommand);
|
||||
});
|
||||
},
|
||||
|
||||
changeDeletedFiles : function() {
|
||||
var deleteFiles = this.ui.deleteFiles.prop('checked');
|
||||
|
||||
if (deleteFiles) {
|
||||
this.ui.deleteFilesInfo.show();
|
||||
} else {
|
||||
this.ui.deleteFilesInfo.hide();
|
||||
}
|
||||
}
|
||||
});
|
@ -1,47 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
var NzbDroneCell = require('../../Cells/NzbDroneCell');
|
||||
var reqres = require('../../reqres');
|
||||
var SeriesCollection = require('../SeriesCollection');
|
||||
|
||||
module.exports = NzbDroneCell.extend({
|
||||
className : 'episode-number-cell',
|
||||
template : 'Series/Details/EpisodeNumberCellTemplate',
|
||||
|
||||
render : function() {
|
||||
this.$el.empty();
|
||||
this.$el.html(this.model.get('episodeNumber'));
|
||||
|
||||
var series = SeriesCollection.get(this.model.get('seriesId'));
|
||||
|
||||
if (series.get('seriesType') === 'anime' && this.model.has('absoluteEpisodeNumber')) {
|
||||
this.$el.html('{0} ({1})'.format(this.model.get('episodeNumber'), this.model.get('absoluteEpisodeNumber')));
|
||||
}
|
||||
|
||||
var alternateTitles = [];
|
||||
|
||||
if (reqres.hasHandler(reqres.Requests.GetAlternateNameBySeasonNumber)) {
|
||||
alternateTitles = reqres.request(reqres.Requests.GetAlternateNameBySeasonNumber, this.model.get('seriesId'), this.model.get('seasonNumber'), this.model.get('sceneSeasonNumber'));
|
||||
}
|
||||
|
||||
if (this.model.get('sceneSeasonNumber') > 0 || this.model.get('sceneEpisodeNumber') > 0 || this.model.has('sceneAbsoluteEpisodeNumber') || alternateTitles.length > 0) {
|
||||
this.templateFunction = Marionette.TemplateCache.get(this.template);
|
||||
|
||||
var json = this.model.toJSON();
|
||||
json.alternateTitles = alternateTitles;
|
||||
|
||||
var html = this.templateFunction(json);
|
||||
|
||||
this.$el.popover({
|
||||
content : html,
|
||||
html : true,
|
||||
trigger : 'hover',
|
||||
title : 'Scene Information',
|
||||
placement : 'right',
|
||||
container : this.$el
|
||||
});
|
||||
}
|
||||
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
}
|
||||
});
|
@ -1,39 +0,0 @@
|
||||
<div class="scene-info">
|
||||
{{#if sceneSeasonNumber}}
|
||||
<div class="row">
|
||||
<div class="key">Season</div>
|
||||
<div class="value">{{sceneSeasonNumber}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if sceneEpisodeNumber}}
|
||||
<div class="row">
|
||||
<div class="key">Episode</div>
|
||||
<div class="value">{{sceneEpisodeNumber}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if sceneAbsoluteEpisodeNumber}}
|
||||
<div class="row">
|
||||
<div class="key">Absolute</div>
|
||||
<div class="value">{{sceneAbsoluteEpisodeNumber}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if alternateTitles}}
|
||||
<div class="row">
|
||||
{{#if_gt alternateTitles.length compare="1"}}
|
||||
<div class="key">Titles</div>
|
||||
{{else}}
|
||||
<div class="key">Title</div>
|
||||
{{/if_gt}}
|
||||
<div class="value">
|
||||
<ul>
|
||||
{{#each alternateTitles}}
|
||||
<li>{{title}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
@ -1,21 +0,0 @@
|
||||
var NzbDroneCell = require('../../Cells/NzbDroneCell');
|
||||
var SeriesCollection = require('../SeriesCollection');
|
||||
|
||||
module.exports = NzbDroneCell.extend({
|
||||
className : 'episode-warning-cell',
|
||||
|
||||
render : function() {
|
||||
this.$el.empty();
|
||||
|
||||
if (this.model.get('unverifiedSceneNumbering')) {
|
||||
this.$el.html('<i class="icon-sonarr-form-warning" title="Scene number hasn\'t been verified yet."></i>');
|
||||
}
|
||||
|
||||
else if (SeriesCollection.get(this.model.get('seriesId')).get('seriesType') === 'anime' && this.model.get('seasonNumber') > 0 && !this.model.has('absoluteEpisodeNumber')) {
|
||||
this.$el.html('<i class="icon-sonarr-form-warning" title="Episode does not have an absolute episode number"></i>');
|
||||
}
|
||||
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
}
|
||||
});
|
@ -1,18 +0,0 @@
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.ItemView.extend({
|
||||
template : 'Series/Details/InfoViewTemplate',
|
||||
|
||||
initialize : function(options) {
|
||||
this.episodeFileCollection = options.episodeFileCollection;
|
||||
|
||||
this.listenTo(this.model, 'change', this.render);
|
||||
this.listenTo(this.episodeFileCollection, 'sync', this.render);
|
||||
},
|
||||
|
||||
templateHelpers : function() {
|
||||
return {
|
||||
fileCount : this.episodeFileCollection.length
|
||||
};
|
||||
}
|
||||
});
|
@ -1,73 +0,0 @@
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
{{profile profileId}}
|
||||
|
||||
{{#if network}}
|
||||
<span class="label label-info">{{network}}</span>
|
||||
{{/if}}
|
||||
|
||||
<span class="label label-info">{{runtime}} minutes</span>
|
||||
<span class="label label-info">{{path}}</span>
|
||||
|
||||
{{#if ratings}}
|
||||
<span class="label label-info" title="{{ratings.votes}} vote{{#if_gt ratings.votes compare="1"}}s{{/if_gt}}">{{ratings.value}}</span>
|
||||
{{/if}}
|
||||
|
||||
<span class="label label-info">{{Bytes sizeOnDisk}}</span>
|
||||
|
||||
{{#if_eq fileCount compare="1"}}
|
||||
<span class="label label-info"> 1 file</span>
|
||||
{{else}}
|
||||
<span class="label label-info"> {{fileCount}} files</span>
|
||||
{{/if_eq}}
|
||||
|
||||
{{#if_eq status compare="continuing"}}
|
||||
<span class="label label-info">Continuing</span>
|
||||
{{else}}
|
||||
<span class="label label-default">Ended</span>
|
||||
{{/if_eq}}
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<span class="series-info-links">
|
||||
{{!--
|
||||
<a href="{{traktUrl}}" class="label label-info">Trakt</a>
|
||||
<a href="{{tvdbUrl}}" class="label label-info">The TVDB</a>
|
||||
--}}
|
||||
{{#if imdbId}}
|
||||
<a href="{{imdbUrl}}" class="label label-info">IMDB</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if tvRageId}}
|
||||
<a href="{{tvRageUrl}}" class="label label-info">TV Rage</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if tvMazeId}}
|
||||
<a href="{{tvMazeUrl}}" class="label label-info">TV Maze</a>
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if alternateTitles}}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{#each alternateTitles}}
|
||||
{{#if_eq seasonNumber compare="-1"}}
|
||||
<span class="label label-default">{{title}}</span>
|
||||
{{/if_eq}}
|
||||
|
||||
{{#if_eq sceneSeasonNumber compare="-1"}}
|
||||
<span class="label label-default">{{title}}</span>
|
||||
{{/if_eq}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if tags}}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{tagDisplay tags}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
@ -1,44 +0,0 @@
|
||||
var _ = require('underscore');
|
||||
var Marionette = require('marionette');
|
||||
var SeasonLayout = require('./SeasonLayout');
|
||||
var AsSortedCollectionView = require('../../Mixins/AsSortedCollectionView');
|
||||
|
||||
var view = Marionette.CollectionView.extend({
|
||||
|
||||
itemView : SeasonLayout,
|
||||
|
||||
initialize : function(options) {
|
||||
if (!options.episodeCollection) {
|
||||
throw 'episodeCollection is needed';
|
||||
}
|
||||
|
||||
this.episodeCollection = options.episodeCollection;
|
||||
this.series = options.series;
|
||||
},
|
||||
|
||||
itemViewOptions : function() {
|
||||
return {
|
||||
episodeCollection : this.episodeCollection,
|
||||
series : this.series
|
||||
};
|
||||
},
|
||||
|
||||
onEpisodeGrabbed : function(message) {
|
||||
if (message.episode.series.id !== this.episodeCollection.seriesId) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
_.each(message.episode.episodes, function(episode) {
|
||||
var ep = self.episodeCollection.get(episode.id);
|
||||
ep.set('downloading', true);
|
||||
});
|
||||
|
||||
this.render();
|
||||
}
|
||||
});
|
||||
|
||||
AsSortedCollectionView.call(view);
|
||||
|
||||
module.exports = view;
|
@ -1,301 +0,0 @@
|
||||
var vent = require('vent');
|
||||
var Marionette = require('marionette');
|
||||
var Backgrid = require('backgrid');
|
||||
var ToggleCell = require('../../Cells/EpisodeMonitoredCell');
|
||||
var EpisodeTitleCell = require('../../Cells/EpisodeTitleCell');
|
||||
var RelativeDateCell = require('../../Cells/RelativeDateCell');
|
||||
var EpisodeStatusCell = require('../../Cells/EpisodeStatusCell');
|
||||
var EpisodeActionsCell = require('../../Cells/EpisodeActionsCell');
|
||||
var EpisodeNumberCell = require('./EpisodeNumberCell');
|
||||
var EpisodeWarningCell = require('./EpisodeWarningCell');
|
||||
var CommandController = require('../../Commands/CommandController');
|
||||
var EpisodeFileEditorLayout = require('../../EpisodeFile/Editor/EpisodeFileEditorLayout');
|
||||
var moment = require('moment');
|
||||
var _ = require('underscore');
|
||||
var Messenger = require('../../Shared/Messenger');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
template : 'Series/Details/SeasonLayoutTemplate',
|
||||
|
||||
ui : {
|
||||
seasonSearch : '.x-season-search',
|
||||
seasonMonitored : '.x-season-monitored',
|
||||
seasonRename : '.x-season-rename'
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-season-episode-file-editor' : '_openEpisodeFileEditor',
|
||||
'click .x-season-monitored' : '_seasonMonitored',
|
||||
'click .x-season-search' : '_seasonSearch',
|
||||
'click .x-season-rename' : '_seasonRename',
|
||||
'click .x-show-hide-episodes' : '_showHideEpisodes',
|
||||
'dblclick .series-season h2' : '_showHideEpisodes'
|
||||
},
|
||||
|
||||
regions : {
|
||||
episodeGrid : '.x-episode-grid'
|
||||
},
|
||||
|
||||
columns : [
|
||||
{
|
||||
name : 'monitored',
|
||||
label : '',
|
||||
cell : ToggleCell,
|
||||
trueClass : 'icon-sonarr-monitored',
|
||||
falseClass : 'icon-sonarr-unmonitored',
|
||||
tooltip : 'Toggle monitored status',
|
||||
sortable : false
|
||||
},
|
||||
{
|
||||
name : 'episodeNumber',
|
||||
label : '#',
|
||||
cell : EpisodeNumberCell
|
||||
},
|
||||
{
|
||||
name : 'this',
|
||||
label : '',
|
||||
cell : EpisodeWarningCell,
|
||||
sortable : false,
|
||||
className : 'episode-warning-cell'
|
||||
},
|
||||
{
|
||||
name : 'this',
|
||||
label : 'Title',
|
||||
hideSeriesLink : true,
|
||||
cell : EpisodeTitleCell,
|
||||
sortable : false
|
||||
},
|
||||
{
|
||||
name : 'airDateUtc',
|
||||
label : 'Air Date',
|
||||
cell : RelativeDateCell
|
||||
},
|
||||
{
|
||||
name : 'status',
|
||||
label : 'Status',
|
||||
cell : EpisodeStatusCell,
|
||||
sortable : false
|
||||
},
|
||||
{
|
||||
name : 'this',
|
||||
label : '',
|
||||
cell : EpisodeActionsCell,
|
||||
sortable : false
|
||||
}
|
||||
],
|
||||
|
||||
templateHelpers : function() {
|
||||
var episodeCount = this.episodeCollection.filter(function(episode) {
|
||||
return episode.get('hasFile') || episode.get('monitored') && moment(episode.get('airDateUtc')).isBefore(moment());
|
||||
}).length;
|
||||
|
||||
var episodeFileCount = this.episodeCollection.where({ hasFile : true }).length;
|
||||
var percentOfEpisodes = 100;
|
||||
|
||||
if (episodeCount > 0) {
|
||||
percentOfEpisodes = episodeFileCount / episodeCount * 100;
|
||||
}
|
||||
|
||||
return {
|
||||
showingEpisodes : this.showingEpisodes,
|
||||
episodeCount : episodeCount,
|
||||
episodeFileCount : episodeFileCount,
|
||||
percentOfEpisodes : percentOfEpisodes
|
||||
};
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
if (!options.episodeCollection) {
|
||||
throw 'episodeCollection is required';
|
||||
}
|
||||
|
||||
this.series = options.series;
|
||||
this.fullEpisodeCollection = options.episodeCollection;
|
||||
this.episodeCollection = this.fullEpisodeCollection.bySeason(this.model.get('seasonNumber'));
|
||||
this._updateEpisodeCollection();
|
||||
|
||||
this.showingEpisodes = this._shouldShowEpisodes();
|
||||
|
||||
this.listenTo(this.model, 'sync', this._afterSeasonMonitored);
|
||||
this.listenTo(this.episodeCollection, 'sync', this.render);
|
||||
|
||||
this.listenTo(this.fullEpisodeCollection, 'sync', this._refreshEpisodes);
|
||||
},
|
||||
|
||||
onRender : function() {
|
||||
if (this.showingEpisodes) {
|
||||
this._showEpisodes();
|
||||
}
|
||||
|
||||
this._setSeasonMonitoredState();
|
||||
|
||||
CommandController.bindToCommand({
|
||||
element : this.ui.seasonSearch,
|
||||
command : {
|
||||
name : 'seasonSearch',
|
||||
seriesId : this.series.id,
|
||||
seasonNumber : this.model.get('seasonNumber')
|
||||
}
|
||||
});
|
||||
|
||||
CommandController.bindToCommand({
|
||||
element : this.ui.seasonRename,
|
||||
command : {
|
||||
name : 'renameFiles',
|
||||
seriesId : this.series.id,
|
||||
seasonNumber : this.model.get('seasonNumber')
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_seasonSearch : function() {
|
||||
CommandController.Execute('seasonSearch', {
|
||||
name : 'seasonSearch',
|
||||
seriesId : this.series.id,
|
||||
seasonNumber : this.model.get('seasonNumber')
|
||||
});
|
||||
},
|
||||
|
||||
_seasonRename : function() {
|
||||
vent.trigger(vent.Commands.ShowRenamePreview, {
|
||||
series : this.series,
|
||||
seasonNumber : this.model.get('seasonNumber')
|
||||
});
|
||||
},
|
||||
|
||||
_seasonMonitored : function() {
|
||||
if (!this.series.get('monitored')) {
|
||||
|
||||
Messenger.show({
|
||||
message : 'Unable to change monitored state when series is not monitored',
|
||||
type : 'error'
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var name = 'monitored';
|
||||
this.model.set(name, !this.model.get(name));
|
||||
this.series.setSeasonMonitored(this.model.get('seasonNumber'));
|
||||
|
||||
var savePromise = this.series.save().always(this._afterSeasonMonitored.bind(this));
|
||||
|
||||
this.ui.seasonMonitored.spinForPromise(savePromise);
|
||||
},
|
||||
|
||||
_afterSeasonMonitored : function() {
|
||||
var self = this;
|
||||
|
||||
_.each(this.episodeCollection.models, function(episode) {
|
||||
episode.set({ monitored : self.model.get('monitored') });
|
||||
});
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
||||
_setSeasonMonitoredState : function() {
|
||||
this.ui.seasonMonitored.removeClass('icon-sonarr-spinner fa-spin');
|
||||
|
||||
if (this.model.get('monitored')) {
|
||||
this.ui.seasonMonitored.addClass('icon-sonarr-monitored');
|
||||
this.ui.seasonMonitored.removeClass('icon-sonarr-unmonitored');
|
||||
} else {
|
||||
this.ui.seasonMonitored.addClass('icon-sonarr-unmonitored');
|
||||
this.ui.seasonMonitored.removeClass('icon-sonarr-monitored');
|
||||
}
|
||||
},
|
||||
|
||||
_showEpisodes : function() {
|
||||
this.episodeGrid.show(new Backgrid.Grid({
|
||||
columns : this.columns,
|
||||
collection : this.episodeCollection,
|
||||
className : 'table table-hover season-grid'
|
||||
}));
|
||||
},
|
||||
|
||||
_shouldShowEpisodes : function() {
|
||||
var startDate = moment().add(-1, 'month');
|
||||
var endDate = moment().add(1, 'year');
|
||||
|
||||
return this.episodeCollection.some(function(episode) {
|
||||
var airDate = episode.get('airDateUtc');
|
||||
|
||||
if (airDate) {
|
||||
var airDateMoment = moment(airDate);
|
||||
|
||||
if (airDateMoment.isAfter(startDate) && airDateMoment.isBefore(endDate)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
_showHideEpisodes : function() {
|
||||
if (this.showingEpisodes) {
|
||||
this.showingEpisodes = false;
|
||||
this.episodeGrid.close();
|
||||
} else {
|
||||
this.showingEpisodes = true;
|
||||
this._showEpisodes();
|
||||
}
|
||||
|
||||
this.templateHelpers.showingEpisodes = this.showingEpisodes;
|
||||
this.render();
|
||||
},
|
||||
|
||||
_episodeMonitoredToggled : function(options) {
|
||||
var model = options.model;
|
||||
var shiftKey = options.shiftKey;
|
||||
|
||||
if (!this.episodeCollection.get(model.get('id'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shiftKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
var lastToggled = this.episodeCollection.lastToggled;
|
||||
|
||||
if (!lastToggled) {
|
||||
return;
|
||||
}
|
||||
|
||||
var currentIndex = this.episodeCollection.indexOf(model);
|
||||
var lastIndex = this.episodeCollection.indexOf(lastToggled);
|
||||
|
||||
var low = Math.min(currentIndex, lastIndex);
|
||||
var high = Math.max(currentIndex, lastIndex);
|
||||
var range = _.range(low + 1, high);
|
||||
|
||||
this.episodeCollection.lastToggled = model;
|
||||
},
|
||||
|
||||
_updateEpisodeCollection : function() {
|
||||
var self = this;
|
||||
|
||||
this.episodeCollection.add(this.fullEpisodeCollection.bySeason(this.model.get('seasonNumber')).models, { merge : true });
|
||||
|
||||
this.episodeCollection.each(function(model) {
|
||||
model.episodeCollection = self.episodeCollection;
|
||||
});
|
||||
},
|
||||
|
||||
_refreshEpisodes : function() {
|
||||
this._updateEpisodeCollection();
|
||||
this.episodeCollection.fullCollection.sort();
|
||||
this.render();
|
||||
},
|
||||
|
||||
_openEpisodeFileEditor : function() {
|
||||
var view = new EpisodeFileEditorLayout({
|
||||
model : this.model,
|
||||
series : this.series,
|
||||
episodeCollection : this.episodeCollection
|
||||
});
|
||||
|
||||
vent.trigger(vent.Commands.OpenModalCommand, view);
|
||||
}
|
||||
});
|
@ -1,50 +0,0 @@
|
||||
<div class="series-season" id="season-{{seasonNumber}}">
|
||||
<h2>
|
||||
<i class="x-season-monitored season-monitored clickable" title="Toggle season monitored status"/>
|
||||
|
||||
{{#if seasonNumber}}
|
||||
Season {{seasonNumber}}
|
||||
{{else}}
|
||||
Specials
|
||||
{{/if}}
|
||||
|
||||
|
||||
{{#if_eq episodeCount compare=0}}
|
||||
{{#if monitored}}
|
||||
<span class="badge badge-primary season-status" title="No aired episodes"> </span>
|
||||
{{else}}
|
||||
<span class="badge badge-warning season-status" title="Season is not monitored"> </span>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#if_eq percentOfEpisodes compare=100}}
|
||||
<span class="badge badge-success season-status" title="{{episodeFileCount}}/{{episodeCount}} episodes downloaded">{{episodeFileCount}} / {{episodeCount}}</span>
|
||||
{{else}}
|
||||
<span class="badge badge-danger season-status" title="{{episodeFileCount}}/{{episodeCount}} episodes downloaded">{{episodeFileCount}} / {{episodeCount}}</span>
|
||||
{{/if_eq}}
|
||||
{{/if_eq}}
|
||||
|
||||
<span class="season-actions pull-right">
|
||||
<div class="x-season-episode-file-editor">
|
||||
<i class="icon-sonarr-episode-file" title="Modify episode files for season"/>
|
||||
</div>
|
||||
<div class="x-season-rename">
|
||||
<i class="icon-sonarr-rename" title="Preview rename for season {{seasonNumber}}"/>
|
||||
</div>
|
||||
<div class="x-season-search">
|
||||
<i class="icon-sonarr-search" title="Search for monitored episodes in season {{seasonNumber}}"/>
|
||||
</div>
|
||||
</span>
|
||||
</h2>
|
||||
<div class="show-hide-episodes x-show-hide-episodes">
|
||||
<h4>
|
||||
{{#if showingEpisodes}}
|
||||
<i class="icon-sonarr-panel-hide"/>
|
||||
Hide Episodes
|
||||
{{else}}
|
||||
<i class="icon-sonarr-panel-show"/>
|
||||
Show Episodes
|
||||
{{/if}}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="x-episode-grid table-responsive"></div>
|
||||
</div>
|
@ -1,272 +0,0 @@
|
||||
var $ = require('jquery');
|
||||
var _ = require('underscore');
|
||||
var vent = require('vent');
|
||||
var reqres = require('../../reqres');
|
||||
var Marionette = require('marionette');
|
||||
var Backbone = require('backbone');
|
||||
var SeriesCollection = require('../SeriesCollection');
|
||||
var EpisodeCollection = require('../EpisodeCollection');
|
||||
var EpisodeFileCollection = require('../EpisodeFileCollection');
|
||||
var SeasonCollection = require('../SeasonCollection');
|
||||
var SeasonCollectionView = require('./SeasonCollectionView');
|
||||
var InfoView = require('./InfoView');
|
||||
var CommandController = require('../../Commands/CommandController');
|
||||
var LoadingView = require('../../Shared/LoadingView');
|
||||
var EpisodeFileEditorLayout = require('../../EpisodeFile/Editor/EpisodeFileEditorLayout');
|
||||
require('backstrech');
|
||||
require('../../Mixins/backbone.signalr.mixin');
|
||||
|
||||
module.exports = Marionette.Layout.extend({
|
||||
itemViewContainer : '.x-series-seasons',
|
||||
template : 'Series/Details/SeriesDetailsTemplate',
|
||||
|
||||
regions : {
|
||||
seasons : '#seasons',
|
||||
info : '#info'
|
||||
},
|
||||
|
||||
ui : {
|
||||
header : '.x-header',
|
||||
monitored : '.x-monitored',
|
||||
edit : '.x-edit',
|
||||
refresh : '.x-refresh',
|
||||
rename : '.x-rename',
|
||||
search : '.x-search',
|
||||
poster : '.x-series-poster',
|
||||
manualSearch : '.x-manual-search'
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-episode-file-editor' : '_openEpisodeFileEditor',
|
||||
'click .x-monitored' : '_toggleMonitored',
|
||||
'click .x-edit' : '_editSeries',
|
||||
'click .x-refresh' : '_refreshSeries',
|
||||
'click .x-rename' : '_renameSeries',
|
||||
'click .x-search' : '_seriesSearch',
|
||||
'click .x-manual-search' : '_manualSearchM'
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
this.seriesCollection = SeriesCollection.clone();
|
||||
this.seriesCollection.shadowCollection.bindSignalR();
|
||||
|
||||
this.listenTo(this.model, 'change:monitored', this._setMonitoredState);
|
||||
this.listenTo(this.model, 'remove', this._seriesRemoved);
|
||||
this.listenTo(vent, vent.Events.CommandComplete, this._commandComplete);
|
||||
|
||||
this.listenTo(this.model, 'change', function(model, options) {
|
||||
if (options && options.changeSource === 'signalr') {
|
||||
this._refresh();
|
||||
}
|
||||
});
|
||||
|
||||
this.listenTo(this.model, 'change:images', this._updateImages);
|
||||
},
|
||||
|
||||
onShow : function() {
|
||||
this._showBackdrop();
|
||||
this._showSeasons();
|
||||
this._setMonitoredState();
|
||||
this._showInfo();
|
||||
},
|
||||
|
||||
onRender : function() {
|
||||
CommandController.bindToCommand({
|
||||
element : this.ui.refresh,
|
||||
command : {
|
||||
name : 'refreshSeries'
|
||||
}
|
||||
});
|
||||
CommandController.bindToCommand({
|
||||
element : this.ui.search,
|
||||
command : {
|
||||
name : 'seriesSearch'
|
||||
}
|
||||
});
|
||||
|
||||
CommandController.bindToCommand({
|
||||
element : this.ui.rename,
|
||||
command : {
|
||||
name : 'renameFiles',
|
||||
seriesId : this.model.id,
|
||||
seasonNumber : -1
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onClose : function() {
|
||||
if (this._backstrech) {
|
||||
this._backstrech.destroy();
|
||||
delete this._backstrech;
|
||||
}
|
||||
|
||||
$('body').removeClass('backdrop');
|
||||
reqres.removeHandler(reqres.Requests.GetEpisodeFileById);
|
||||
},
|
||||
|
||||
_getImage : function(type) {
|
||||
var image = _.where(this.model.get('images'), { coverType : type });
|
||||
|
||||
if (image && image[0]) {
|
||||
return image[0].url;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
|
||||
_toggleMonitored : function() {
|
||||
var savePromise = this.model.save('monitored', !this.model.get('monitored'), { wait : true });
|
||||
|
||||
this.ui.monitored.spinForPromise(savePromise);
|
||||
},
|
||||
|
||||
_setMonitoredState : function() {
|
||||
var monitored = this.model.get('monitored');
|
||||
|
||||
this.ui.monitored.removeAttr('data-idle-icon');
|
||||
this.ui.monitored.removeClass('fa-spin icon-sonarr-spinner');
|
||||
|
||||
if (monitored) {
|
||||
this.ui.monitored.addClass('icon-sonarr-monitored');
|
||||
this.ui.monitored.removeClass('icon-sonarr-unmonitored');
|
||||
this.$el.removeClass('series-not-monitored');
|
||||
} else {
|
||||
this.ui.monitored.addClass('icon-sonarr-unmonitored');
|
||||
this.ui.monitored.removeClass('icon-sonarr-monitored');
|
||||
this.$el.addClass('series-not-monitored');
|
||||
}
|
||||
},
|
||||
|
||||
_editSeries : function() {
|
||||
vent.trigger(vent.Commands.EditSeriesCommand, { series : this.model });
|
||||
},
|
||||
|
||||
_refreshSeries : function() {
|
||||
CommandController.Execute('refreshSeries', {
|
||||
name : 'refreshSeries',
|
||||
seriesId : this.model.id
|
||||
});
|
||||
},
|
||||
|
||||
_seriesRemoved : function() {
|
||||
Backbone.history.navigate('/', { trigger : true });
|
||||
},
|
||||
|
||||
_renameSeries : function() {
|
||||
vent.trigger(vent.Commands.ShowRenamePreview, { series : this.model });
|
||||
},
|
||||
|
||||
_seriesSearch : function() {
|
||||
CommandController.Execute('seriesSearch', {
|
||||
name : 'seriesSearch',
|
||||
seriesId : this.model.id
|
||||
});
|
||||
},
|
||||
|
||||
_showSeasons : function() {
|
||||
var self = this;
|
||||
|
||||
this.seasons.show(new LoadingView());
|
||||
|
||||
this.seasonCollection = new SeasonCollection(this.model.get('seasons'));
|
||||
this.episodeCollection = new EpisodeCollection({ seriesId : this.model.id }).bindSignalR();
|
||||
this.episodeFileCollection = new EpisodeFileCollection({ seriesId : this.model.id }).bindSignalR();
|
||||
|
||||
reqres.setHandler(reqres.Requests.GetEpisodeFileById, function(episodeFileId) {
|
||||
return self.episodeFileCollection.get(episodeFileId);
|
||||
});
|
||||
|
||||
reqres.setHandler(reqres.Requests.GetAlternateNameBySeasonNumber, function(seriesId, seasonNumber, sceneSeasonNumber) {
|
||||
if (self.model.get('id') !== seriesId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (sceneSeasonNumber === undefined) {
|
||||
sceneSeasonNumber = seasonNumber;
|
||||
}
|
||||
|
||||
return _.where(self.model.get('alternateTitles'),
|
||||
function(alt) {
|
||||
return alt.sceneSeasonNumber === sceneSeasonNumber || alt.seasonNumber === seasonNumber;
|
||||
});
|
||||
});
|
||||
|
||||
$.when(this.episodeCollection.fetch(), this.episodeFileCollection.fetch()).done(function() {
|
||||
var seasonCollectionView = new SeasonCollectionView({
|
||||
collection : self.seasonCollection,
|
||||
episodeCollection : self.episodeCollection,
|
||||
series : self.model
|
||||
});
|
||||
|
||||
if (!self.isClosed) {
|
||||
self.seasons.show(seasonCollectionView);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_showInfo : function() {
|
||||
this.info.show(new InfoView({
|
||||
model : this.model,
|
||||
episodeFileCollection : this.episodeFileCollection
|
||||
}));
|
||||
},
|
||||
|
||||
_commandComplete : function(options) {
|
||||
if (options.command.get('name') === 'renamefiles') {
|
||||
if (options.command.get('seriesId') === this.model.get('id')) {
|
||||
this._refresh();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_refresh : function() {
|
||||
this.seasonCollection.add(this.model.get('seasons'), { merge : true });
|
||||
this.episodeCollection.fetch();
|
||||
this.episodeFileCollection.fetch();
|
||||
|
||||
this._setMonitoredState();
|
||||
this._showInfo();
|
||||
},
|
||||
|
||||
_openEpisodeFileEditor : function() {
|
||||
var view = new EpisodeFileEditorLayout({
|
||||
series : this.model,
|
||||
episodeCollection : this.episodeCollection
|
||||
});
|
||||
|
||||
vent.trigger(vent.Commands.OpenModalCommand, view);
|
||||
},
|
||||
|
||||
_updateImages : function () {
|
||||
var poster = this._getImage('poster');
|
||||
|
||||
if (poster) {
|
||||
this.ui.poster.attr('src', poster);
|
||||
}
|
||||
|
||||
this._showBackdrop();
|
||||
},
|
||||
|
||||
_showBackdrop : function () {
|
||||
$('body').addClass('backdrop');
|
||||
var fanArt = this._getImage('fanart');
|
||||
|
||||
if (fanArt) {
|
||||
this._backstrech = $.backstretch(fanArt);
|
||||
} else {
|
||||
$('body').removeClass('backdrop');
|
||||
}
|
||||
},
|
||||
|
||||
_manualSearchM : function() {
|
||||
console.warn("Manual Search started");
|
||||
console.warn(this.model.get("seriesId"));
|
||||
console.warn(this.model);
|
||||
console.warn(this.episodeCollection);
|
||||
vent.trigger(vent.Commands.ShowEpisodeDetails, {
|
||||
episode : this.episodeCollection.models[0],
|
||||
hideSeriesLink : true,
|
||||
openingTab : 'search'
|
||||
});
|
||||
}
|
||||
});
|
@ -1,38 +0,0 @@
|
||||
<div class="row series-page-header">
|
||||
<div class="visible-lg col-lg-2 poster">
|
||||
{{poster}}
|
||||
</div>
|
||||
<div class="col-md-12 col-lg-10">
|
||||
<div>
|
||||
<h1 class="header-text">
|
||||
<i class="x-monitored" title="Toggle monitored state for movie"/>
|
||||
{{title}}
|
||||
<div class="series-actions pull-right">
|
||||
<div class="x-episode-file-editor">
|
||||
<i class="icon-sonarr-episode-file" title="Modify episode files for movie"/>
|
||||
</div>
|
||||
<div class="x-refresh">
|
||||
<i class="icon-sonarr-refresh icon-can-spin" title="Update movie info and scan disk"/>
|
||||
</div>
|
||||
<div class="x-rename">
|
||||
<i class="icon-sonarr-rename" title="Preview rename for all episodes"/>
|
||||
</div>
|
||||
<div class="x-search">
|
||||
<i class="icon-sonarr-search" title="Search for movie"/>
|
||||
</div>
|
||||
<div class="x-manual-search">
|
||||
<i class="icon-sonarr-search-manual" title="Manual Search"/>
|
||||
</div>
|
||||
<div class="x-edit">
|
||||
<i class="icon-sonarr-edit" title="Edit movie"/>
|
||||
</div>
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="series-detail-overview">
|
||||
{{overview}}
|
||||
</div>
|
||||
<div id="info" class="series-info"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="seasons"></div>
|
@ -1,54 +0,0 @@
|
||||
var vent = require('vent');
|
||||
var Marionette = require('marionette');
|
||||
var Profiles = require('../../Profile/ProfileCollection');
|
||||
var AsModelBoundView = require('../../Mixins/AsModelBoundView');
|
||||
var AsValidatedView = require('../../Mixins/AsValidatedView');
|
||||
var AsEditModalView = require('../../Mixins/AsEditModalView');
|
||||
require('../../Mixins/TagInput');
|
||||
require('../../Mixins/FileBrowser');
|
||||
|
||||
var view = Marionette.ItemView.extend({
|
||||
template : 'Series/Edit/EditSeriesViewTemplate',
|
||||
|
||||
ui : {
|
||||
profile : '.x-profile',
|
||||
path : '.x-path',
|
||||
tags : '.x-tags'
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-remove' : '_removeSeries'
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
this.model.set('profiles', Profiles);
|
||||
},
|
||||
|
||||
onRender : function() {
|
||||
this.ui.path.fileBrowser();
|
||||
this.ui.tags.tagInput({
|
||||
model : this.model,
|
||||
property : 'tags'
|
||||
});
|
||||
},
|
||||
|
||||
_onBeforeSave : function() {
|
||||
var profileId = this.ui.profile.val();
|
||||
this.model.set({ profileId : profileId });
|
||||
},
|
||||
|
||||
_onAfterSave : function() {
|
||||
this.trigger('saved');
|
||||
vent.trigger(vent.Commands.CloseModalCommand);
|
||||
},
|
||||
|
||||
_removeSeries : function() {
|
||||
vent.trigger(vent.Commands.DeleteSeriesCommand, { series : this.model });
|
||||
}
|
||||
});
|
||||
|
||||
AsModelBoundView.call(view);
|
||||
AsValidatedView.call(view);
|
||||
AsEditModalView.call(view);
|
||||
|
||||
module.exports = view;
|
@ -1,104 +0,0 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>{{title}}</h3>
|
||||
</div>
|
||||
<div class="modal-body edit-series-modal">
|
||||
<div class="row">
|
||||
<div class="col-sm-3 hidden-xs">
|
||||
{{poster}}
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<div class="form-horizontal">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">Monitored</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<label class="checkbox toggle well">
|
||||
<input type="checkbox" name="monitored"/>
|
||||
<p>
|
||||
<span>Yes</span>
|
||||
<span>No</span>
|
||||
</p>
|
||||
|
||||
<div class="btn btn-primary slide-button"/>
|
||||
</label>
|
||||
|
||||
<span class="help-inline-checkbox">
|
||||
<i class="icon-sonarr-form-info" title="Should Radarr download episodes for this series?"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">Use Season Folder</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<label class="checkbox toggle well">
|
||||
<input type="checkbox" name="seasonFolder"/>
|
||||
<p>
|
||||
<span>Yes</span>
|
||||
<span>No</span>
|
||||
</p>
|
||||
|
||||
<div class="btn btn-primary slide-button"/>
|
||||
</label>
|
||||
|
||||
<span class="help-inline-checkbox">
|
||||
<i class="icon-sonarr-form-info" title="Should downloaded episodes be stored in season folders?"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">Profile</label>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<select class="form-control x-profile" id="inputProfile" name="profileId">
|
||||
{{#each profiles.models}}
|
||||
<option value="{{id}}">{{attributes.name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">Series Type</label>
|
||||
<div class="col-sm-4">
|
||||
{{> SeriesTypeSelectionPartial}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">Path</label>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<input type="text" class="form-control x-path" placeholder="Path" name="path">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">Tags</label>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<input type="text" class="form-control x-tags">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-danger pull-left x-remove">Delete</button>
|
||||
|
||||
<span class="indicator x-indicator"><i class="icon-sonarr-spinner fa-spin"></i></span>
|
||||
<button class="btn" data-dismiss="modal">Cancel</button>
|
||||
<button class="btn btn-primary x-save">Save</button>
|
||||
</div>
|
||||
</div>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user