diff --git a/couchpotato/core/media/_base/library/main.py b/couchpotato/core/media/_base/library/main.py old mode 100644 new mode 100755 index b90f4c38..b565d16e --- a/couchpotato/core/media/_base/library/main.py +++ b/couchpotato/core/media/_base/library/main.py @@ -11,10 +11,13 @@ class Library(LibraryBase): def __init__(self): addEvent('library.title', self.title) addEvent('library.related', self.related) + addEvent('library.tree', self.tree) + addEvent('library.root', self.root) addApiView('library.query', self.queryView) addApiView('library.related', self.relatedView) + addApiView('library.tree', self.treeView) def queryView(self, media_id, **kwargs): db = get_db() @@ -32,6 +35,14 @@ class Library(LibraryBase): 'result': fireEvent('library.related', media, single = True) } + def treeView(self, media_id, **kwargs): + db = get_db() + media = db.get('id', media_id) + + return { + 'result': fireEvent('library.tree', media, single = True) + } + def title(self, library): return fireEvent( 'library.query', @@ -52,7 +63,9 @@ class Library(LibraryBase): while cur and cur.get('parent_id'): cur = db.get('id', cur['parent_id']) - result[cur['type']] = cur + parts = cur['type'].split('.') + + result[parts[-1]] = cur return result @@ -64,3 +77,28 @@ class Library(LibraryBase): cur = db.get('id', cur['parent_id']) return cur + + def tree(self, media): + result = media + + db = get_db() + items = db.get_many('media_children', media['_id'], with_doc = True) + + keys = [] + + for item in items: + parts = item['doc']['type'].split('.') + key = parts[-1] + 's' + + if key not in result: + result[key] = {} + + if key not in keys: + keys.append(key) + + result[key][item['_id']] = fireEvent('library.tree', item['doc'], single = True) + + for key in keys: + result[key] = result[key].values() + + return result diff --git a/couchpotato/core/media/show/_base/static/1_wanted.js b/couchpotato/core/media/show/_base/static/1_wanted.js old mode 100644 new mode 100755 index e7b308bf..2400071e --- a/couchpotato/core/media/show/_base/static/1_wanted.js +++ b/couchpotato/core/media/show/_base/static/1_wanted.js @@ -12,7 +12,7 @@ Page.Shows = new Class({ if(!self.wanted){ // Wanted movies - self.wanted = new MovieList({ + self.wanted = new ShowList({ 'identifier': 'wanted', 'status': 'active', 'type': 'show', diff --git a/couchpotato/core/media/show/_base/static/episode.js b/couchpotato/core/media/show/_base/static/episode.js new file mode 100755 index 00000000..2ba18a97 --- /dev/null +++ b/couchpotato/core/media/show/_base/static/episode.js @@ -0,0 +1,71 @@ +var Episode = new Class({ + + Extends: BlockBase, + + action: {}, + + initialize: function(show, data){ + var self = this; + + self.show = show; + self.data = data; + + self.el = new Element('div.item'); + self.el_actions = new Element('div.actions'); + + self.create(); + }, + + create: function(){ + var self = this; + + self.el.set('id', 'episode_'+self.data._id); + + self.el.adopt( + new Element('span.episode', {'text': (self.data.info.number || 0)}), + new Element('span.name', {'text': self.getTitle()}), + new Element('span.firstaired', {'text': self.data.info.firstaired}) + ); + + self.el_actions.inject(self.el); + + if(self.data.identifiers && self.data.identifiers.imdb) { + new Element('a.imdb.icon2', { + 'title': 'Go to the IMDB page of ' + self.show.getTitle(), + 'href': 'http://www.imdb.com/title/' + self.data.identifiers.imdb + '/', + 'target': '_blank' + }).inject(self.el_actions); + } + + new Element('a.refresh.icon2', { + 'title': 'Refresh the episode info and do a forced search', + 'events': { + 'click': self.doRefresh.bind(self) + } + }).inject(self.el_actions); + }, + + getTitle: function(){ + var self = this; + + var title = ''; + + if(self.data.info.titles && self.data.info.titles.length > 0) { + title = self.data.info.titles[0]; + } else { + title = 'Episode ' + self.data.info.number; + } + + return title; + }, + + doRefresh: function(e) { + var self = this; + + Api.request('media.refresh', { + 'data': { + 'id': self.data._id + } + }); + } +}); \ No newline at end of file diff --git a/couchpotato/core/media/show/_base/static/list.js b/couchpotato/core/media/show/_base/static/list.js new file mode 100755 index 00000000..a32e9b7c --- /dev/null +++ b/couchpotato/core/media/show/_base/static/list.js @@ -0,0 +1,635 @@ +var ShowList = new Class({ + + Implements: [Events, Options], + + options: { + navigation: true, + limit: 50, + load_more: true, + loader: true, + menu: [], + add_new: false, + force_view: false + }, + + movies: [], + movies_added: {}, + total_movies: 0, + letters: {}, + filter: null, + + initialize: function(options){ + var self = this; + self.setOptions(options); + + self.offset = 0; + self.filter = self.options.filter || { + 'starts_with': null, + 'search': null + }; + + self.el = new Element('div.shows').adopt( + self.title = self.options.title ? new Element('h2', { + 'text': self.options.title, + 'styles': {'display': 'none'} + }) : null, + self.description = self.options.description ? new Element('div.description', { + 'html': self.options.description, + 'styles': {'display': 'none'} + }) : null, + self.movie_list = new Element('div'), + self.load_more = self.options.load_more ? new Element('a.load_more', { + 'events': { + 'click': self.loadMore.bind(self) + } + }) : null + ); + + if($(window).getSize().x <= 480 && !self.options.force_view) + self.changeView('list'); + else + self.changeView(self.getSavedView() || self.options.view || 'details'); + + self.getMovies(); + + App.on('movie.added', self.movieAdded.bind(self)); + App.on('movie.deleted', self.movieDeleted.bind(self)) + }, + + movieDeleted: function(notification){ + var self = this; + + if(self.movies_added[notification.data._id]){ + self.movies.each(function(movie){ + if(movie.get('_id') == notification.data._id){ + movie.destroy(); + delete self.movies_added[notification.data._id]; + self.setCounter(self.counter_count-1); + self.total_movies--; + } + }) + } + + self.checkIfEmpty(); + }, + + movieAdded: function(notification){ + var self = this; + + self.fireEvent('movieAdded', notification); + if(self.options.add_new && !self.movies_added[notification.data._id] && notification.data.status == self.options.status){ + window.scroll(0,0); + self.createMovie(notification.data, 'top'); + self.setCounter(self.counter_count+1); + + self.checkIfEmpty(); + } + }, + + create: function(){ + var self = this; + + // Create the alphabet nav + if(self.options.navigation) + self.createNavigation(); + + if(self.options.load_more) + self.scrollspy = new ScrollSpy({ + min: function(){ + var c = self.load_more.getCoordinates(); + return c.top - window.document.getSize().y - 300 + }, + onEnter: self.loadMore.bind(self) + }); + + self.created = true; + }, + + addMovies: function(movies, total){ + var self = this; + + if(!self.created) self.create(); + + // do scrollspy + if(movies.length < self.options.limit && self.scrollspy){ + self.load_more.hide(); + self.scrollspy.stop(); + } + + Object.each(movies, function(movie){ + self.createMovie(movie); + }); + + self.total_movies += total; + self.setCounter(total); + + }, + + setCounter: function(count){ + var self = this; + + if(!self.navigation_counter) return; + + self.counter_count = count; + self.navigation_counter.set('text', (count || 0) + ' movies'); + + if (self.empty_message) { + self.empty_message.destroy(); + self.empty_message = null; + } + + if(self.total_movies && count == 0 && !self.empty_message){ + var message = (self.filter.search ? 'for "'+self.filter.search+'"' : '') + + (self.filter.starts_with ? ' in '+self.filter.starts_with+'' : ''); + + self.empty_message = new Element('.message', { + 'html': 'No movies found ' + message + '.
' + }).grab( + new Element('a', { + 'text': 'Reset filter', + 'events': { + 'click': function(){ + self.filter = { + 'starts_with': null, + 'search': null + }; + self.navigation_search_input.set('value', ''); + self.reset(); + self.activateLetter(); + self.getMovies(true); + self.last_search_value = ''; + } + } + }) + ).inject(self.movie_list); + + } + + }, + + createMovie: function(movie, inject_at){ + var self = this; + var m = new Show(self, { + 'actions': self.options.actions, + 'view': self.current_view, + 'onSelect': self.calculateSelected.bind(self) + }, movie); + + $(m).inject(self.movie_list, inject_at || 'bottom'); + + m.fireEvent('injected'); + + self.movies.include(m); + self.movies_added[movie._id] = true; + }, + + createNavigation: function(){ + var self = this; + var chars = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + self.el.addClass('with_navigation'); + + self.navigation = new Element('div.alph_nav').adopt( + 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) + } + }) + ), + new Element('div.refresh').adopt( + new Element('span[text=or]'), + new Element('a.button.green', { + 'text': 'Refresh', + 'events': { + 'click': self.refreshSelected.bind(self) + } + }) + ) + ), + new Element('div.menus').adopt( + self.navigation_counter = new Element('span.counter[title=Total]'), + self.filter_menu = new Block.Menu(self, { + 'class': 'filter' + }), + self.navigation_actions = new Element('ul.actions', { + 'events': { + 'click:relay(li)': function(e, el){ + var a = 'active'; + self.navigation_actions.getElements('.'+a).removeClass(a); + self.changeView(el.get('data-view')); + this.addClass(a); + + el.inject(el.getParent(), 'top'); + el.getSiblings().hide(); + setTimeout(function(){ + el.getSiblings().setStyle('display', null); + }, 100) + } + } + }), + self.navigation_menu = new Block.Menu(self, { + 'class': 'extra' + }) + ) + ).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.get('_id'), + 'text': profile.get('label') + }).inject(self.mass_edit_quality) + }); + + self.filter_menu.addLink( + self.navigation_search_input = new Element('input', { + 'title': 'Search through ' + self.options.identifier, + 'placeholder': 'Search through ' + self.options.identifier, + 'events': { + 'keyup': self.search.bind(self), + 'change': self.search.bind(self) + } + }) + ).addClass('search'); + + var available_chars; + self.filter_menu.addEvent('open', function(){ + self.navigation_search_input.focus(); + + // Get available chars and highlight + if(!available_chars && (self.navigation.isDisplayed() || self.navigation.isVisible())) + Api.request('media.available_chars', { + 'data': Object.merge({ + 'status': self.options.status + }, self.filter), + 'onSuccess': function(json){ + available_chars = json.chars; + + available_chars.each(function(c){ + self.letters[c.capitalize()].addClass('available') + }) + + } + }); + }); + + self.filter_menu.addLink( + self.navigation_alpha = new Element('ul.numbers', { + 'events': { + 'click:relay(li.available)': function(e, el){ + self.activateLetter(el.get('data-letter')); + self.getMovies(true) + } + } + }) + ); + + // Actions + ['mass_edit', 'details', 'list'].each(function(view){ + var current = self.current_view == view; + new Element('li', { + 'class': 'icon2 ' + view + (current ? ' active ' : ''), + 'data-view': view + }).inject(self.navigation_actions, current ? 'top' : 'bottom'); + }); + + // All + self.letters['all'] = new Element('li.letter_all.available.active', { + 'text': 'ALL' + }).inject(self.navigation_alpha); + + // Chars + chars.split('').each(function(c){ + self.letters[c] = new Element('li', { + 'text': c, + 'class': 'letter_'+c, + 'data-letter': c + }).inject(self.navigation_alpha); + }); + + // Add menu or hide + if (self.options.menu.length > 0) + self.options.menu.each(function(menu_item){ + self.navigation_menu.addLink(menu_item); + }); + else + self.navigation_menu.hide(); + + }, + + 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, + ids = self.getSelectedMovies(), + help_msg = self.identifier == 'wanted' ? 'If you do, you won\'t be able to watch them, as they won\'t get downloaded!' : 'Your files will be safe, this will only delete the reference from the CouchPotato manage list'; + + var qObj = new Question('Are you sure you want to delete '+ids.length+' movie'+ (ids.length != 1 ? 's' : '') +'?', help_msg, [{ + 'text': 'Yes, delete '+(ids.length != 1 ? 'them' : 'it'), + 'class': 'delete', + 'events': { + 'click': function(e){ + (e).preventDefault(); + this.set('text', 'Deleting..'); + Api.request('media.delete', { + 'method': 'post', + 'data': { + 'id': ids.join(','), + 'delete_from': self.options.identifier + }, + 'onSuccess': function(){ + qObj.close(); + + var erase_movies = []; + self.movies.each(function(movie){ + if (movie.isSelected()){ + $(movie).destroy(); + erase_movies.include(movie); + } + }); + + erase_movies.each(function(movie){ + self.movies.erase(movie); + movie.destroy(); + self.setCounter(self.counter_count-1); + self.total_movies--; + }); + + self.calculateSelected(); + } + }); + + } + } + }, { + 'text': 'Cancel', + 'cancel': true + }]); + + }, + + changeQualitySelected: function(){ + var self = this; + var ids = self.getSelectedMovies(); + + Api.request('movie.edit', { + 'method': 'post', + 'data': { + 'id': ids.join(','), + 'profile_id': self.mass_edit_quality.get('value') + }, + 'onSuccess': self.search.bind(self) + }); + }, + + refreshSelected: function(){ + var self = this; + var ids = self.getSelectedMovies(); + + Api.request('media.refresh', { + 'method': 'post', + 'data': { + 'id': ids.join(',') + } + }); + }, + + 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.movies = []; + if(self.mass_edit_select) + self.calculateSelected(); + if(self.navigation_alpha) + self.navigation_alpha.getElements('.active').removeClass('active'); + + self.offset = 0; + if(self.scrollspy){ + //self.load_more.show(); + self.scrollspy.start(); + } + }, + + activateLetter: function(letter){ + var self = this; + + self.reset(); + + self.letters[letter || 'all'].addClass('active'); + self.filter.starts_with = letter; + + }, + + changeView: function(new_view){ + var self = this; + + self.el + .removeClass(self.current_view+'_list') + .addClass(new_view+'_list'); + + self.current_view = new_view; + Cookie.write(self.options.identifier+'_view2', new_view, {duration: 1000}); + }, + + getSavedView: function(){ + var self = this; + return Cookie.read(self.options.identifier+'_view2'); + }, + + search: function(){ + var self = this; + + if(self.search_timer) clearTimeout(self.search_timer); + self.search_timer = (function(){ + var search_value = self.navigation_search_input.get('value'); + if (search_value == self.last_search_value) return; + + self.reset(); + + self.activateLetter(); + self.filter.search = search_value; + + self.getMovies(true); + + self.last_search_value = search_value; + + }).delay(250); + + }, + + update: function(){ + var self = this; + + self.reset(); + self.getMovies(true); + }, + + getMovies: function(reset){ + var self = this; + + if(self.scrollspy){ + self.scrollspy.stop(); + self.load_more.set('text', 'loading...'); + } + + if(self.movies.length == 0 && self.options.loader){ + + self.loader_first = new Element('div.loading').adopt( + new Element('div.message', {'text': self.options.title ? 'Loading \'' + self.options.title + '\'' : 'Loading...'}) + ).inject(self.el, 'top'); + + createSpinner(self.loader_first, { + radius: 4, + length: 4, + width: 1 + }); + + self.el.setStyle('min-height', 93); + + } + + Api.request(self.options.api_call || 'media.list', { + 'data': Object.merge({ + 'type': self.options.type || 'movie', + 'status': self.options.status, + 'limit_offset': self.options.limit ? self.options.limit + ',' + self.offset : null + }, self.filter), + 'onSuccess': function(json){ + + if(reset) + self.movie_list.empty(); + + if(self.loader_first){ + var lf = self.loader_first; + self.loader_first.addClass('hide'); + self.loader_first = null; + setTimeout(function(){ + lf.destroy(); + }, 20000); + self.el.setStyle('min-height', null); + } + + self.store(json.movies); + self.addMovies(json.movies, json.total || json.movies.length); + if(self.scrollspy) { + self.load_more.set('text', 'load more movies'); + self.scrollspy.start(); + } + + self.checkIfEmpty(); + self.fireEvent('loaded'); + } + }); + }, + + loadMore: function(){ + var self = this; + if(self.offset >= self.options.limit) + self.getMovies() + }, + + store: function(movies){ + var self = this; + + self.offset += movies.length; + + }, + + checkIfEmpty: function(){ + var self = this; + + var is_empty = self.movies.length == 0 && (self.total_movies == 0 || self.total_movies === undefined); + + if(self.title) + self.title[is_empty ? 'hide' : 'show'](); + + if(self.description) + self.description.setStyle('display', [is_empty ? 'none' : '']); + + if(is_empty && self.options.on_empty_element){ + self.options.on_empty_element.inject(self.loader_first || self.title || self.movie_list, 'after'); + + if(self.navigation) + self.navigation.hide(); + + self.empty_element = self.options.on_empty_element; + } + else if(self.empty_element){ + self.empty_element.destroy(); + + if(self.navigation) + self.navigation.show(); + } + + }, + + toElement: function(){ + return this.el; + } + +}); diff --git a/couchpotato/core/media/show/_base/static/show.css b/couchpotato/core/media/show/_base/static/show.css new file mode 100755 index 00000000..14dc462d --- /dev/null +++ b/couchpotato/core/media/show/_base/static/show.css @@ -0,0 +1,1077 @@ +.shows { + padding: 10px 0 20px; + position: relative; + z-index: 3; + width: 100%; +} + + .shows > div { + clear: both; + } + + .shows > div .message { + display: block; + padding: 20px; + font-size: 20px; + color: white; + text-align: center; + } + .shows > div .message a { + padding: 20px; + display: block; + } + + .shows.thumbs_list > div:not(.description) { + margin-right: -4px; + } + + .shows .loading { + display: block; + padding: 20px 0 0 0; + width: 100%; + z-index: 3; + transition: all .4s cubic-bezier(0.9,0,0.1,1); + height: 40px; + opacity: 1; + position: absolute; + text-align: center; + } + .shows .loading.hide { + height: 0; + padding: 0; + opacity: 0; + margin-top: -20px; + overflow: hidden; + } + + .shows .loading .spinner { + display: inline-block; + } + + .shows .loading .message { + margin: 0 20px; + } + + .shows h2 { + margin-bottom: 20px; + } + + @media all and (max-width: 480px) { + .shows h2 { + font-size: 25px; + margin-bottom: 10px; + } + } + + .shows > .description { + position: absolute; + top: 30px; + right: 0; + font-style: italic; + opacity: 0.8; + } + .shows:hover > .description { + opacity: 1; + } + + @media all and (max-width: 860px) { + .shows > .description { + display: none; + } + } + + .shows.thumbs_list { + padding: 20px 0 20px; + } + + .home .shows { + padding-top: 6px; + } + + .shows .show { + position: relative; + margin: 10px 0; + padding-left: 20px; + overflow: hidden; + width: 100%; + height: 180px; + transition: all 0.6s cubic-bezier(0.9,0,0.1,1); + transition-property: width, height; + background: rgba(0,0,0,.2); + } + + .shows .show.expanded { + height: 360px; + } + + .shows .show .table.expanded { + height: 360px; + } + + .shows.mass_edit_list .show { + padding-left: 22px; + background: none; + } + + .shows.details_list .show { + padding-left: 120px; + } + + .shows.list_list .show:not(.details_view), + .shows.mass_edit_list .show { + height: 30px; + border-bottom: 1px solid rgba(255,255,255,.15); + } + + .shows.list_list .show:last-child, + .shows.mass_edit_list .show:last-child { + border: none; + } + + .shows.thumbs_list .show { + width: 16.66667%; + height: auto; + min-height: 200px; + display: inline-block; + margin: 0; + padding: 0; + vertical-align: top; + line-height: 0; + } + + @media all and (max-width: 800px) { + .shows.thumbs_list .show { + width: 25%; + min-height: 100px; + } + } + + .shows .show .mask { + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + } + + .shows.list_list .show:not(.details_view), + .shows.mass_edit_list .show { + margin: 0; + } + + .shows .data { + padding: 20px; + height: 100%; + width: 100%; + position: relative; + transition: all .6s cubic-bezier(0.9,0,0.1,1); + right: 0; + } + .shows.list_list .show:not(.details_view) .data, + .shows.mass_edit_list .show .data { + padding: 0 0 0 10px; + border: 0; + background: #4e5969; + } + .shows.mass_edit_list .show .data { + padding-left: 8px; + } + + .shows.thumbs_list .data { + position: absolute; + left: 0; + top: 0; + width: 100%; + padding: 10px; + height: 100%; + background: none; + transition: none; + } + + .shows.thumbs_list .show:hover .data { + background: rgba(0,0,0,0.9); + } + + .shows .data.hide_right { + right: -100%; + } + + .shows .show .check { + display: none; + } + + .shows.mass_edit_list .show .check { + position: absolute; + left: 0; + top: 0; + display: block; + margin: 7px 0 0 5px; + } + + .shows .poster { + position: absolute; + left: 0; + width: 120px; + height: 180px; + line-height: 0; + overflow: hidden; + transition: all .6s cubic-bezier(0.9,0,0.1,1); + background: rgba(0,0,0,.1); + } + .shows.thumbs_list .poster { + position: relative; + } + .shows.list_list .show:not(.details_view) .poster, + .shows.mass_edit_list .poster { + width: 20px; + height: 30px; + } + .shows.mass_edit_list .poster { + display: none; + } + + .shows.thumbs_list .poster { + width: 100%; + height: 100%; + transition: none; + background: no-repeat center; + background-size: cover; + } + .shows.thumbs_list .no_thumbnail .empty_file { + width: 100%; + height: 100%; + } + + .shows .poster img, + .options .poster img { + width: 100%; + height: 100%; + } + .shows.thumbs_list .poster img { + height: auto; + width: 100%; + top: 0; + bottom: 0; + opacity: 0; + } + + .shows .info { + position: relative; + height: 100%; + width: 100%; + } + + .shows .info .title { + font-size: 28px; + font-weight: bold; + margin-bottom: 10px; + margin-top: 2px; + width: 100%; + padding-right: 80px; + transition: all 0.2s linear; + height: 35px; + top: -5px; + position: relative; + } + .shows.list_list .info .title, + .shows.mass_edit_list .info .title { + height: 100%; + top: 0; + margin: 0; + } + .touch_enabled .shows.list_list .info .title { + display: inline-block; + padding-right: 55px; + } + + .shows .info .title a { + display: inline-block; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + width: 100%; + height: 100%; + line-height: 30px; + color: rgb(255, 255, 255); + } + + .shows .info .title a:hover { + color: rgba(255, 255, 255, 0.6); + } + + .shows.thumbs_list .info .title a { + white-space: normal; + overflow: auto; + height: auto; + text-align: left; + } + + @media all and (max-width: 480px) { + .shows.thumbs_list .show .info .title a, + .shows.thumbs_list .show .info .year { + font-size: 15px; + line-height: 15px; + overflow: hidden; + } + } + + .shows.list_list .show:not(.details_view) .info .title, + .shows.mass_edit_list .info .title { + font-size: 16px; + font-weight: normal; + width: auto; + } + + .shows.thumbs_list .show:not(.no_thumbnail) .info { + display: none; + } + .shows.thumbs_list .show:hover .info { + display: block; + } + + .shows.thumbs_list .info .title { + font-size: 21px; + word-wrap: break-word; + padding: 0; + height: 100%; + } + + .shows .info .year { + position: absolute; + color: #bbb; + right: 0; + top: 6px; + text-align: right; + transition: all 0.2s linear; + font-weight: normal; + } + .shows.list_list .show:not(.details_view) .info .year, + .shows.mass_edit_list .info .year { + font-size: 1.25em; + right: 10px; + } + + .shows.thumbs_list .info .year { + font-size: 23px; + margin: 0; + bottom: 0; + left: 0; + top: auto; + right: auto; + color: #FFF; + line-height: 18px; + } + + .touch_enabled .shows.list_list .show .info .year { + font-size: 1em; + } + + .shows .info .description { + top: 30px; + clear: both; + bottom: 30px; + position: absolute; + } + .shows.list_list .show:not(.details_view) .info .description, + .shows.mass_edit_list .info .description, + .shows.thumbs_list .info .description { + display: none; + } + + .shows .data .quality { + position: absolute; + bottom: 2px; + display: block; + min-height: 20px; + } + + .shows.list_list .show:hover .data .quality { + display: none; + } + + .touch_enabled .shows.list_list .show .data .quality { + position: relative; + display: inline-block; + margin: 0; + top: -4px; + } + + @media all and (max-width: 480px) { + .shows .data .quality { + display: none; + } + } + + .shows .status_suggest .data .quality, + .shows.thumbs_list .data .quality { + display: none; + } + + .shows .data .quality span { + padding: 2px 3px; + opacity: 0.5; + font-size: 10px; + height: 16px; + line-height: 12px; + vertical-align: middle; + display: inline-block; + text-transform: uppercase; + font-weight: normal; + margin: 0 4px 0 0; + border-radius: 2px; + background-color: rgba(255,255,255,0.1); + } + .shows.list_list .data .quality, + .shows.mass_edit_list .data .quality { + text-align: right; + right: 0; + margin-right: 60px; + z-index: 1; + top: 5px; + } + + .shows .data .quality .available, + .shows .data .quality .snatched, + .shows .data .quality .seeding { + opacity: 1; + cursor: pointer; + } + + .shows .data .quality .available { background-color: #578bc3; } + .shows .data .quality .failed, + .shows .data .quality .missing, + .shows .data .quality .ignored { background-color: #a43d34; } + .shows .data .quality .snatched { background-color: #a2a232; } + .shows .data .quality .done { + background-color: #369545; + opacity: 1; + } + .shows .data .quality .seeding { background-color: #0a6819; } + .shows .data .quality .finish { + background-image: url('../../images/sprite.png'); + background-repeat: no-repeat; + background-position: 0 2px; + padding-left: 14px; + background-size: 14px + } + + .shows .data .actions { + position: absolute; + bottom: 17px; + right: 20px; + line-height: 0; + top: 0; + width: auto; + opacity: 0; + display: none; + } + @media all and (max-width: 480px) { + .shows .data .actions { + display: none !important; + } + } + + .shows .show:hover .data .actions, + .touch_enabled .shows .show .data .actions { + opacity: 1; + display: inline-block; + } + + .shows.details_list .data .actions { + top: auto; + bottom: 18px; + } + + .shows .show:hover .actions { + opacity: 1; + display: inline-block; + } + .shows.thumbs_list .data .actions { + bottom: 12px; + right: 10px; + top: auto; + } + + .shows .show:hover .action { opacity: 0.6; } + .shows .show:hover .action:hover { opacity: 1; } + + .shows .data .action { + display: inline-block; + height: 22px; + min-width: 33px; + padding: 0 5px; + line-height: 26px; + text-align: center; + font-size: 13px; + color: #FFF; + margin-left: 1px; + } + .shows .data .action.trailer { color: #FFF; } + .shows .data .action.download { color: #b9dec0; } + .shows .data .action.edit { color: #c6b589; } + .shows .data .action.refresh { color: #cbeecc; } + .shows .data .action.delete { color: #e9b0b0; } + .shows .data .action.directory { color: #ffed92; } + .shows .data .action.readd { color: #c2fac5; } + + .shows.mass_edit_list .show .data .actions { + display: none; + } + + .shows.list_list .show:not(.details_view):hover .actions, + .shows.mass_edit_list .show:hover .actions, + .touch_enabled .shows.list_list .show:not(.details_view) .actions { + margin: 0; + background: #4e5969; + top: 2px; + bottom: 2px; + right: 5px; + z-index: 3; + } + + .shows .delete_container { + clear: both; + text-align: center; + font-size: 20px; + position: absolute; + padding: 80px 0 0; + left: 120px; + right: 0; + } + .shows .delete_container .or { + padding: 10px; + } + .shows .delete_container .delete { + background-color: #ff321c; + font-weight: normal; + } + .shows .delete_container .delete:hover { + color: #fff; + background-color: #d32917; + } + + .shows .options { + position: absolute; + right: 0; + left: 120px; + } + + .shows .options .form { + margin: 80px 0 0; + font-size: 20px; + text-align: center; + } + + .shows .options .form select { + margin-right: 20px; + } + + .shows .options .table { + height: 180px; + overflow: auto; + line-height: 2em; + } + .shows .options .table .item { + border-bottom: 1px solid rgba(255,255,255,0.1); + } + .shows .options .table .item.ignored span, + .shows .options .table .item.failed span { + text-decoration: line-through; + color: rgba(255,255,255,0.4); + } + .shows .options .table .item.ignored .delete:before, + .shows .options .table .item.failed .delete:before { + display: inline-block; + content: "\e04b"; + transform: scale(-1, 1); + } + + .shows .options .table .item:last-child { border: 0; } + .shows .options .table .item:nth-child(even) { + background: rgba(255,255,255,0.05); + } + .shows .options .table .item:not(.head):hover { + background: rgba(255,255,255,0.03); + } + + .shows .options .table .item > * { + display: inline-block; + padding: 0 5px; + width: 60px; + min-height: 24px; + white-space: nowrap; + text-overflow: ellipsis; + text-align: center; + vertical-align: top; + border-left: 1px solid rgba(255, 255, 255, 0.1); + } + .shows .options .table .item > *:first-child { + border: 0; + } + .shows .options .table .provider { + width: 120px; + text-overflow: ellipsis; + overflow: hidden; + } + .shows .options .table .name { + width: 340px; + overflow: hidden; + text-align: left; + padding: 0 10px; + } + .shows .options .table.files .name { width: 590px; } + .shows .options .table .type { width: 130px; } + .shows .options .table .is_available { width: 90px; } + .shows .options .table .age, + .shows .options .table .size { width: 40px; } + + .shows .options .table a { + width: 30px !important; + height: 20px; + opacity: 0.8; + line-height: 25px; + } + .shows .options .table a:hover { opacity: 1; } + .shows .options .table a.download { color: #a7fbaf; } + .shows .options .table a.delete { color: #fda3a3; } + .shows .options .table .ignored a.delete, + .shows .options .table .failed a.delete { color: #b5fda3; } + + .shows .options .table .head > * { + font-weight: bold; + font-size: 14px; + padding-top: 4px; + padding-bottom: 4px; + height: auto; + } + + .trailer_container { + width: 100%; + background: #000; + text-align: center; + transition: all .6s cubic-bezier(0.9,0,0.1,1); + overflow: hidden; + left: 0; + position: absolute; + z-index: 10; + } + @media only screen and (device-width: 768px) { + .trailer_container iframe { + margin-top: 25px; + } + } + + .trailer_container.hide { + height: 0 !important; + } + + .hide_trailer { + position: absolute; + top: 0; + left: 50%; + margin-left: -50px; + width: 100px; + text-align: center; + padding: 3px 10px; + background: #4e5969; + transition: all .2s cubic-bezier(0.9,0,0.1,1) .2s; + z-index: 11; + } + .hide_trailer.hide { + top: -30px; + } + + .shows .show .episodes .item { + position: relative; + } + + .shows .show .episodes .actions { + position: absolute; + width: auto; + right: 0; + + border-left: none; + } + + .shows .show .episodes .actions .refresh { + color: #cbeecc; + } + + .shows .show .try_container { + padding: 5px 10px; + text-align: center; + } + + .shows .show .try_container a { + margin: 0 5px; + padding: 2px 5px; + } + + .shows .show .releases .next_release { + border-left: 6px solid #2aa300; + } + + .shows .show .releases .next_release > :first-child { + margin-left: -6px; + } + + .shows .show .releases .last_release { + border-left: 6px solid #ffa200; + } + + .shows .show .releases .last_release > :first-child { + margin-left: -6px; + } + .shows .show .trynext { + display: inline; + position: absolute; + right: 180px; + z-index: 2; + opacity: 0; + background: #4e5969; + text-align: right; + height: 100%; + top: 0; + } + .touch_enabled .shows .show .trynext { + display: none; + } + + @media all and (max-width: 480px) { + .shows .show .trynext { + display: none; + } + } + .shows.mass_edit_list .trynext { display: none; } + .wanted .shows .show .trynext { + padding-right: 30px; + } + .shows .show:hover .trynext, + .touch_enabled .shows.details_list .show .trynext { + opacity: 1; + } + + .shows.details_list .show .trynext { + background: #47515f; + padding: 0; + right: 0; + height: 25px; + } + + .shows .show .trynext a { + background-position: 5px center; + padding: 0 5px 0 25px; + margin-right: 10px; + color: #FFF; + height: 100%; + line-height: 27px; + font-family: OpenSans, "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif; + } + .shows .show .trynext a:before { + margin: 2px 0 0 -20px; + position: absolute; + font-family: 'Elusive-Icons'; + } + .shows.details_list .show .trynext a { + line-height: 23px; + } + .shows .show .trynext a:last-child { + margin: 0; + } + .shows .show .trynext a:hover, + .touch_enabled .shows .show .trynext a { + background-color: #369545; + } + + .shows .load_more { + display: block; + padding: 10px; + text-align: center; + font-size: 20px; + } + .shows .load_more.loading { + opacity: .5; + } + +.shows .alph_nav { + height: 44px; +} + + @media all and (max-width: 480px) { + .shows .alph_nav { + display: none; + } + } + + .shows .alph_nav .menus { + display: inline-block; + float: right; + } + +.shows .alph_nav .numbers, +.shows .alph_nav .counter, +.shows .alph_nav .actions { + list-style: none; + padding: 0 0 1px; + margin: 0; + user-select: none; +} + + .shows .alph_nav .counter { + display: inline-block; + text-align: right; + padding: 0 10px; + height: 100%; + line-height: 43px; + border-right: 1px solid rgba(255,255,255,.07); + } + + .shows .alph_nav .numbers li, + .shows .alph_nav .actions li { + display: inline-block; + vertical-align: top; + height: 100%; + line-height: 30px; + text-align: center; + border: 1px solid transparent; + transition: all 0.1s ease-in-out; + } + + .shows .alph_nav .numbers li { + width: 30px; + height: 30px; + opacity: 0.3; + } + .shows .alph_nav .numbers li.letter_all { + width: 60px; + } + + .shows .alph_nav li.available { + font-weight: bold; + cursor: pointer; + opacity: 1; + + } + .shows .alph_nav li.active.available, + .shows .alph_nav li.available:hover { + background: rgba(0,0,0,.1); + } + + .shows .alph_nav .search input { + width: 100%; + height: 44px; + display: inline-block; + border: 0; + background: none; + color: #444; + font-size: 14px; + padding: 0 10px 0 30px; + border-bottom: 1px solid rgba(0,0,0,.08); + } + .shows .alph_nav .search input:focus { + background: rgba(0,0,0,.08); + } + + .shows .alph_nav .search input::-webkit-input-placeholder { + color: #444; + opacity: .6; + } + + .shows .alph_nav .search:before { + font-family: 'Elusive-Icons'; + content: "\e03e"; + position: absolute; + height: 20px; + line-height: 45px; + font-size: 12px; + margin: 0 0 0 10px; + opacity: .6; + color: #444; + } + + .shows .alph_nav .actions { + -moz-user-select: none; + width: 44px; + height: 44px; + display: inline-block; + vertical-align: top; + z-index: 200; + position: relative; + border: 1px solid rgba(255,255,255,.07); + border-width: 0 1px; + } + .shows .alph_nav .actions:hover { + box-shadow: 0 100px 20px -10px rgba(0,0,0,0.55); + } + .shows .alph_nav .actions li { + width: 100%; + height: 45px; + line-height: 40px; + position: relative; + z-index: 20; + display: none; + cursor: pointer; + } + .shows .alph_nav .actions:hover li:not(.active) { + display: block; + background: #FFF; + color: #444; + } + .shows .alph_nav .actions li:hover:not(.active) { + background: #ccc; + } + .shows .alph_nav .actions li.active { + display: block; + } + + .shows .alph_nav .actions li.mass_edit:before { + content: "\e070"; + } + + .shows .alph_nav .actions li.list:before { + content: "\e0d8"; + } + + .shows .alph_nav .actions li.details:before { + content: "\e022"; + } + + .shows .alph_nav .mass_edit_form { + clear: both; + text-align: center; + display: none; + overflow: hidden; + float: left; + height: 44px; + line-height: 44px; + } + .shows.mass_edit_list .mass_edit_form { + display: inline-block; + } + .shows.mass_edit_list .mass_edit_form .select { + font-size: 14px; + display: inline-block; + } + .shows.mass_edit_list .mass_edit_form .select .check { + display: inline-block; + vertical-align: middle; + margin: -4px 0 0 5px; + } + .shows.mass_edit_list .mass_edit_form .select span { + opacity: 0.7; + } + .shows.mass_edit_list .mass_edit_form .select .count { + font-weight: bold; + margin: 0 3px 0 10px; + } + + .shows .alph_nav .mass_edit_form .quality { + display: inline-block; + margin: 0 0 0 16px; + } + .shows .alph_nav .mass_edit_form .quality select { + width: 120px; + margin-right: 5px; + } + .shows .alph_nav .mass_edit_form .button { + padding: 3px 7px; + } + + .shows .alph_nav .mass_edit_form .refresh, + .shows .alph_nav .mass_edit_form .delete { + display: inline-block; + margin-left: 8px; + } + + .shows .alph_nav .mass_edit_form .refresh span, + .shows .alph_nav .mass_edit_form .delete span { + margin: 0 10px 0 0; + } + + .shows .alph_nav .more_menu > a { + background: none; + } + + .shows .alph_nav .more_menu.extra > a:before { + content: '...'; + font-size: 1.7em; + line-height: 23px; + text-align: center; + display: block; + } + + .shows .alph_nav .more_menu.filter { + } + + .shows .alph_nav .more_menu.filter > a:before { + content: "\e0e8"; + font-family: 'Elusive-Icons'; + line-height: 33px; + display: block; + text-align: center; + } + + .shows .alph_nav .more_menu.filter .wrapper { + right: 88px; + width: 300px; + } + +.shows .empty_wanted { + background-image: url('../../images/emptylist.png'); + background-position: 80% 0; + height: 750px; + width: 100%; + max-width: 900px; + padding-top: 260px; +} + +.shows .empty_manage { + text-align: center; + font-size: 25px; + line-height: 150%; + padding: 40px 0; +} + + .shows .empty_manage .after_manage { + margin-top: 30px; + font-size: 16px; + } + + .shows .progress { + padding: 10px; + margin: 5px 0; + text-align: left; + } + + .shows .progress > div { + padding: 5px 10px; + font-size: 12px; + line-height: 12px; + text-align: left; + display: inline-block; + width: 49%; + background: rgba(255, 255, 255, 0.05); + margin: 2px 0.5%; + } + + .shows .progress > div .folder { + display: inline-block; + padding: 5px 20px 5px 0; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + width: 85%; + direction: ltr; + vertical-align: middle; + } + + .shows .progress > div .percentage { + display: inline-block; + text-transform: uppercase; + font-weight: normal; + font-size: 20px; + border-left: 1px solid rgba(255, 255, 255, .2); + width: 15%; + text-align: right; + vertical-align: middle; + } diff --git a/couchpotato/core/media/show/_base/static/show.episodes.js b/couchpotato/core/media/show/_base/static/show.episodes.js new file mode 100755 index 00000000..ace93af4 --- /dev/null +++ b/couchpotato/core/media/show/_base/static/show.episodes.js @@ -0,0 +1,103 @@ +var Episodes = new Class({ + initialize: function(show) { + var self = this; + + self.show = show; + }, + + open: function(){ + var self = this; + + if(!self.container){ + self.container = new Element('div.options').grab( + self.episodes_container = new Element('div.episodes.table') + ); + + self.container.inject(self.show, 'top'); + + Api.request('library.tree', { + 'data': { + 'media_id': self.show.data._id + }, + 'onComplete': function(json){ + self.data = json.result; + + self.createEpisodes(); + } + }); + } + + self.show.slide('in', self.container); + }, + + createEpisodes: function() { + var self = this; + + self.data.seasons.sort(self.sortSeasons); + self.data.seasons.each(function(season) { + self.createSeason(season); + + season.episodes.sort(self.sortEpisodes); + season.episodes.each(function(episode) { + self.createEpisode(episode); + }); + }); + }, + + createSeason: function(season) { + var self = this, + title = ''; + + if(season.info.number) { + title = 'Season ' + season.info.number; + } else { + // Season 0 / Specials + title = 'Specials'; + } + + season['el'] = new Element('div', { + 'class': 'item head', + 'id': 'season_'+season._id + }).adopt( + new Element('span.name', {'text': title}) + ).inject(self.episodes_container); + }, + + createEpisode: function(episode){ + var self = this, + e = new Episode(self.show, episode); + + $(e).inject(self.episodes_container); + }, + + sortSeasons: function(a, b) { + // Move "Specials" to the bottom of the list + if(!a.info.number) { + return 1; + } + + if(!b.info.number) { + return -1; + } + + // Order seasons descending + if(a.info.number < b.info.number) + return -1; + + if(a.info.number > b.info.number) + return 1; + + return 0; + }, + + sortEpisodes: function(a, b) { + // Order episodes descending + if(a.info.number < b.info.number) + return -1; + + if(a.info.number > b.info.number) + return 1; + + return 0; + } +}); \ No newline at end of file diff --git a/couchpotato/core/media/show/_base/static/show.js b/couchpotato/core/media/show/_base/static/show.js new file mode 100755 index 00000000..b91e637c --- /dev/null +++ b/couchpotato/core/media/show/_base/static/show.js @@ -0,0 +1,347 @@ +var Show = new Class({ + + Extends: BlockBase, + + action: {}, + + initialize: function(list, options, data){ + var self = this; + + self.data = data; + self.view = options.view || 'details'; + self.list = list; + + self.el = new Element('div.show'); + + self.episodes = new Episodes(self); + + self.profile = Quality.getProfile(data.profile_id) || {}; + self.category = CategoryList.getCategory(data.category_id) || {}; + self.parent(self, options); + + self.addEvents(); + }, + + addEvents: function(){ + var self = this; + + self.global_events = {}; + + // Do refresh with new data + self.global_events['movie.update'] = function(notification){ + if(self.data._id != notification.data._id) return; + + self.busy(false); + self.removeView(); + self.update.delay(2000, self, notification); + }; + App.on('movie.update', self.global_events['movie.update']); + + // Add spinner on load / search + ['media.busy', 'movie.searcher.started'].each(function(listener){ + self.global_events[listener] = function(notification){ + if(notification.data && (self.data._id == notification.data._id || (typeOf(notification.data._id) == 'array' && notification.data._id.indexOf(self.data._id) > -1))) + self.busy(true); + }; + App.on(listener, self.global_events[listener]); + }); + + // Remove spinner + self.global_events['movie.searcher.ended'] = function(notification){ + if(notification.data && self.data._id == notification.data._id) + self.busy(false) + }; + App.on('movie.searcher.ended', self.global_events['movie.searcher.ended']); + + // Reload when releases have updated + self.global_events['release.update_status'] = function(notification){ + var data = notification.data; + if(data && self.data._id == data.movie_id){ + + if(!self.data.releases) + self.data.releases = []; + + self.data.releases.push({'quality': data.quality, 'status': data.status}); + self.updateReleases(); + } + }; + + App.on('release.update_status', self.global_events['release.update_status']); + + }, + + destroy: function(){ + var self = this; + + self.el.destroy(); + delete self.list.movies_added[self.get('id')]; + self.list.movies.erase(self); + + self.list.checkIfEmpty(); + + // Remove events + Object.each(self.global_events, function(handle, listener){ + App.off(listener, handle); + }); + }, + + busy: function(set_busy, timeout){ + var self = this; + + if(!set_busy){ + setTimeout(function(){ + if(self.spinner){ + self.mask.fade('out'); + setTimeout(function(){ + if(self.mask) + self.mask.destroy(); + if(self.spinner) + self.spinner.el.destroy(); + self.spinner = null; + self.mask = null; + }, timeout || 400); + } + }, timeout || 1000) + } + else if(!self.spinner) { + self.createMask(); + self.spinner = createSpinner(self.mask); + self.mask.fade('in'); + } + }, + + createMask: function(){ + var self = this; + self.mask = new Element('div.mask', { + 'styles': { + 'z-index': 4 + } + }).inject(self.el, 'top').fade('hide'); + }, + + update: function(notification){ + var self = this; + + self.data = notification.data; + self.el.empty(); + self.removeView(); + + self.profile = Quality.getProfile(self.data.profile_id) || {}; + self.category = CategoryList.getCategory(self.data.category_id) || {}; + self.create(); + + self.busy(false); + }, + + create: function(){ + var self = this; + + self.el.addClass('status_'+self.get('status')); + + self.el.adopt( + self.select_checkbox = new Element('input[type=checkbox].inlay', { + 'events': { + 'change': function(){ + self.fireEvent('select') + } + } + }), + self.thumbnail = (self.data.files && self.data.files.image_poster) ? new Element('img', { + 'class': 'type_image poster', + 'src': Api.createUrl('file.cache') + self.data.files.image_poster[0].split(Api.getOption('path_sep')).pop() + }): null, + self.data_container = new Element('div.data.inlay.light').adopt( + self.info_container = new Element('div.info').adopt( + new Element('div.title').adopt( + self.title = new Element('a', { + 'events': { + 'click': function(e){ + self.episodes.open(); + } + }, + 'text': self.getTitle() || 'n/a' + }), + self.year = new Element('div.year', { + 'text': self.data.info.year || 'n/a' + }) + ), + self.description = new Element('div.description.tiny_scroll', { + 'text': self.data.info.plot + }), + self.quality = new Element('div.quality', { + 'events': { + 'click': function(e){ + var releases = self.el.getElement('.actions .releases'); + if(releases.isVisible()) + releases.fireEvent('click', [e]) + } + } + }) + ), + self.actions = new Element('div.actions') + ) + ); + + if(!self.thumbnail) + self.el.addClass('no_thumbnail'); + + //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){ + + var q = self.addQuality(type.get('quality'), type.get('3d')); + if((type.finish == true || type.get('finish')) && !q.hasClass('finish')){ + q.addClass('finish'); + q.set('title', q.get('title') + ' Will finish searching for this movie if this quality is found.') + } + + }); + + // Add releases + self.updateReleases(); + + Object.each(self.options.actions, function(action, key){ + self.action[key.toLowerCase()] = action = new self.options.actions[key](self); + if(action.el) + self.actions.adopt(action) + }); + + }, + + updateReleases: function(){ + var self = this; + if(!self.data.releases || self.data.releases.length == 0) return; + + self.data.releases.each(function(release){ + + var q = self.quality.getElement('.q_'+ release.quality+(release.is_3d ? '.is_3d' : ':not(.is_3d)')), + status = release.status; + + if(!q && (status == 'snatched' || status == 'seeding' || status == 'done')) + q = self.addQuality(release.quality, release.is_3d || false); + + if (q && !q.hasClass(status)){ + q.addClass(status); + q.set('title', (q.get('title') ? q.get('title') : '') + ' status: '+ status) + } + + }); + }, + + addQuality: function(quality, is_3d){ + var self = this; + + var q = Quality.getQuality(quality); + return new Element('span', { + 'text': q.label + (is_3d ? ' 3D' : ''), + 'class': 'q_'+q.identifier + (is_3d ? ' is_3d' : ''), + 'title': '' + }).inject(self.quality); + + }, + + getTitle: function(){ + var self = this; + + if(self.data.title) + return self.getUnprefixedTitle(self.data.title); + else if(self.data.info.titles.length > 0) + return self.getUnprefixedTitle(self.data.info.titles[0]); + + return 'Unknown movie' + }, + + getUnprefixedTitle: function(t){ + if(t.substr(0, 4).toLowerCase() == 'the ') + t = t.substr(4) + ', The'; + else if(t.substr(0, 3).toLowerCase() == 'an ') + t = t.substr(3) + ', An'; + else if(t.substr(0, 2).toLowerCase() == 'a ') + t = t.substr(2) + ', A'; + return t; + }, + + slide: function(direction, el){ + var self = this; + + if(direction == 'in'){ + self.temp_view = self.view; + self.changeView('details'); + + self.el.addEvent('outerClick', function(){ + self.removeView(); + self.slide('out') + }); + el.show(); + + + self.el.addClass('expanded'); + self.el.getElements('.table').addClass('expanded'); + + self.data_container.addClass('hide_right'); + } + else { + self.el.removeEvents('outerClick'); + + setTimeout(function(){ + if(self.el) + { + self.el.getElements('> :not(.data):not(.poster):not(.movie_container)').hide(); + self.el.getElements('.table').removeClass('expanded'); + } + }, 600); + + self.el.removeClass('expanded'); + self.data_container.removeClass('hide_right'); + } + }, + + changeView: function(new_view){ + var self = this; + + if(self.el) + self.el + .removeClass(self.view+'_view') + .addClass(new_view+'_view'); + + self.view = new_view; + }, + + removeView: function(){ + var self = this; + + self.el.removeClass(self.view+'_view') + }, + + getIdentifier: function(){ + var self = this; + + try { + return self.get('identifiers').imdb; + } + catch (e){ } + + return self.get('imdb'); + }, + + get: function(attr){ + return this.data[attr] || this.data.info[attr] + }, + + select: function(bool){ + var self = this; + self.select_checkbox_class[bool ? 'check' : 'uncheck']() + }, + + isSelected: function(){ + return this.select_checkbox.get('checked'); + }, + + toElement: function(){ + return this.el; + } + +}); diff --git a/couchpotato/core/media/show/episode.py b/couchpotato/core/media/show/episode.py old mode 100644 new mode 100755 index 0f05f284..e184e900 --- a/couchpotato/core/media/show/episode.py +++ b/couchpotato/core/media/show/episode.py @@ -26,7 +26,7 @@ class Episode(MediaBase): # Add Season episode_info = { '_t': 'media', - 'type': 'episode', + 'type': 'show.episode', 'identifiers': identifiers, 'parent_id': parent_id, 'info': info, # Returned dict by providers @@ -63,7 +63,16 @@ class Episode(MediaBase): # Get new info if not info: - info = fireEvent('episode.info', episode.get('identifiers'), merge = True) + season = db.get('id', episode['parent_id']) + show = db.get('id', season['parent_id']) + + info = fireEvent( + 'episode.info', show.get('identifiers'), { + 'season_identifier': season.get('info', {}).get('number'), + 'episode_identifier': episode.get('identifiers') + }, + merge = True + ) # Update/create media if force: diff --git a/couchpotato/core/media/show/library/episode.py b/couchpotato/core/media/show/library/episode.py old mode 100644 new mode 100755 index 7161f2d2..26b5c3de --- a/couchpotato/core/media/show/library/episode.py +++ b/couchpotato/core/media/show/library/episode.py @@ -14,7 +14,7 @@ class EpisodeLibraryPlugin(LibraryBase): addEvent('library.identifier', self.identifier) def query(self, media, first = True, condense = True, include_identifier = True, **kwargs): - if media.get('type') != 'episode': + if media.get('type') != 'show.episode': return related = fireEvent('library.related', media, single = True) @@ -43,7 +43,7 @@ class EpisodeLibraryPlugin(LibraryBase): return titles def identifier(self, media): - if media.get('type') != 'episode': + if media.get('type') != 'show.episode': return identifier = { diff --git a/couchpotato/core/media/show/library/season.py b/couchpotato/core/media/show/library/season.py old mode 100644 new mode 100755 index 228d1432..89489af6 --- a/couchpotato/core/media/show/library/season.py +++ b/couchpotato/core/media/show/library/season.py @@ -14,7 +14,7 @@ class SeasonLibraryPlugin(LibraryBase): addEvent('library.identifier', self.identifier) def query(self, media, first = True, condense = True, include_identifier = True, **kwargs): - if media.get('type') != 'season': + if media.get('type') != 'show.season': return related = fireEvent('library.related', media, single = True) @@ -44,7 +44,7 @@ class SeasonLibraryPlugin(LibraryBase): return titles def identifier(self, media): - if media.get('type') != 'season': + if media.get('type') != 'show.season': return return { diff --git a/couchpotato/core/media/show/providers/info/thetvdb.py b/couchpotato/core/media/show/providers/info/thetvdb.py index b2e58d96..e57057c3 100755 --- a/couchpotato/core/media/show/providers/info/thetvdb.py +++ b/couchpotato/core/media/show/providers/info/thetvdb.py @@ -172,15 +172,16 @@ class TheTVDb(ShowProvider): """Either return a list of all episodes or a single episode. If episode_identifer contains an episode number to search for """ - season_identifier = params.get('season_identifier', None) - episode_identifier = params.get('episode_identifier', None) + season_identifier = self.getIdentifier(params.get('season_identifier', None)) + episode_identifier = self.getIdentifier(params.get('episode_identifier', None)) + identifier = self.getIdentifier(identifier) if not identifier and season_identifier is None: return False # season_identifier must contain the 'show id : season number' since there is no tvdb id # for season and we need a reference to both the show id and season number - if season_identifier: + if not identifier and season_identifier: try: identifier, season_identifier = season_identifier.split(':') season_identifier = int(season_identifier) @@ -205,15 +206,21 @@ class TheTVDb(ShowProvider): for episode in season.values(): if episode_identifier is not None and episode['id'] == toUnicode(episode_identifier): - result = self._parseEpisode(show, episode) + result = self._parseEpisode(episode) self.setCache(cache_key, result) return result else: - result.append(self._parseEpisode(show, episode)) + result.append(self._parseEpisode(episode)) self.setCache(cache_key, result) return result + def getIdentifier(self, value): + if type(value) is dict: + return value.get('thetvdb') + + return value + def _parseShow(self, show): # diff --git a/couchpotato/core/media/show/searcher/episode.py b/couchpotato/core/media/show/searcher/episode.py old mode 100644 new mode 100755 index 1e6b253c..ace9768e --- a/couchpotato/core/media/show/searcher/episode.py +++ b/couchpotato/core/media/show/searcher/episode.py @@ -116,7 +116,7 @@ class EpisodeSearcher(SearcherBase, ShowTypeBase): log.info2('Too early to search for %s, %s', (too_early_to_search, query)) def correctRelease(self, release = None, media = None, quality = None, **kwargs): - if media.get('type') != 'episode': + if media.get('type') != 'show.episode': return retention = Env.setting('retention', section = 'nzb') diff --git a/couchpotato/core/media/show/season.py b/couchpotato/core/media/show/season.py old mode 100644 new mode 100755 index a2dde780..6197c9ca --- a/couchpotato/core/media/show/season.py +++ b/couchpotato/core/media/show/season.py @@ -28,7 +28,7 @@ class Season(MediaBase): # Add Season season_info = { '_t': 'media', - 'type': 'season', + 'type': 'show.season', 'identifiers': identifiers, 'parent_id': parent_id, 'info': info, # Returned dict by providers