parent
0b278c7db8
commit
40d7590f80
Binary file not shown.
Binary file not shown.
@ -0,0 +1,22 @@
|
|||||||
|
var Backbone = require('backbone');
|
||||||
|
var MovieModel = require('../Movies/MovieModel');
|
||||||
|
var _ = require('underscore');
|
||||||
|
|
||||||
|
module.exports = Backbone.Collection.extend({
|
||||||
|
url : window.NzbDrone.ApiRoot + '/movies/lookup',
|
||||||
|
model : MovieModel,
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,53 @@
|
|||||||
|
var vent = require('vent');
|
||||||
|
var AppLayout = require('../AppLayout');
|
||||||
|
var Marionette = require('marionette');
|
||||||
|
var RootFolderLayout = require('./RootFolders/RootFolderLayout');
|
||||||
|
//var ExistingMoviesCollectionView = require('./Existing/AddExistingSeriesCollectionView');
|
||||||
|
var AddMoviesView = require('./AddMoviesView');
|
||||||
|
var ProfileCollection = require('../Profile/ProfileCollection');
|
||||||
|
var RootFolderCollection = require('./RootFolders/RootFolderCollection');
|
||||||
|
require('../Movies/MoviesCollection');
|
||||||
|
|
||||||
|
module.exports = Marionette.Layout.extend({
|
||||||
|
template : 'AddMovies/AddMoviesLayoutTemplate',
|
||||||
|
|
||||||
|
regions : {
|
||||||
|
workspace : '#add-movies-workspace'
|
||||||
|
},
|
||||||
|
|
||||||
|
events : {
|
||||||
|
'click .x-import' : '_importMovies',
|
||||||
|
'click .x-add-new' : '_addMovies'
|
||||||
|
},
|
||||||
|
|
||||||
|
attributes : {
|
||||||
|
id : 'add-movies-screen'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize : function() {
|
||||||
|
ProfileCollection.fetch();
|
||||||
|
RootFolderCollection.fetch().done(function() {
|
||||||
|
RootFolderCollection.synced = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow : function() {
|
||||||
|
this.workspace.show(new AddMoviesView());
|
||||||
|
},
|
||||||
|
|
||||||
|
_folderSelected : function(options) {
|
||||||
|
//vent.trigger(vent.Commands.CloseModalCommand);
|
||||||
|
//TODO: Fix this shit.
|
||||||
|
//this.workspace.show(new ExistingMoviesCollectionView({ model : options.model }));
|
||||||
|
},
|
||||||
|
|
||||||
|
_importMovies : function() {
|
||||||
|
this.rootFolderLayout = new RootFolderLayout();
|
||||||
|
this.listenTo(this.rootFolderLayout, 'folderSelected', this._folderSelected);
|
||||||
|
AppLayout.modalRegion.show(this.rootFolderLayout);
|
||||||
|
},
|
||||||
|
|
||||||
|
_addMovies : function() {
|
||||||
|
this.workspace.show(new AddMoviesView());
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,16 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="btn-group add-movies-btn-group btn-group-lg btn-block">
|
||||||
|
<button type="button" class="btn btn-default col-md-10 col-xs-8 add-movies-import-btn x-import">
|
||||||
|
<i class="icon-sonarr-hdd"/>
|
||||||
|
Import existing movies 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-movies-workspace"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,183 @@
|
|||||||
|
var _ = require('underscore');
|
||||||
|
var vent = require('vent');
|
||||||
|
var Marionette = require('marionette');
|
||||||
|
var AddMoviesCollection = require('./AddMoviesCollection');
|
||||||
|
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 : 'AddMovies/AddMoviesViewTemplate',
|
||||||
|
|
||||||
|
regions : {
|
||||||
|
searchResult : '#search-result'
|
||||||
|
},
|
||||||
|
|
||||||
|
ui : {
|
||||||
|
moviesSearch : '.x-movies-search',
|
||||||
|
searchBar : '.x-search-bar',
|
||||||
|
loadMore : '.x-load-more'
|
||||||
|
},
|
||||||
|
|
||||||
|
events : {
|
||||||
|
'click .x-load-more' : '_onLoadMore'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize : function(options) {
|
||||||
|
console.log(options)
|
||||||
|
this.isExisting = options.isExisting;
|
||||||
|
this.collection = new AddMoviesCollection();
|
||||||
|
|
||||||
|
if (this.isExisting) {
|
||||||
|
this.collection.unmappedFolderModel = this.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isExisting) {
|
||||||
|
this.className = 'existing-movies';
|
||||||
|
} else {
|
||||||
|
this.className = 'new-movies';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.listenTo(vent, vent.Events.MoviesAdded, this._onMoviesAdded);
|
||||||
|
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.moviesSearch.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.moviesSearch.val()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this._clearResults();
|
||||||
|
|
||||||
|
if (this.isExisting) {
|
||||||
|
this.ui.searchBar.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow : function() {
|
||||||
|
this.ui.moviesSearch.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;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onMoviesAdded : function(options) {
|
||||||
|
if (this.isExisting && options.movies.get('path') === this.model.get('folder').path) {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (!this.isExisting) {
|
||||||
|
this.collection.term = '';
|
||||||
|
this.collection.reset();
|
||||||
|
this._clearResults();
|
||||||
|
this.ui.moviesSearch.val('');
|
||||||
|
this.ui.moviesSearch.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 = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,24 @@
|
|||||||
|
{{#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-movies-search">
|
||||||
|
<span class="input-group-addon"><i class="icon-sonarr-search"/></span>
|
||||||
|
|
||||||
|
{{#if folder}}
|
||||||
|
<input type="text" class="form-control x-movies-search" value="{{folder.name}}">
|
||||||
|
{{else}}
|
||||||
|
<input type="text" class="form-control x-movies-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-movies-loadmore x-load-more" style="display: none;">
|
||||||
|
<i class="icon-sonarr-load-more"/>
|
||||||
|
more
|
||||||
|
</div>
|
@ -0,0 +1,5 @@
|
|||||||
|
var Marionette = require('marionette');
|
||||||
|
|
||||||
|
module.exports = Marionette.CompositeView.extend({
|
||||||
|
template : 'AddMovies/EmptyViewTemplate'
|
||||||
|
});
|
@ -0,0 +1,3 @@
|
|||||||
|
<div class="text-center hint col-md-12">
|
||||||
|
<span>You can also search by imdbid using the imdb: prefixes.</span>
|
||||||
|
</div>
|
@ -0,0 +1,13 @@
|
|||||||
|
var Marionette = require('marionette');
|
||||||
|
|
||||||
|
module.exports = Marionette.CompositeView.extend({
|
||||||
|
template : 'AddMovies/ErrorViewTemplate',
|
||||||
|
|
||||||
|
initialize : function(options) {
|
||||||
|
this.options = options;
|
||||||
|
},
|
||||||
|
|
||||||
|
templateHelpers : function() {
|
||||||
|
return this.options;
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,7 @@
|
|||||||
|
<div class="text-center col-md-12">
|
||||||
|
<h3>
|
||||||
|
There was an error searching for '{{term}}'.
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
If the movie title contains non-alphanumeric characters try removing them, otherwise try your search again later.
|
||||||
|
</div>
|
@ -0,0 +1,51 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
@ -0,0 +1,5 @@
|
|||||||
|
<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>
|
@ -0,0 +1,20 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,3 @@
|
|||||||
|
var Backbone = require('backbone');
|
||||||
|
|
||||||
|
module.exports = Backbone.Model.extend({});
|
@ -0,0 +1,18 @@
|
|||||||
|
<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>
|
@ -0,0 +1,3 @@
|
|||||||
|
<select class="form-control col-md-2 x-movie-type" name="movieType">
|
||||||
|
<option value="standard">Standard</option>
|
||||||
|
</select>
|
@ -0,0 +1,13 @@
|
|||||||
|
var Marionette = require('marionette');
|
||||||
|
|
||||||
|
module.exports = Marionette.CompositeView.extend({
|
||||||
|
template : 'AddMovies/NotFoundViewTemplate',
|
||||||
|
|
||||||
|
initialize : function(options) {
|
||||||
|
this.options = options;
|
||||||
|
},
|
||||||
|
|
||||||
|
templateHelpers : function() {
|
||||||
|
return this.options;
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,7 @@
|
|||||||
|
<div class="text-center col-md-12">
|
||||||
|
<h3>
|
||||||
|
Sorry. We couldn't find any movies 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>
|
@ -0,0 +1,10 @@
|
|||||||
|
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();
|
@ -0,0 +1,8 @@
|
|||||||
|
var Marionette = require('marionette');
|
||||||
|
var RootFolderItemView = require('./RootFolderItemView');
|
||||||
|
|
||||||
|
module.exports = Marionette.CompositeView.extend({
|
||||||
|
template : 'AddSeries/RootFolders/RootFolderCollectionViewTemplate',
|
||||||
|
itemViewContainer : '.x-root-folders',
|
||||||
|
itemView : RootFolderItemView
|
||||||
|
});
|
@ -0,0 +1,13 @@
|
|||||||
|
<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>
|
@ -0,0 +1,28 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,9 @@
|
|||||||
|
<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>
|
@ -0,0 +1,77 @@
|
|||||||
|
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;
|
@ -0,0 +1,8 @@
|
|||||||
|
var Backbone = require('backbone');
|
||||||
|
|
||||||
|
module.exports = Backbone.Model.extend({
|
||||||
|
urlRoot : window.NzbDrone.ApiRoot + '/rootfolder',
|
||||||
|
defaults : {
|
||||||
|
freeSpace : 0
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,11 @@
|
|||||||
|
<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>
|
||||||
|
|
@ -0,0 +1,29 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,272 @@
|
|||||||
|
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 MoviesCollection = require('../Movies/MoviesCollection');
|
||||||
|
var Config = require('../Config');
|
||||||
|
var Messenger = require('../Shared/Messenger');
|
||||||
|
var AsValidatedView = require('../Mixins/AsValidatedView');
|
||||||
|
|
||||||
|
require('jquery.dotdotdot');
|
||||||
|
|
||||||
|
var view = Marionette.ItemView.extend({
|
||||||
|
|
||||||
|
template : 'AddMovies/SearchResultViewTemplate',
|
||||||
|
|
||||||
|
ui : {
|
||||||
|
profile : '.x-profile',
|
||||||
|
rootFolder : '.x-root-folder',
|
||||||
|
seasonFolder : '.x-season-folder',
|
||||||
|
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-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 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.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('AddMovies/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 existingMovies = MoviesCollection.where({ imdbId : this.model.get('imdbId') });
|
||||||
|
console.log(existingMovies)
|
||||||
|
if (existingMovies.length > 0) {
|
||||||
|
this.templateHelpers.existing = existingMovies[0].toJSON();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.templateHelpers.profiles = Profiles.toJSON();
|
||||||
|
console.log(this.model)
|
||||||
|
console.log(this.templateHelpers.existing)
|
||||||
|
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.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);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_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._addMovies(true);
|
||||||
|
},
|
||||||
|
|
||||||
|
_addAndSearch : function() {
|
||||||
|
this._addMovies(true);
|
||||||
|
},
|
||||||
|
|
||||||
|
_addMovies : 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 options = this._getAddMoviesOptions();
|
||||||
|
options.searchForMissingEpisodes = searchForMissingEpisodes;
|
||||||
|
|
||||||
|
this.model.set({
|
||||||
|
profileId : profile,
|
||||||
|
rootFolderPath : rootFolderPath,
|
||||||
|
addOptions : options,
|
||||||
|
monitored : true
|
||||||
|
}, { silent : true });
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var promise = this.model.save();
|
||||||
|
|
||||||
|
console.log(this.model.save);
|
||||||
|
console.log(promise);
|
||||||
|
|
||||||
|
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() {
|
||||||
|
MoviesCollection.add(self.model);
|
||||||
|
|
||||||
|
self.close();
|
||||||
|
|
||||||
|
Messenger.show({
|
||||||
|
message : 'Added: ' + self.model.get('title'),
|
||||||
|
actions : {
|
||||||
|
goToSeries : {
|
||||||
|
label : 'Go to Movie',
|
||||||
|
action : function() {
|
||||||
|
Backbone.history.navigate('/movies/' + self.model.get('titleSlug'), { trigger : true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hideAfter : 8,
|
||||||
|
hideOnNavigate : true
|
||||||
|
});
|
||||||
|
|
||||||
|
vent.trigger(vent.Events.MoviesAdded, { movie : self.model });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_rootFoldersUpdated : function() {
|
||||||
|
this._configureTemplateHelpers();
|
||||||
|
this.render();
|
||||||
|
},
|
||||||
|
|
||||||
|
_getAddMoviesOptions : function() {
|
||||||
|
var monitor = this.ui.monitor.val();
|
||||||
|
|
||||||
|
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;
|
@ -0,0 +1,101 @@
|
|||||||
|
<div class="search-item {{#unless isExisting}}search-item-new{{/unless}}">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-2">
|
||||||
|
<a href="{{imdbUrl}}" target="_blank">
|
||||||
|
{{poster}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h2 class="movies-title">
|
||||||
|
{{titleWithYear}}
|
||||||
|
|
||||||
|
<span class="labels">
|
||||||
|
<span class="label label-default">{{network}}</span>
|
||||||
|
{{#unless_eq status compare="announced"}}
|
||||||
|
<span class="label label-danger">Released</span> <!-- TODO: Better handling of cases here! -->
|
||||||
|
{{/unless_eq}}
|
||||||
|
</span>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row new-movies-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="missing">Missing</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>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}}
|
||||||
|
|
||||||
|
{{#unless existing}}
|
||||||
|
{{#if title}}
|
||||||
|
<div class="form-group col-md-2">
|
||||||
|
<!--Uncomment if we need to add even more controls to add Movies-->
|
||||||
|
<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}}
|
||||||
|
<label style="visibility: hidden">Add</label>
|
||||||
|
<div class="col-md-2" title="Movies require an English title">
|
||||||
|
<button class="btn add-movies disabled">
|
||||||
|
Add
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{else}}
|
||||||
|
<label style="visibility: hidden">Add</label>
|
||||||
|
<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>
|
@ -0,0 +1,13 @@
|
|||||||
|
<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>
|
@ -0,0 +1,177 @@
|
|||||||
|
@import "../Shared/Styles/card.less";
|
||||||
|
@import "../Shared/Styles/clickable.less";
|
||||||
|
|
||||||
|
#add-movies-screen {
|
||||||
|
.existing-movies {
|
||||||
|
|
||||||
|
.card();
|
||||||
|
margin : 30px 0px;
|
||||||
|
|
||||||
|
.unmapped-folder-path {
|
||||||
|
padding: 20px;
|
||||||
|
margin-left : 0px;
|
||||||
|
font-weight : 100;
|
||||||
|
font-size : 25px;
|
||||||
|
text-align : center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-movies-loadmore {
|
||||||
|
font-size : 30px;
|
||||||
|
font-weight : 300;
|
||||||
|
padding-top : 10px;
|
||||||
|
padding-bottom : 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-movies {
|
||||||
|
.search-item {
|
||||||
|
.card();
|
||||||
|
margin : 40px 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-movies-search {
|
||||||
|
margin-top : 20px;
|
||||||
|
margin-bottom : 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-item {
|
||||||
|
|
||||||
|
padding-bottom : 20px;
|
||||||
|
|
||||||
|
.btn-group{
|
||||||
|
display: table;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movies-title {
|
||||||
|
margin-top : 5px;
|
||||||
|
|
||||||
|
.labels {
|
||||||
|
margin-left : 10px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size : 12px;
|
||||||
|
vertical-align : middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.year {
|
||||||
|
font-style : italic;
|
||||||
|
color : #aaaaaa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-movies-overview {
|
||||||
|
overflow : hidden;
|
||||||
|
height : 103px;
|
||||||
|
|
||||||
|
.overview-internal {
|
||||||
|
overflow : hidden;
|
||||||
|
height : 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.movies-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 : 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add {
|
||||||
|
i {
|
||||||
|
&:before {
|
||||||
|
color : #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-tooltip {
|
||||||
|
margin-left : 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-folders {
|
||||||
|
margin : 30px 0px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
color : #999999;
|
||||||
|
font-style : italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-tooltip-contents {
|
||||||
|
padding-bottom : 0px;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
var Backbone = require('backbone');
|
||||||
|
var _ = require('underscore');
|
||||||
|
|
||||||
|
module.exports = Backbone.Model.extend({
|
||||||
|
urlRoot : window.NzbDrone.ApiRoot + '/movies',
|
||||||
|
|
||||||
|
defaults : {
|
||||||
|
episodeFileCount : 0,
|
||||||
|
episodeCount : 0,
|
||||||
|
isExisting : false,
|
||||||
|
status : 0
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,120 @@
|
|||||||
|
var _ = require('underscore');
|
||||||
|
var Backbone = require('backbone');
|
||||||
|
var PageableCollection = require('backbone.pageable');
|
||||||
|
var MovieModel = require('./MovieModel');
|
||||||
|
var ApiData = require('../Shared/ApiData');
|
||||||
|
var AsFilteredCollection = require('../Mixins/AsFilteredCollection');
|
||||||
|
var AsSortedCollection = require('../Mixins/AsSortedCollection');
|
||||||
|
var AsPersistedStateCollection = require('../Mixins/AsPersistedStateCollection');
|
||||||
|
var moment = require('moment');
|
||||||
|
require('../Mixins/backbone.signalr.mixin');
|
||||||
|
|
||||||
|
var Collection = PageableCollection.extend({
|
||||||
|
url : window.NzbDrone.ApiRoot + '/movies',
|
||||||
|
model : MovieModel,
|
||||||
|
tableName : 'movies',
|
||||||
|
|
||||||
|
state : {
|
||||||
|
sortKey : 'sortTitle',
|
||||||
|
order : -1,
|
||||||
|
pageSize : 100000,
|
||||||
|
secondarySortKey : 'sortTitle',
|
||||||
|
secondarySortOrder : -1
|
||||||
|
},
|
||||||
|
|
||||||
|
mode : 'client',
|
||||||
|
|
||||||
|
save : function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var proxy = _.extend(new Backbone.Model(), {
|
||||||
|
id : '',
|
||||||
|
|
||||||
|
url : self.url + '/editor',
|
||||||
|
|
||||||
|
toJSON : function() {
|
||||||
|
return self.filter(function(model) {
|
||||||
|
return model.edited;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.listenTo(proxy, 'sync', function(proxyModel, models) {
|
||||||
|
this.add(models, { merge : true });
|
||||||
|
this.trigger('save', this);
|
||||||
|
});
|
||||||
|
|
||||||
|
return proxy.save();
|
||||||
|
},
|
||||||
|
|
||||||
|
filterModes : {
|
||||||
|
'all' : [
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
],
|
||||||
|
'continuing' : [
|
||||||
|
'status',
|
||||||
|
'continuing'
|
||||||
|
],
|
||||||
|
'ended' : [
|
||||||
|
'status',
|
||||||
|
'ended'
|
||||||
|
],
|
||||||
|
'monitored' : [
|
||||||
|
'monitored',
|
||||||
|
true
|
||||||
|
],
|
||||||
|
'missing' : [
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
function(model) { return model.get('episodeCount') !== model.get('episodeFileCount'); }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
sortMappings : {
|
||||||
|
title : {
|
||||||
|
sortKey : 'sortTitle'
|
||||||
|
},
|
||||||
|
|
||||||
|
nextAiring : {
|
||||||
|
sortValue : function(model, attr, order) {
|
||||||
|
var nextAiring = model.get(attr);
|
||||||
|
|
||||||
|
if (nextAiring) {
|
||||||
|
return moment(nextAiring).unix();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (order === 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Number.MAX_VALUE;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
percentOfEpisodes : {
|
||||||
|
sortValue : function(model, attr) {
|
||||||
|
var percentOfEpisodes = model.get(attr);
|
||||||
|
var episodeCount = model.get('episodeCount');
|
||||||
|
|
||||||
|
return percentOfEpisodes + episodeCount / 1000000;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
path : {
|
||||||
|
sortValue : function(model) {
|
||||||
|
var path = model.get('path');
|
||||||
|
|
||||||
|
return path.toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Collection = AsFilteredCollection.call(Collection);
|
||||||
|
Collection = AsSortedCollection.call(Collection);
|
||||||
|
Collection = AsPersistedStateCollection.call(Collection);
|
||||||
|
|
||||||
|
var data = ApiData.get('series');
|
||||||
|
|
||||||
|
module.exports = new Collection(data, { full : true }).bindSignalR();
|
Loading…
Reference in new issue