Mass editing of movies

List movie view
This commit is contained in:
Ruud
2012-02-26 23:19:53 +01:00
parent c8dc03a78e
commit 17d431a9e1
5 changed files with 425 additions and 56 deletions
+20 -14
View File
@@ -69,7 +69,7 @@ class MoviePlugin(Plugin):
addApiView('movie.edit', self.edit, docs = {
'desc': 'Add new movie to the wanted list',
'params': {
'id': {'desc': 'Movie ID you want to edit'},
'id': {'desc': 'Movie ID(s) you want to edit.', 'type': 'int (comma separated)'},
'profile_id': {'desc': 'ID of quality profile you want the edit the movie to.'},
'default_title': {'desc': 'Movie title to use for searches. Has to be one of the titles returned by movie.search.'},
}
@@ -77,7 +77,7 @@ class MoviePlugin(Plugin):
addApiView('movie.delete', self.delete, docs = {
'desc': 'Delete a movie from the wanted list',
'params': {
'id': {'desc': 'Movie ID you want to delete'},
'id': {'desc': 'Movie ID(s) you want to delete.', 'type': 'int (comma separated)'},
}
})
@@ -301,19 +301,23 @@ class MoviePlugin(Plugin):
params = getParams()
db = get_session()
m = db.query(Movie).filter_by(id = params.get('id')).first()
m.profile_id = params.get('profile_id')
ids = params.get('id').split(',')
for movie_id in ids:
# Default title
for title in m.library.titles:
title.default = params.get('default_title').lower() == title.title.lower()
m = db.query(Movie).filter_by(id = movie_id).first()
m.profile_id = params.get('profile_id')
db.commit()
# Default title
if params.get('default_title'):
for title in m.library.titles:
title.default = params.get('default_title').lower() == title.title.lower()
fireEvent('movie.restatus', m.id)
db.commit()
movie_dict = m.to_dict(self.default_dict)
fireEventAsync('searcher.single', movie_dict)
fireEvent('movie.restatus', m.id)
movie_dict = m.to_dict(self.default_dict)
fireEventAsync('searcher.single', movie_dict)
return jsonified({
'success': True,
@@ -326,9 +330,11 @@ class MoviePlugin(Plugin):
status = fireEvent('status.add', 'deleted', single = True)
movie = db.query(Movie).filter_by(id = params.get('id')).first()
movie.status_id = status.get('id')
db.commit()
ids = params.get('id').split(',')
for movie_id in ids:
movie = db.query(Movie).filter_by(id = movie_id).first()
movie.status_id = status.get('id')
db.commit()
return jsonified({
'success': True,
+187 -14
View File
@@ -3,7 +3,7 @@ var MovieList = new Class({
Implements: [Options],
options: {
navigation: false,
navigation: true,
limit: 50
},
@@ -76,11 +76,15 @@ var MovieList = new Class({
var actions = a[info.status.identifier.capitalize()] || a.Wanted || {};
var m = new Movie(self, {
'actions': actions
'actions': actions,
'view': self.current_view,
'onSelect': self.calculateSelected.bind(self)
}, info);
$(m).inject(self.movie_list);
m.fireEvent('injected');
self.movies.include(m)
});
},
@@ -89,8 +93,12 @@ var MovieList = new Class({
var self = this;
var chars = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ';
self.current_view = self.getSavedView();
self.el.addClass(self.current_view+'_list')
self.navigation = new Element('div.alph_nav').adopt(
self.alpha = new Element('ul.inlay', {
self.navigation_actions = new Element('ul.inlay.actions.reversed'),
self.navigation_alpha = new Element('ul.inlay.numbers', {
'events': {
'click:relay(li)': function(e, el){
self.movie_list.empty()
@@ -99,24 +107,73 @@ var MovieList = new Class({
}
}
}),
self.search_input = new Element('input.inlay', {
self.navigation_search_input = new Element('input.inlay', {
'placeholder': 'Search',
'events': {
'keyup': self.search.bind(self),
'change': self.search.bind(self)
}
})/*,
self.view = new Element('ul.inlay').adopt(
new Element('li.list'),
new Element('li.thumbnails'),
new Element('li.text')
)*/
}),
self.mass_edit_form = new Element('div.mass_edit_form').adopt(
new Element('span.select').adopt(
self.mass_edit_select = new Element('input[type=checkbox].inlay', {
'events': {
'change': self.massEditToggleAll.bind(self)
}
}),
self.mass_edit_selected = new Element('span.count', {'text': 0}),
self.mass_edit_selected_label = new Element('span', {'text': 'selected'})
),
new Element('div.quality').adopt(
self.mass_edit_quality = new Element('select'),
new Element('a.button.orange', {
'text': 'Change quality',
'events': {
'click': self.changeQualitySelected.bind(self)
}
})
),
new Element('div.delete').adopt(
new Element('span[text=or]'),
new Element('a.button.red', {
'text': 'Delete',
'events': {
'click': self.deleteSelected.bind(self)
}
})
)
)
).inject(self.el, 'top');
// Mass edit
self.mass_edit_select_class = new Form.Check(self.mass_edit_select);
Quality.getActiveProfiles().each(function(profile){
new Element('option', {
'value': profile.id ? profile.id : profile.data.id,
'text': profile.label ? profile.label : profile.data.label
}).inject(self.mass_edit_quality)
});
// Actions
['mass_edit', 'thumbs', 'list'].each(function(view){
self.navigation_actions.adopt(
new Element('li.'+view+(self.current_view == view ? '.active' : '')+'[data-view='+view+']', {
'events': {
'click': function(e){
var a = 'active';
self.navigation_actions.getElements('.'+a).removeClass(a);
self.changeView(this.get('data-view'));
this.addClass(a);
}
}
}).adopt(new Element('span'))
)
});
// All
self.letters['all'] = new Element('li.letter_all.available.active', {
'text': 'ALL',
}).inject(self.alpha);
}).inject(self.navigation_alpha);
// Chars
chars.split('').each(function(c){
@@ -124,7 +181,7 @@ var MovieList = new Class({
'text': c,
'class': 'letter_'+c,
'data-letter': c
}).inject(self.alpha);
}).inject(self.navigation_alpha);
});
// Get available chars and highlight
@@ -153,10 +210,106 @@ var MovieList = new Class({
},
calculateSelected: function(){
var self = this;
var selected = 0,
movies = self.movies.length;
self.movies.each(function(movie){
selected += movie.isSelected() ? 1 : 0
})
var indeterminate = selected > 0 && selected < movies,
checked = selected == movies && selected > 0;
self.mass_edit_select.set('indeterminate', indeterminate)
self.mass_edit_select_class[checked ? 'check' : 'uncheck']()
self.mass_edit_select_class.element[indeterminate ? 'addClass' : 'removeClass']('indeterminate')
self.mass_edit_selected.set('text', selected);
},
deleteSelected: function(){
var self = this;
var ids = self.getSelectedMovies()
var qObj = new Question('Are you sure you want to delete the selected movies?', 'Items using this profile, will be set to the default quality.', [{
'text': 'Yes, delete them',
'class': 'delete',
'events': {
'click': function(e){
(e).stop();
Api.request('movie.delete', {
'data': {
'id': ids.join(',')
},
'onSuccess': function(){
qObj.close();
self.movies.each(function(movie){
if (movie.isSelected()){
$(movie).destroy()
self.movies.erase(movie)
}
});
self.calculateSelected()
}
});
}
}
}, {
'text': 'Cancel',
'cancel': true
}]);
},
changeQualitySelected: function(){
var self = this;
var ids = self.getSelectedMovies()
Api.request('movie.edit', {
'data': {
'id': ids.join(','),
'profile_id': self.mass_edit_quality.get('value')
},
'onSuccess': self.search.bind(self)
});
},
getSelectedMovies: function(){
var self = this;
var ids = []
self.movies.each(function(movie){
if (movie.isSelected())
ids.include(movie.get('id'))
});
return ids
},
massEditToggleAll: function(){
var self = this;
var select = self.mass_edit_select.get('checked');
self.movies.each(function(movie){
movie.select(select)
});
self.calculateSelected()
},
reset: function(){
var self = this;
self.navigation.getElements('.active').removeClass('active')
self.movies = []
self.calculateSelected()
self.navigation_alpha.getElements('.active').removeClass('active')
self.offset = 0;
self.load_more.show();
self.scrollspy.start();
@@ -172,12 +325,32 @@ var MovieList = new Class({
},
changeView: function(new_view){
var self = this;
self.movies.each(function(movie){
movie.changeView(new_view)
});
self.el
.removeClass(self.current_view+'_list')
.addClass(new_view+'_list')
self.current_view = new_view;
Cookie.write(self.options.identifier+'_view', new_view, {duration: 1000});
},
getSavedView: function(){
var self = this;
return Cookie.read(self.options.identifier+'_view') || 'thumb';
},
search: function(){
var self = this;
if(self.search_timer) clearTimeout(self.search_timer);
self.search_timer = (function(){
var search_value = self.search_input.get('value');
var search_value = self.navigation_search_input.get('value');
if (search_value == self.last_search_value) return
self.reset()
+175 -21
View File
@@ -5,31 +5,61 @@
*/
.movies {
padding: 50px 0 20px;
padding: 60px 0 20px;
}
.movies.mass_edit_list {
padding-top: 90px;
}
.movies .movie {
position: relative;
border-radius: 4px;
margin: 10px 0;
overflow: hidden;
width: 100%;
transition: all 0.2s linear;
}
.movies .movie:hover {
border-color: #ddd #fff #fff #ddd;
.movies .movie.list_view, .movies .movie.mass_edit_view {
margin: 1px 0;
border-radius: 0;
background: no-repeat;
box-shadow: none;
border-bottom: 1px solid rgba(255,255,255,0.05);
}
.movies .movie.list_view:hover, .movies .movie.mass_edit_view:hover {
background: rgba(255,255,255,0.03);
}
.movies .data {
padding: 20px;
height: 180px;
width: 840px;
position: relative;
float: right;
border-radius: 0;
-moz-border-radius: 0;
-webkit-border-radius: 0;
overflow: hidden;
transition: all 0.2s linear;
}
.movies .list_view .data, .movies .mass_edit_view .data {
height: 30px;
padding: 3px 10px;
width: 938px;
box-shadow: none;
border: 0;
background: none;
}
.movies .movie .check {
display: none;
}
.movies.mass_edit_list .movie .check {
float: left;
display: block;
margin: 7px 0 0 5px;
}
.movies .poster {
float: left;
width: 120px;
@@ -37,8 +67,17 @@
overflow: hidden;
height: 180px;
border-radius: 4px 0 0 4px;
transition: all 0.2s linear;
}
.movies .list_view .poster, .movies .mass_edit_view .poster {
width: 20px;
height: 30px;
}
.movies.mass_edit_list .poster {
display: none;
}
.movies .poster img, .options .poster img {
width: 101%;
height: 101%;
@@ -49,8 +88,14 @@
font-weight: bold;
margin-bottom: 10px;
float: left;
width: 80%;
width: 50%;
transition: all 0.2s linear;
overflow: hidden;
}
.movies .list_view .info .title, .movies .mass_edit_view .info .title {
font-size: 16px;
font-weight: normal;
}
.movies .info .year {
font-size: 30px;
@@ -59,7 +104,12 @@
color: #bbb;
width: 10%;
text-align: right;
transition: all 0.2s linear;
}
.movies .list_view .info .year, .movies .mass_edit_view .info .year {
font-size: 16px;
width: 6%;
}
.movies .info .rating {
font-size: 30px;
@@ -78,12 +128,20 @@
.movies .data:hover .description {
overflow: auto;
}
.movies .list_view .info .description, .movies .mass_edit_view .info .description {
display: none;
}
.movies .data .quality span {
padding: 0 5px;
font-weight: bold;
}
.movies .data .quality span:first-child {padding-left: 0;}
.movies .list_view .data .quality, .movies .mass_edit_view .data .quality {
text-align: right;
float: right;
width: 35%;
}
.movies .data .quality .available { color: orange; }
.movies .data .quality .snatched { color: lightgreen; }
@@ -95,7 +153,10 @@
margin-top: -25px;
}
.movies .data:hover .action { opacity: 0.6; }
.movies .data:hover .action:hover { opacity: 1; }
.movies .data:hover .action:hover { opacity: 1; }
.movies.mass_edit_list .data .actions {
display: none;
}
.movies .data .action {
background-repeat: no-repeat;
@@ -106,6 +167,11 @@
padding: 3px;
opacity: 0;
}
.movies .list_view .data:hover .actions, .movies .mass_edit_view .data:hover .actions {
margin: -35px -7px 0 0;
background: #4e5969;
}
.movies .delete_container {
clear: both;
@@ -183,9 +249,9 @@
text-align: left;
padding: 0 10px;
}
.movies .options .table.files .name { width: 598px; }
.movies .options .table .type { width: 120px; }
.movies .options .table .is_available { width: 80px; }
.movies .options .table.files .name { width: 608px; }
.movies .options .table .type { width: 130px; }
.movies .options .table .is_available { width: 90px; }
.movies .options .table a {
width: 30px !important;
@@ -220,17 +286,18 @@
position: fixed;
z-index: 2;
top: 0;
padding: 100px 7px 7px;
margin: -7px;
width: 960px;
padding: 100px 60px 7px;
width: 1082px;
margin: 0 -60px;
box-shadow: 0 20px 20px -22px rgba(0,0,0,0.1);
}
.movies .alph_nav.float {
box-shadow: 0 0 10px rgba(0,0,0,0.4);
border-radius: 4px;
box-shadow: 0 30px 30px -32px rgba(0,0,0,0.5);
border-radius: 0;
background: #4e5969;
}
.movies .alph_nav ul {
list-style: none;
padding: 0 0 1px;
@@ -250,7 +317,7 @@
color: #666;
border: 1px solid transparent;
}
.movies .alph_nav li:first-child {
.movies .alph_nav .numbers li:first-child {
width: 34px;
}
.movies .alph_nav li.active, .movies .alph_nav li:hover {
@@ -265,4 +332,91 @@
padding: 6px 5px;
margin: 0;
float: right;
}
width: 155px;
height: 25px;
float: right;
}
.movies .alph_nav .actions {
margin: 0 32px 0 0;
-moz-user-select: none;
}
.movies .alph_nav .actions li {
border-radius: 1px;
width: auto;
}
.movies .alph_nav .actions li.active {
background: none;
border: 1px solid transparent;
box-shadow: none;
}
.movies .alph_nav .actions li span {
display: block;
background: url('../images/sprite.png') no-repeat;
width: 25px;
height: 100%;
}
.movies .alph_nav .actions li.mass_edit span {
background-position: 3px 3px;
}
.movies .alph_nav .actions li.list span {
background-position: 3px -95px;
}
.movies .alph_nav .actions li.thumbs span {
background-position: 3px -74px;
}
.movies .alph_nav .actions li:first-child {
border-radius: 3px 0 0 3px;
}
.movies .alph_nav .actions li:last-child {
border-radius: 0 3px 3px 0;
}
.movies .alph_nav .mass_edit_form {
clear: both;
text-align: center;
display: none;
}
.movies.mass_edit_list .mass_edit_form {
display: block;
}
.movies.mass_edit_list .mass_edit_form .select {
float: left;
margin: 5px 0 0 5px;
font-size: 14px;
}
.movies.mass_edit_list .mass_edit_form .select span {
vertical-align: middle;
opacity: 0.7;
}
.movies.mass_edit_list .mass_edit_form .select .count {
font-weight: bold;
margin: 0 3px 0 10px;
}
.movies .alph_nav .mass_edit_form .quality {
float: left;
padding: 8px 0 0;
margin: 0 0 0 16px;
}
.movies .alph_nav .mass_edit_form .quality select {
width: 120px;
margin-right: 5px;
}
.movies .alph_nav .mass_edit_form .button {
padding: 3px 7px;
}
.movies .alph_nav .mass_edit_form .delete {
float: left;
padding: 8px 0 0 8px;
}
.movies .alph_nav .mass_edit_form .delete span {
margin: 0 10px 0 0;
}
+37 -1
View File
@@ -8,6 +8,7 @@ var Movie = new Class({
var self = this;
self.data = data;
self.view = options.view || 'thumb';
self.profile = Quality.getProfile(data.profile_id) || {};
self.parent(self, options);
@@ -17,6 +18,13 @@ var Movie = new Class({
var self = this;
self.el = new Element('div.movie.inlay').adopt(
self.select_checkbox = new Element('input[type=checkbox].inlay', {
'events': {
'change': function(){
self.fireEvent('select')
}
}
}),
self.thumbnail = File.Select.single('poster', self.data.library.files),
self.data_container = new Element('div.data.inlay.light', {
'tween': {
@@ -44,6 +52,9 @@ var Movie = new Class({
)
);
self.changeView(self.view);
self.select_checkbox_class = new Form.Check(self.select_checkbox);
// Add profile
if(self.profile.data)
self.profile.getTypes().each(function(type){
@@ -108,7 +119,13 @@ var Movie = new Class({
var self = this;
if(direction == 'in'){
self.el.addEvent('outerClick', self.slide.bind(self, 'out'))
self.temp_view = self.view;
self.changeView('thumb')
self.el.addEvent('outerClick', function(){
self.changeView(self.temp_view)
self.slide('out')
})
el.show();
self.data_container.tween('right', 0, -840);
}
@@ -123,8 +140,27 @@ var Movie = new Class({
}
},
changeView: function(new_view){
var self = this;
self.el
.removeClass(self.view+'_view')
.addClass(new_view+'_view')
self.view = new_view;
},
get: function(attr){
return this.data[attr] || this.data.library[attr]
},
select: function(bool){
var self = this;
self.select_checkbox_class[bool ? 'check' : 'uncheck']()
},
isSelected: function(){
return this.select_checkbox.get('checked');
}
});
+6 -6
View File
@@ -161,11 +161,11 @@ body > .spinner, .mask{
margin: 0;
width: 100%;
z-index: 5;
box-shadow: 0 0 5px rgba(0,0,0,0.05);
box-shadow: 0 20px 30px -30px rgba(0,0,0,0.05);
transition: box-shadow .4s cubic-bezier(0.9,0,0.1,1);
}
.header.with_shadow {
box-shadow: 0 0 20px rgba(0,0,0,0.3);
box-shadow: 0 20px 30px -30px rgba(0,0,0,0.3);
}
.header > div {
@@ -342,22 +342,22 @@ body > .spinner, .mask{
color: #fff;
border: 0;
border-radius:3px;
background: #282d34;
background-color: #282d34;
box-shadow: inset 0 1px 8px rgba(0,0,0,0.25), 0 1px 0px rgba(255,255,255,0.25);
}
.inlay.light {
background: #47515f;
background-color: #47515f;
outline: none;
box-shadow: inset 0 1px 8px rgba(0,0,0,0.05), 0 1px 0px rgba(255,255,255,0.15);
}
.inlay:focus {
background: #3a4350;
background-color: #3a4350;
outline: none;
}
.onlay, .inlay .selected, .inlay > li:hover, .inlay > li.active {
.onlay, .inlay .selected, .inlay:not(.reversed) > li:hover, .inlay > li.active, .inlay.reversed > li {
border-radius:3px;
border: 1px solid #252930;
box-shadow: inset 0 1px 0px rgba(255,255,255,0.20), 0 0 3px rgba(0,0,0, 0.2);