diff --git a/couchpotato/core/media/show/_base/static/1_wanted.js b/couchpotato/core/media/show/_base/static/1_wanted.js deleted file mode 100755 index f6af814..0000000 --- a/couchpotato/core/media/show/_base/static/1_wanted.js +++ /dev/null @@ -1,59 +0,0 @@ -Page.Shows = new Class({ - - Extends: PageBase, - - name: 'shows', - title: 'List of TV Shows subscribed to', - folder_browser: null, - has_tab: false, - - toggleShows: function(arg) { - var self = this; - var nav = App.getBlock('navigation'); - - if ((typeof arg === 'object' && arg.data === true) || arg === true) { - self.tab = nav.addTab(self.name, { - 'href': App.createUrl(self.name), - 'title': self.title, - 'text': self.name.capitalize() - }); - self.has_tab = true; - } else { - self.has_tab = false; - self.tab = null; - nav.removeTab('shows'); - } - }, - - load: function() { - var self = this; - - Api.request('settings', { - 'onComplete': function(json){ - self.toggleShows(json.values.shows.enabled); - } - }); - - App.on('shows.enabled', self.toggleShows.bind(self)); - }, - - indexAction: function(){ - var self = this; - - if(!self.wanted){ - - // Wanted movies - self.wanted = new ShowList({ - 'identifier': 'wanted', - 'status': 'active', - 'type': 'show', - 'actions': [MA.IMDB, MA.Trailer, MA.Release, MA.Edit, MA.Refresh, MA.Readd, MA.Delete], - 'add_new': true, - 'on_empty_element': App.createUserscriptButtons().addClass('empty_wanted') - }); - $(self.wanted).inject(self.el); - } - - } - -}); diff --git a/couchpotato/core/media/show/_base/static/episode.actions.js b/couchpotato/core/media/show/_base/static/episode.actions.js index cc46ce3..e69de29 100755 --- a/couchpotato/core/media/show/_base/static/episode.actions.js +++ b/couchpotato/core/media/show/_base/static/episode.actions.js @@ -1,474 +0,0 @@ -var EpisodeAction = new Class({ - - Implements: [Options], - - class_name: 'item-action icon2', - - initialize: function(episode, options){ - var self = this; - self.setOptions(options); - - self.show = episode.show; - self.episode = episode; - - self.create(); - if(self.el) - self.el.addClass(self.class_name) - }, - - create: function(){}, - - disable: function(){ - if(this.el) - this.el.addClass('disable') - }, - - enable: function(){ - if(this.el) - this.el.removeClass('disable') - }, - - getTitle: function(){ - var self = this; - - try { - return self.show.getTitle(); - } - catch(e){ - try { - return self.show.original_title ? self.show.original_title : self.show.titles[0]; - } - catch(e){ - return 'Unknown'; - } - } - }, - - get: function(key){ - var self = this; - try { - return self.show.get(key) - } - catch(e){ - return self.show[key] - } - }, - - createMask: function(){ - var self = this; - self.mask = new Element('div.mask', { - 'styles': { - 'z-index': '1' - } - }).inject(self.show, 'top').fade('hide'); - }, - - toElement: function(){ - return this.el || null - } - -}); - -var EA = {}; - -EA.IMDB = new Class({ - - Extends: EpisodeAction, - id: null, - - create: function(){ - var self = this; - - self.id = self.show.getIdentifier ? self.show.getIdentifier() : self.get('imdb'); - - self.el = new Element('a.imdb', { - 'title': 'Go to the IMDB page of ' + self.getTitle(), - 'href': 'http://www.imdb.com/title/'+self.id+'/', - 'target': '_blank' - }); - - if(!self.id) self.disable(); - } - -}); - -EA.Release = new Class({ - - Extends: EpisodeAction, - - create: function(){ - var self = this; - - self.el = new Element('a.releases.download', { - 'title': 'Show the releases that are available for ' + self.getTitle(), - 'events': { - 'click': self.toggle.bind(self) - } - }); - - self.options = new Element('div.episode-options').inject(self.episode.el); - - if(!self.episode.data.releases || self.episode.data.releases.length == 0) - self.el.hide(); - else - self.showHelper(); - - App.on('show.searcher.ended', function(notification){ - if(self.show.data._id != notification.data._id) return; - - self.releases = null; - if(self.options_container){ - self.options_container.destroy(); - self.options_container = null; - } - }); - - }, - - toggle: function(e){ - var self = this; - - if(self.options && self.options.hasClass('expanded')) { - self.close(); - } else { - self.open(); - } - }, - - open: function(e){ - var self = this; - - if(e) - (e).preventDefault(); - - self.createReleases(); - - }, - - close: function(e) { - var self = this; - - if(e) - (e).preventDefault(); - - self.options.setStyle('height', 0) - .removeClass('expanded'); - }, - - createReleases: function(){ - var self = this; - - if(!self.releases_table){ - self.options.adopt( - self.releases_table = new Element('div.releases.table') - ); - - // Header - new Element('div.item.head').adopt( - new Element('span.name', {'text': 'Release name'}), - new Element('span.status', {'text': 'Status'}), - new Element('span.quality', {'text': 'Quality'}), - new Element('span.size', {'text': 'Size'}), - new Element('span.age', {'text': 'Age'}), - new Element('span.score', {'text': 'Score'}), - new Element('span.provider', {'text': 'Provider'}) - ).inject(self.releases_table); - - if(self.episode.data.releases) - self.episode.data.releases.each(function(release){ - - var quality = Quality.getQuality(release.quality) || {}, - info = release.info || {}, - provider = self.get(release, 'provider') + (info['provider_extra'] ? self.get(release, 'provider_extra') : ''); - - var release_name = self.get(release, 'name'); - if(release.files && release.files.length > 0){ - try { - var movie_file = release.files.filter(function(file){ - var type = File.Type.get(file.type_id); - return type && type.identifier == 'movie' - }).pick(); - release_name = movie_file.path.split(Api.getOption('path_sep')).getLast(); - } - catch(e){} - } - - // Create release - release['el'] = new Element('div', { - 'class': 'item '+release.status, - 'id': 'release_'+release._id - }).adopt( - new Element('span.name', {'text': release_name, 'title': release_name}), - new Element('span.status', {'text': release.status, 'class': 'status '+release.status}), - new Element('span.quality', {'text': quality.label + (release.is_3d ? ' 3D' : '') || 'n/a'}), - new Element('span.size', {'text': info['size'] ? Math.floor(self.get(release, 'size')) : 'n/a'}), - new Element('span.age', {'text': self.get(release, 'age')}), - new Element('span.score', {'text': self.get(release, 'score')}), - new Element('span.provider', { 'text': provider, 'title': provider }), - info['detail_url'] ? new Element('a.info.icon2', { - 'href': info['detail_url'], - 'target': '_blank' - }) : new Element('a'), - new Element('a.download.icon2', { - 'events': { - 'click': function(e){ - (e).preventDefault(); - if(!this.hasClass('completed')) - self.download(release); - } - } - }), - new Element('a.delete.icon2', { - 'events': { - 'click': function(e){ - (e).preventDefault(); - self.ignore(release); - } - } - }) - ).inject(self.releases_table); - - if(release.status == 'ignored' || release.status == 'failed' || release.status == 'snatched'){ - if(!self.last_release || (self.last_release && self.last_release.status != 'snatched' && release.status == 'snatched')) - self.last_release = release; - } - else if(!self.next_release && release.status == 'available'){ - self.next_release = release; - } - - var update_handle = function(notification) { - if(notification.data._id != release._id) return; - - var q = self.show.quality.getElement('.q_' + release.quality), - new_status = notification.data.status; - - release.el.set('class', 'item ' + new_status); - - var status_el = release.el.getElement('.release_status'); - status_el.set('class', 'release_status ' + new_status); - status_el.set('text', new_status); - - if(!q && (new_status == 'snatched' || new_status == 'seeding' || new_status == 'done')) - q = self.addQuality(release.quality_id); - - if(q && !q.hasClass(new_status)) { - q.removeClass(release.status).addClass(new_status); - q.set('title', q.get('title').replace(release.status, new_status)); - } - }; - - App.on('release.update_status', update_handle); - - }); - - if(self.last_release) - self.releases_table.getElements('#release_'+self.last_release._id).addClass('last_release'); - - if(self.next_release) - self.releases_table.getElements('#release_'+self.next_release._id).addClass('next_release'); - - if(self.next_release || (self.last_release && ['ignored', 'failed'].indexOf(self.last_release.status) === false)){ - - self.trynext_container = new Element('div.buttons.try_container').inject(self.releases_table, 'top'); - - var nr = self.next_release, - lr = self.last_release; - - self.trynext_container.adopt( - new Element('span.or', { - 'text': 'If anything went wrong, download' - }), - lr ? new Element('a.button.orange', { - 'text': 'the same release again', - 'events': { - 'click': function(){ - self.download(lr); - } - } - }) : null, - nr && lr ? new Element('span.or', { - 'text': ',' - }) : null, - nr ? [new Element('a.button.green', { - 'text': lr ? 'another release' : 'the best release', - 'events': { - 'click': function(){ - self.download(nr); - } - } - }), - new Element('span.or', { - 'text': 'or pick one below' - })] : null - ) - } - - self.last_release = null; - self.next_release = null; - - self.episode.el.addEvent('outerClick', function(){ - self.close(); - }); - } - - self.options.setStyle('height', self.releases_table.getSize().y) - .addClass('expanded'); - - }, - - showHelper: function(e){ - var self = this; - if(e) - (e).preventDefault(); - - var has_available = false, - has_snatched = false; - - if(self.episode.data.releases) - self.episode.data.releases.each(function(release){ - if(has_available && has_snatched) return; - - if(['snatched', 'downloaded', 'seeding'].contains(release.status)) - has_snatched = true; - - if(['available'].contains(release.status)) - has_available = true; - - }); - - if(has_available || has_snatched){ - - self.trynext_container = new Element('div.buttons.trynext').inject(self.show.info_container); - - self.trynext_container.adopt( - has_available ? [new Element('a.icon2.readd', { - 'text': has_snatched ? 'Download another release' : 'Download the best release', - 'events': { - 'click': self.tryNextRelease.bind(self) - } - }), - new Element('a.icon2.download', { - 'text': 'pick one yourself', - 'events': { - 'click': function(){ - self.show.quality.fireEvent('click'); - } - } - })] : null, - new Element('a.icon2.completed', { - 'text': 'mark this movie done', - 'events': { - 'click': self.markMovieDone.bind(self) - } - }) - ) - } - - }, - - get: function(release, type){ - return (release.info && release.info[type] !== undefined) ? release.info[type] : 'n/a' - }, - - download: function(release){ - var self = this; - - var release_el = self.releases_table.getElement('#release_'+release._id), - icon = release_el.getElement('.download.icon2'); - - if(icon) - icon.addClass('icon spinner').removeClass('download'); - - Api.request('release.manual_download', { - 'data': { - 'id': release._id - }, - 'onComplete': function(json){ - if(icon) - icon.removeClass('icon spinner'); - - if(json.success){ - if(icon) - icon.addClass('completed'); - release_el.getElement('.release_status').set('text', 'snatched'); - } - else - if(icon) - icon.addClass('attention').set('title', 'Something went wrong when downloading, please check logs.'); - } - }); - }, - - ignore: function(release){ - - Api.request('release.ignore', { - 'data': { - 'id': release._id - } - }) - - }, - - markMovieDone: function(){ - var self = this; - - Api.request('media.delete', { - 'data': { - 'id': self.show.get('_id'), - 'delete_from': 'wanted' - }, - 'onComplete': function(){ - var movie = $(self.show); - movie.set('tween', { - 'duration': 300, - 'onComplete': function(){ - self.show.destroy() - } - }); - movie.tween('height', 0); - } - }); - - }, - - tryNextRelease: function(){ - var self = this; - - Api.request('movie.searcher.try_next', { - 'data': { - 'media_id': self.show.get('_id') - } - }); - - } - -}); - -EA.Refresh = new Class({ - - Extends: EpisodeAction, - - create: function(){ - var self = this; - - self.el = new Element('a.refresh', { - 'title': 'Refresh the movie info and do a forced search', - 'events': { - 'click': self.doRefresh.bind(self) - } - }); - - }, - - doRefresh: function(e){ - var self = this; - (e).preventDefault(); - - Api.request('media.refresh', { - 'data': { - 'id': self.episode.get('_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 index 4177725..d89435e 100755 --- a/couchpotato/core/media/show/_base/static/list.js +++ b/couchpotato/core/media/show/_base/static/list.js @@ -1,636 +1,8 @@ var ShowList = new Class({ - Implements: [Events, Options], + Extends: MovieList, - 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.list'), - 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.createShow(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.createShow(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) + ' shows'); - - 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 shows 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); - - } - - }, - - createShow: function(show, inject_at){ - var self = this; - var m = new Show(self, { - 'actions': self.options.actions, - 'view': self.current_view, - 'onSelect': self.calculateSelected.bind(self) - }, show); - - $(m).inject(self.movie_list, inject_at || 'bottom'); - - m.fireEvent('injected'); - - self.movies.include(m); - self.movies_added[show._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({ - 'type': 'show', - '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.shows); - self.addMovies(json.shows, json.total || json.shows.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; - } + media_type: 'show', + list_key: 'shows' }); diff --git a/couchpotato/core/media/show/_base/static/page.js b/couchpotato/core/media/show/_base/static/page.js new file mode 100644 index 0000000..d5e9134 --- /dev/null +++ b/couchpotato/core/media/show/_base/static/page.js @@ -0,0 +1,56 @@ +Page.Shows = new Class({ + + Extends: PageBase, + + name: 'shows', + icon: 'show', + sub_pages: ['Wanted'], + default_page: 'Wanted', + current_page: null, + + initialize: function(parent, options){ + var self = this; + self.parent(parent, options); + + self.navigation = new BlockNavigation(); + $(self.navigation).inject(self.content, 'top'); + + App.on('shows.enabled', self.toggleShows.bind(self)); + + }, + + defaultAction: function(action, params){ + var self = this; + + if(self.current_page){ + self.current_page.hide(); + + if(self.current_page.list && self.current_page.list.navigation) + self.current_page.list.navigation.dispose(); + } + + var route = new Route(); + route.parse(action); + + var page_name = route.getPage() != 'index' ? route.getPage().capitalize() : self.default_page; + + var page = self.sub_pages.filter(function(page){ + return page.name == page_name; + }).pick()['class']; + + page.open(route.getAction() || 'index', params); + page.show(); + + if(page.list && page.list.navigation) + page.list.navigation.inject(self.navigation); + + self.current_page = page; + self.navigation.activate(page_name.toLowerCase()); + + }, + + toggleShows: function(notification) { + document.body[notification.data === true ? 'addClass' : 'removeClass']('show_support'); + } + +}); diff --git a/couchpotato/core/media/show/_base/static/search.js b/couchpotato/core/media/show/_base/static/search.js index 96498e5..6f09ef9 100755 --- a/couchpotato/core/media/show/_base/static/search.js +++ b/couchpotato/core/media/show/_base/static/search.js @@ -1,230 +1,7 @@ -Block.Search.ShowItem = new Class({ +var BlockSearchShowItem = new Class({ - Implements: [Options, Events], + Extends: BlockSearchMovieItem, - initialize: function(info, options){ - var self = this; - self.setOptions(options); - - self.info = info; - self.alternative_titles = []; - - self.create(); - }, - - create: function(){ - var self = this, - info = self.info; - - self.el = new Element('div.media_result', { - 'id': info.id - }).adopt( - self.thumbnail = info.images && info.images.poster.length > 0 ? new Element('img.thumbnail', { - 'src': info.images.poster[0], - 'height': null, - 'width': null - }) : null, - self.options_el = new Element('div.options.inlay'), - self.data_container = new Element('div.data', { - 'events': { - 'click': self.showOptions.bind(self) - } - }).adopt( - self.info_container = new Element('div.info').adopt( - new Element('h2').adopt( - self.title = new Element('span.title', { - 'text': info.titles && info.titles.length > 0 ? info.titles[0] : 'Unknown' - }), - self.year = info.year ? new Element('span.year', { - 'text': info.year - }) : null - ) - ) - ) - ) - - if(info.titles) - info.titles.each(function(title){ - self.alternativeTitle({ - 'title': title - }); - }) - }, - - alternativeTitle: function(alternative){ - var self = this; - - self.alternative_titles.include(alternative); - }, - - getTitle: function(){ - var self = this; - try { - return self.info.original_title ? self.info.original_title : self.info.titles[0]; - } - catch(e){ - return 'Unknown'; - } - }, - - get: function(key){ - return this.info[key] - }, - - showOptions: function(){ - var self = this; - - self.createOptions(); - - self.data_container.addClass('open'); - self.el.addEvent('outerClick', self.closeOptions.bind(self)) - - }, - - closeOptions: function(){ - var self = this; - - self.data_container.removeClass('open'); - self.el.removeEvents('outerClick') - }, - - add: function(e){ - var self = this; - - if(e) - (e).preventDefault(); - - self.loadingMask(); - - Api.request('show.add', { - 'data': { - 'identifiers': self.info.identifiers, - 'type': self.info.type, - 'title': self.title_select.get('value'), - 'profile_id': self.profile_select.get('value'), - 'category_id': self.category_select.get('value') - }, - 'onComplete': function(json){ - self.options_el.empty(); - self.options_el.adopt( - new Element('div.message', { - 'text': json.success ? 'Show successfully added.' : 'Show didn\'t add properly. Check logs' - }) - ); - self.mask.fade('out'); - - self.fireEvent('added'); - }, - 'onFailure': function(){ - self.options_el.empty(); - self.options_el.adopt( - new Element('div.message', { - 'text': 'Something went wrong, check the logs for more info.' - }) - ); - self.mask.fade('out'); - } - }); - }, - - createOptions: function(){ - var self = this, - info = self.info; - - if(!self.options_el.hasClass('set')){ - - if(self.info.in_library){ - var in_library = []; - self.info.in_library.releases.each(function(release){ - in_library.include(release.quality.label) - }); - } - - self.options_el.grab( - new Element('div', { - 'class': self.info.in_wanted && self.info.in_wanted.profile_id || in_library ? 'in_library_wanted' : '' - }).adopt( - self.info.in_wanted && self.info.in_wanted.profile_id ? new Element('span.in_wanted', { - 'text': 'Already in wanted list: ' + Quality.getProfile(self.info.in_wanted.profile_id).get('label') - }) : (in_library ? new Element('span.in_library', { - 'text': 'Already in library: ' + in_library.join(', ') - }) : null), - self.title_select = new Element('select', { - 'name': 'title' - }), - self.profile_select = new Element('select', { - 'name': 'profile' - }), - self.category_select = new Element('select', { - 'name': 'category' - }).grab( - new Element('option', {'value': -1, 'text': 'None'}) - ), - self.add_button = new Element('a.button', { - 'text': 'Add', - 'events': { - 'click': self.add.bind(self) - } - }) - ) - ); - - Array.each(self.alternative_titles, function(alt){ - new Element('option', { - 'text': alt.title - }).inject(self.title_select) - }) - - - // Fill categories - var categories = CategoryList.getAll(); - - if(categories.length == 0) - self.category_select.hide(); - else { - self.category_select.show(); - categories.each(function(category){ - new Element('option', { - 'value': category.data._id, - 'text': category.data.label - }).inject(self.category_select); - }); - } - - // Fill profiles - var profiles = Quality.getActiveProfiles(); - if(profiles.length == 1) - self.profile_select.hide(); - - profiles.each(function(profile){ - new Element('option', { - 'value': profile.get('_id'), - 'text': profile.get('label') - }).inject(self.profile_select) - }); - - self.options_el.addClass('set'); - - if(categories.length == 0 && self.title_select.getElements('option').length == 1 && profiles.length == 1 && - !(self.info.in_wanted && self.info.in_wanted.profile_id || in_library)) - self.add(); - - } - - }, - - loadingMask: function(){ - var self = this; - - self.mask = new Element('div.mask').inject(self.el).fade('hide') - - createSpinner(self.mask) - self.mask.fade('in') - - }, - - toElement: function(){ - return this.el - } + media_type: 'movie' }); diff --git a/couchpotato/core/media/show/_base/static/show.js b/couchpotato/core/media/show/_base/static/show.js index 6019721..c51f1d3 100755 --- a/couchpotato/core/media/show/_base/static/show.js +++ b/couchpotato/core/media/show/_base/static/show.js @@ -1,370 +1,5 @@ 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, { - 'actions': [EA.IMDB, EA.Release, EA.Refresh] - }); - - 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')); - - var eta = null, - eta_date = null, - now = Math.round(+new Date()/1000); - - if(self.data.info.release_date) - [self.data.info.release_date.dvd, self.data.info.release_date.theater].each(function(timestamp){ - if (timestamp > 0 && (eta == null || Math.abs(timestamp - now) < Math.abs(eta - now))) - eta = timestamp; - }); - - if(eta){ - eta_date = new Date(eta * 1000); - eta_date = eta_date.toLocaleString('en-us', { month: "long" }) + ' ' + eta_date.getFullYear(); - } - - 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.eta = eta_date && (now+8035200 > eta) ? new Element('div.eta', { - 'text': eta_date, - 'title': 'ETA' - }) : null, - 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, expand){ - 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(); - - - if(expand === true) { - 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; - } + Extends: Movie }); diff --git a/couchpotato/core/media/show/_base/static/show.css b/couchpotato/core/media/show/_base/static/show.scss old mode 100755 new mode 100644 similarity index 99% rename from couchpotato/core/media/show/_base/static/show.css rename to couchpotato/core/media/show/_base/static/show.scss index ec20240..46a94ec --- a/couchpotato/core/media/show/_base/static/show.css +++ b/couchpotato/core/media/show/_base/static/show.scss @@ -1,3 +1,12 @@ +.header .navigation ul .tab_shows { + display: none; + + .support_show & { + display: block; + } +} + +/* .shows.details_list { padding: 10px 0 20px; position: relative; @@ -1213,3 +1222,4 @@ text-align: right; vertical-align: middle; } +*/ diff --git a/couchpotato/core/media/show/_base/static/wanted.js b/couchpotato/core/media/show/_base/static/wanted.js new file mode 100644 index 0000000..13a5576 --- /dev/null +++ b/couchpotato/core/media/show/_base/static/wanted.js @@ -0,0 +1,28 @@ +var ShowsWanted = new Class({ + Extends: PageBase, + + name: 'wanted', + title: 'List of TV Shows subscribed to', + folder_browser: null, + has_tab: false, + + indexAction: function(){ + var self = this; + + if(!self.wanted){ + + // Wanted movies + self.wanted = new ShowList({ + 'identifier': 'wanted', + 'status': 'active', + 'type': 'show', + 'actions': [MA.IMDB, MA.Release, MA.Refresh, MA.Delete], + 'add_new': true, + 'on_empty_element': App.createUserscriptButtons().addClass('empty_wanted') + }); + $(self.wanted).inject(self.content); + } + + } + +}); diff --git a/couchpotato/static/scripts/combined.base.min.js b/couchpotato/static/scripts/combined.base.min.js index 113bedb..81bdd40 100644 --- a/couchpotato/static/scripts/combined.base.min.js +++ b/couchpotato/static/scripts/combined.base.min.js @@ -265,6 +265,13 @@ var CouchPotato = new Class({ setting_links.each(function(a) { self.block.more.addLink(a); }); + var support_classes = []; + self.options.support.each(function(support) { + if (support) { + support_classes.push("support_" + support); + } + }); + document.body.addClass(support_classes.join(" ")); new ScrollSpy({ min: 10, onLeave: function() { @@ -825,6 +832,13 @@ var BlockNavigation = new Class({ var self = this; return new Element("li.tab_" + (name || "unknown")).grab(new Element("a", tab)).inject(self.nav); }, + removeTab: function(name) { + var self = this; + var element = self.nav.getElement("li.tab_" + name); + if (element) { + element.dispose(); + } + }, activate: function(name) { var self = this; self.nav.getElements(".active").removeClass("active"); diff --git a/couchpotato/static/scripts/combined.plugins.min.js b/couchpotato/static/scripts/combined.plugins.min.js index 5b83e21..0e921bd 100644 --- a/couchpotato/static/scripts/combined.plugins.min.js +++ b/couchpotato/static/scripts/combined.plugins.min.js @@ -606,6 +606,8 @@ var MovieDetails = new Class({ var MovieList = new Class({ Implements: [ Events, Options ], + media_type: "movie", + list_key: "movies", options: { api_call: "media.list", navigation: true, @@ -1034,7 +1036,7 @@ var MovieList = new Class({ } Api.request(self.options.api_call, { data: Object.merge({ - type: self.options.type || "movie", + type: self.media_type || "movie", status: self.options.status, limit_offset: self.options.limit ? self.options.limit + "," + self.offset : null }, self.filter), @@ -1050,8 +1052,9 @@ var MovieList = new Class({ }, 1e3); self.el.setStyle("min-height", null); } - self.store(json.movies); - self.addMovies(json.movies, json.total || json.movies.length); + var items = json[self.list_key] || []; + self.store(items); + self.addMovies(items, json.total || items.length); if (self.scrollspy) { self.load_more.set("text", "load more movies"); self.scrollspy.start(); @@ -2262,6 +2265,7 @@ Page.Movies = new Class({ var BlockSearchMovieItem = new Class({ Implements: [ Options, Events ], + media_type: "movie", initialize: function(info, options) { var self = this; self.setOptions(options); @@ -2335,7 +2339,7 @@ var BlockSearchMovieItem = new Class({ var self = this; if (e) e.preventDefault(); self.loadingMask(); - Api.request("movie.add", { + Api.request(self.media_type + ".add", { data: { identifier: self.info.imdb, title: self.title_select.get("value"), @@ -2644,1175 +2648,231 @@ var TraktAutomation = new Class({ new TraktAutomation(); -Page.Shows = new Class({ - Extends: PageBase, - name: "shows", - title: "List of TV Shows subscribed to", - folder_browser: null, - has_tab: false, - toggleShows: function(arg) { - var self = this; - var nav = App.getBlock("navigation"); - if (typeof arg === "object" && arg.data === true || arg === true) { - self.tab = nav.addTab(self.name, { - href: App.createUrl(self.name), - title: self.title, - text: self.name.capitalize() - }); - self.has_tab = true; - } else { - self.has_tab = false; - self.tab = null; - nav.removeTab("shows"); - } - }, - load: function() { +var Episode = new Class({ + Extends: BlockBase, + action: {}, + initialize: function(show, options, data) { var self = this; - Api.request("settings", { - onComplete: function(json) { - self.toggleShows(json.values.shows.enabled); - } - }); - App.on("shows.enabled", self.toggleShows.bind(self)); + self.setOptions(options); + self.show = show; + self.options = options; + self.data = data; + self.profile = self.show.profile; + self.el = new Element("div.item.episode").adopt(self.detail = new Element("div.item.data")); + self.create(); }, - indexAction: function() { + create: function() { var self = this; - if (!self.wanted) { - self.wanted = new ShowList({ - identifier: "wanted", - status: "active", - type: "show", - actions: [ MA.IMDB, MA.Trailer, MA.Release, MA.Edit, MA.Refresh, MA.Readd, MA.Delete ], - add_new: true, - on_empty_element: App.createUserscriptButtons().addClass("empty_wanted") + self.detail.set("id", "episode_" + self.data._id); + self.detail.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.quality = new Element("span.quality", { + events: { + click: function(e) { + var releases = self.detail.getElement(".item-actions .releases"); + if (releases.isVisible()) releases.fireEvent("click", [ e ]); + } + } + }), self.actions = new Element("div.item-actions")); + 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."); + } }); - $(self.wanted).inject(self.el); } - } -}); - -var EpisodeAction = new Class({ - Implements: [ Options ], - class_name: "item-action icon2", - initialize: function(episode, options) { - var self = this; - self.setOptions(options); - self.show = episode.show; - self.episode = episode; - self.create(); - if (self.el) self.el.addClass(self.class_name); + 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); + }); }, - create: function() {}, - disable: function() { - if (this.el) this.el.addClass("disable"); + 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); + } + }); }, - enable: function() { - if (this.el) this.el.removeClass("disable"); + addQuality: function(quality, is_3d) { + var self = this, 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; - try { - return self.show.getTitle(); - } catch (e) { - try { - return self.show.original_title ? self.show.original_title : self.show.titles[0]; - } catch (e) { - return "Unknown"; - } + 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; }, - get: function(key) { + getIdentifier: function() { var self = this; try { - return self.show.get(key); - } catch (e) { - return self.show[key]; - } - }, - createMask: function() { - var self = this; - self.mask = new Element("div.mask", { - styles: { - "z-index": "1" - } - }).inject(self.show, "top").fade("hide"); + return self.get("identifiers").imdb; + } catch (e) {} + return self.get("imdb"); }, - toElement: function() { - return this.el || null; + get: function(attr) { + return this.data[attr] || this.data.info[attr]; } }); -var EA = {}; +var ShowList = new Class({ + Extends: MovieList, + media_type: "show", + list_key: "shows" +}); -EA.IMDB = new Class({ - Extends: EpisodeAction, - id: null, - create: function() { +Page.Shows = new Class({ + Extends: PageBase, + name: "shows", + icon: "show", + sub_pages: [ "Wanted" ], + default_page: "Wanted", + current_page: null, + initialize: function(parent, options) { var self = this; - self.id = self.show.getIdentifier ? self.show.getIdentifier() : self.get("imdb"); - self.el = new Element("a.imdb", { - title: "Go to the IMDB page of " + self.getTitle(), - href: "http://www.imdb.com/title/" + self.id + "/", - target: "_blank" - }); - if (!self.id) self.disable(); + self.parent(parent, options); + self.navigation = new BlockNavigation(); + $(self.navigation).inject(self.content, "top"); + App.on("shows.enabled", self.toggleShows.bind(self)); + }, + defaultAction: function(action, params) { + var self = this; + if (self.current_page) { + self.current_page.hide(); + if (self.current_page.list && self.current_page.list.navigation) self.current_page.list.navigation.dispose(); + } + var route = new Route(); + route.parse(action); + var page_name = route.getPage() != "index" ? route.getPage().capitalize() : self.default_page; + var page = self.sub_pages.filter(function(page) { + return page.name == page_name; + }).pick()["class"]; + page.open(route.getAction() || "index", params); + page.show(); + if (page.list && page.list.navigation) page.list.navigation.inject(self.navigation); + self.current_page = page; + self.navigation.activate(page_name.toLowerCase()); + }, + toggleShows: function(notification) { + document.body[notification.data === true ? "addClass" : "removeClass"]("show_support"); } }); -EA.Release = new Class({ - Extends: EpisodeAction, +var BlockSearchShowItem = new Class({ + Extends: BlockSearchMovieItem, + media_type: "movie" +}); + +var Season = new Class({ + Extends: BlockBase, + action: {}, + initialize: function(show, options, data) { + var self = this; + self.setOptions(options); + self.show = show; + self.options = options; + self.data = data; + self.profile = self.show.profile; + self.el = new Element("div.item.season").adopt(self.detail = new Element("div.item.data")); + self.create(); + }, create: function() { var self = this; - self.el = new Element("a.releases.download", { - title: "Show the releases that are available for " + self.getTitle(), + self.detail.set("id", "season_" + self.data._id); + self.detail.adopt(new Element("span.name", { + text: self.getTitle() + }), self.quality = new Element("span.quality", { events: { - click: self.toggle.bind(self) + click: function(e) { + var releases = self.detail.getElement(".item-actions .releases"); + if (releases.isVisible()) releases.fireEvent("click", [ e ]); + } } + }), self.actions = new Element("div.item-actions")); + 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."); + } + }); + } + 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); }); - self.options = new Element("div.episode-options").inject(self.episode.el); - if (!self.episode.data.releases || self.episode.data.releases.length == 0) self.el.hide(); else self.showHelper(); - App.on("show.searcher.ended", function(notification) { - if (self.show.data._id != notification.data._id) return; - self.releases = null; - if (self.options_container) { - self.options_container.destroy(); - self.options_container = null; + }, + 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); } }); }, - toggle: function(e) { + addQuality: function(quality, is_3d) { + var self = this, 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.options && self.options.hasClass("expanded")) { - self.close(); + var title = ""; + if (self.data.info.number) { + title = "Season " + self.data.info.number; } else { - self.open(); + title = "Specials"; } + return title; }, - open: function(e) { + getIdentifier: function() { var self = this; - if (e) e.preventDefault(); - self.createReleases(); + try { + return self.get("identifiers").imdb; + } catch (e) {} + return self.get("imdb"); }, - close: function(e) { + get: function(attr) { + return this.data[attr] || this.data.info[attr]; + } +}); + +var Episodes = new Class({ + initialize: function(show, options) { var self = this; - if (e) e.preventDefault(); - self.options.setStyle("height", 0).removeClass("expanded"); + self.show = show; + self.options = options; }, - createReleases: function() { - var self = this; - if (!self.releases_table) { - self.options.adopt(self.releases_table = new Element("div.releases.table")); - new Element("div.item.head").adopt(new Element("span.name", { - text: "Release name" - }), new Element("span.status", { - text: "Status" - }), new Element("span.quality", { - text: "Quality" - }), new Element("span.size", { - text: "Size" - }), new Element("span.age", { - text: "Age" - }), new Element("span.score", { - text: "Score" - }), new Element("span.provider", { - text: "Provider" - })).inject(self.releases_table); - if (self.episode.data.releases) self.episode.data.releases.each(function(release) { - var quality = Quality.getQuality(release.quality) || {}, info = release.info || {}, provider = self.get(release, "provider") + (info["provider_extra"] ? self.get(release, "provider_extra") : ""); - var release_name = self.get(release, "name"); - if (release.files && release.files.length > 0) { - try { - var movie_file = release.files.filter(function(file) { - var type = File.Type.get(file.type_id); - return type && type.identifier == "movie"; - }).pick(); - release_name = movie_file.path.split(Api.getOption("path_sep")).getLast(); - } catch (e) {} - } - release["el"] = new Element("div", { - class: "item " + release.status, - id: "release_" + release._id - }).adopt(new Element("span.name", { - text: release_name, - title: release_name - }), new Element("span.status", { - text: release.status, - class: "status " + release.status - }), new Element("span.quality", { - text: quality.label + (release.is_3d ? " 3D" : "") || "n/a" - }), new Element("span.size", { - text: info["size"] ? Math.floor(self.get(release, "size")) : "n/a" - }), new Element("span.age", { - text: self.get(release, "age") - }), new Element("span.score", { - text: self.get(release, "score") - }), new Element("span.provider", { - text: provider, - title: provider - }), info["detail_url"] ? new Element("a.info.icon2", { - href: info["detail_url"], - target: "_blank" - }) : new Element("a"), new Element("a.download.icon2", { - events: { - click: function(e) { - e.preventDefault(); - if (!this.hasClass("completed")) self.download(release); - } - } - }), new Element("a.delete.icon2", { - events: { - click: function(e) { - e.preventDefault(); - self.ignore(release); - } - } - })).inject(self.releases_table); - if (release.status == "ignored" || release.status == "failed" || release.status == "snatched") { - if (!self.last_release || self.last_release && self.last_release.status != "snatched" && release.status == "snatched") self.last_release = release; - } else if (!self.next_release && release.status == "available") { - self.next_release = release; - } - var update_handle = function(notification) { - if (notification.data._id != release._id) return; - var q = self.show.quality.getElement(".q_" + release.quality), new_status = notification.data.status; - release.el.set("class", "item " + new_status); - var status_el = release.el.getElement(".release_status"); - status_el.set("class", "release_status " + new_status); - status_el.set("text", new_status); - if (!q && (new_status == "snatched" || new_status == "seeding" || new_status == "done")) q = self.addQuality(release.quality_id); - if (q && !q.hasClass(new_status)) { - q.removeClass(release.status).addClass(new_status); - q.set("title", q.get("title").replace(release.status, new_status)); - } - }; - App.on("release.update_status", update_handle); - }); - if (self.last_release) self.releases_table.getElements("#release_" + self.last_release._id).addClass("last_release"); - if (self.next_release) self.releases_table.getElements("#release_" + self.next_release._id).addClass("next_release"); - if (self.next_release || self.last_release && [ "ignored", "failed" ].indexOf(self.last_release.status) === false) { - self.trynext_container = new Element("div.buttons.try_container").inject(self.releases_table, "top"); - var nr = self.next_release, lr = self.last_release; - self.trynext_container.adopt(new Element("span.or", { - text: "If anything went wrong, download" - }), lr ? new Element("a.button.orange", { - text: "the same release again", - events: { - click: function() { - self.download(lr); - } - } - }) : null, nr && lr ? new Element("span.or", { - text: "," - }) : null, nr ? [ new Element("a.button.green", { - text: lr ? "another release" : "the best release", - events: { - click: function() { - self.download(nr); - } - } - }), new Element("span.or", { - text: "or pick one below" - }) ] : null); - } - self.last_release = null; - self.next_release = null; - self.episode.el.addEvent("outerClick", function() { - self.close(); - }); - } - self.options.setStyle("height", self.releases_table.getSize().y).addClass("expanded"); - }, - showHelper: function(e) { - var self = this; - if (e) e.preventDefault(); - var has_available = false, has_snatched = false; - if (self.episode.data.releases) self.episode.data.releases.each(function(release) { - if (has_available && has_snatched) return; - if ([ "snatched", "downloaded", "seeding" ].contains(release.status)) has_snatched = true; - if ([ "available" ].contains(release.status)) has_available = true; - }); - if (has_available || has_snatched) { - self.trynext_container = new Element("div.buttons.trynext").inject(self.show.info_container); - self.trynext_container.adopt(has_available ? [ new Element("a.icon2.readd", { - text: has_snatched ? "Download another release" : "Download the best release", - events: { - click: self.tryNextRelease.bind(self) - } - }), new Element("a.icon2.download", { - text: "pick one yourself", - events: { - click: function() { - self.show.quality.fireEvent("click"); - } - } - }) ] : null, new Element("a.icon2.completed", { - text: "mark this movie done", - events: { - click: self.markMovieDone.bind(self) - } - })); - } - }, - get: function(release, type) { - return release.info && release.info[type] !== undefined ? release.info[type] : "n/a"; - }, - download: function(release) { - var self = this; - var release_el = self.releases_table.getElement("#release_" + release._id), icon = release_el.getElement(".download.icon2"); - if (icon) icon.addClass("icon spinner").removeClass("download"); - Api.request("release.manual_download", { - data: { - id: release._id - }, - onComplete: function(json) { - if (icon) icon.removeClass("icon spinner"); - if (json.success) { - if (icon) icon.addClass("completed"); - release_el.getElement(".release_status").set("text", "snatched"); - } else if (icon) icon.addClass("attention").set("title", "Something went wrong when downloading, please check logs."); - } - }); - }, - ignore: function(release) { - Api.request("release.ignore", { - data: { - id: release._id - } - }); - }, - markMovieDone: function() { - var self = this; - Api.request("media.delete", { - data: { - id: self.show.get("_id"), - delete_from: "wanted" - }, - onComplete: function() { - var movie = $(self.show); - movie.set("tween", { - duration: 300, - onComplete: function() { - self.show.destroy(); - } - }); - movie.tween("height", 0); - } - }); - }, - tryNextRelease: function() { - var self = this; - Api.request("movie.searcher.try_next", { - data: { - media_id: self.show.get("_id") - } - }); - } -}); - -EA.Refresh = new Class({ - Extends: EpisodeAction, - create: function() { - var self = this; - self.el = new Element("a.refresh", { - title: "Refresh the movie info and do a forced search", - events: { - click: self.doRefresh.bind(self) - } - }); - }, - doRefresh: function(e) { - var self = this; - e.preventDefault(); - Api.request("media.refresh", { - data: { - id: self.episode.get("_id") - } - }); - } -}); - -var Episode = new Class({ - Extends: BlockBase, - action: {}, - initialize: function(show, options, data) { - var self = this; - self.setOptions(options); - self.show = show; - self.options = options; - self.data = data; - self.profile = self.show.profile; - self.el = new Element("div.item.episode").adopt(self.detail = new Element("div.item.data")); - self.create(); - }, - create: function() { - var self = this; - self.detail.set("id", "episode_" + self.data._id); - self.detail.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.quality = new Element("span.quality", { - events: { - click: function(e) { - var releases = self.detail.getElement(".item-actions .releases"); - if (releases.isVisible()) releases.fireEvent("click", [ e ]); - } - } - }), self.actions = new Element("div.item-actions")); - 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."); - } - }); - } - 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, 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; - 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; - }, - 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]; - } -}); - -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.list"), 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.createShow(notification.data, "top"); - self.setCounter(self.counter_count + 1); - self.checkIfEmpty(); - } - }, - create: function() { - var self = this; - 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(); - if (movies.length < self.options.limit && self.scrollspy) { - self.load_more.hide(); - self.scrollspy.stop(); - } - Object.each(movies, function(movie) { - self.createShow(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) + " shows"); - 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 shows 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); - } - }, - createShow: function(show, inject_at) { - var self = this; - var m = new Show(self, { - actions: self.options.actions, - view: self.current_view, - onSelect: self.calculateSelected.bind(self) - }, show); - $(m).inject(self.movie_list, inject_at || "bottom"); - m.fireEvent("injected"); - self.movies.include(m); - self.movies_added[show._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"); - 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(); - if (!available_chars && (self.navigation.isDisplayed() || self.navigation.isVisible())) Api.request("media.available_chars", { - data: Object.merge({ - type: "show", - 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); - } - } - })); - [ "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"); - }); - self.letters["all"] = new Element("li.letter_all.available.active", { - text: "ALL" - }).inject(self.navigation_alpha); - chars.split("").each(function(c) { - self.letters[c] = new Element("li", { - text: c, - class: "letter_" + c, - "data-letter": c - }).inject(self.navigation_alpha); - }); - 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.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: 1e3 - }); - }, - 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(); - }, 2e4); - self.el.setStyle("min-height", null); - } - self.store(json.shows); - self.addMovies(json.shows, json.total || json.shows.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; - } -}); - -Block.Search.ShowItem = new Class({ - Implements: [ Options, Events ], - initialize: function(info, options) { - var self = this; - self.setOptions(options); - self.info = info; - self.alternative_titles = []; - self.create(); - }, - create: function() { - var self = this, info = self.info; - self.el = new Element("div.media_result", { - id: info.id - }).adopt(self.thumbnail = info.images && info.images.poster.length > 0 ? new Element("img.thumbnail", { - src: info.images.poster[0], - height: null, - width: null - }) : null, self.options_el = new Element("div.options.inlay"), self.data_container = new Element("div.data", { - events: { - click: self.showOptions.bind(self) - } - }).adopt(self.info_container = new Element("div.info").adopt(new Element("h2").adopt(self.title = new Element("span.title", { - text: info.titles && info.titles.length > 0 ? info.titles[0] : "Unknown" - }), self.year = info.year ? new Element("span.year", { - text: info.year - }) : null)))); - if (info.titles) info.titles.each(function(title) { - self.alternativeTitle({ - title: title - }); - }); - }, - alternativeTitle: function(alternative) { - var self = this; - self.alternative_titles.include(alternative); - }, - getTitle: function() { - var self = this; - try { - return self.info.original_title ? self.info.original_title : self.info.titles[0]; - } catch (e) { - return "Unknown"; - } - }, - get: function(key) { - return this.info[key]; - }, - showOptions: function() { - var self = this; - self.createOptions(); - self.data_container.addClass("open"); - self.el.addEvent("outerClick", self.closeOptions.bind(self)); - }, - closeOptions: function() { - var self = this; - self.data_container.removeClass("open"); - self.el.removeEvents("outerClick"); - }, - add: function(e) { - var self = this; - if (e) e.preventDefault(); - self.loadingMask(); - Api.request("show.add", { - data: { - identifiers: self.info.identifiers, - type: self.info.type, - title: self.title_select.get("value"), - profile_id: self.profile_select.get("value"), - category_id: self.category_select.get("value") - }, - onComplete: function(json) { - self.options_el.empty(); - self.options_el.adopt(new Element("div.message", { - text: json.success ? "Show successfully added." : "Show didn't add properly. Check logs" - })); - self.mask.fade("out"); - self.fireEvent("added"); - }, - onFailure: function() { - self.options_el.empty(); - self.options_el.adopt(new Element("div.message", { - text: "Something went wrong, check the logs for more info." - })); - self.mask.fade("out"); - } - }); - }, - createOptions: function() { - var self = this, info = self.info; - if (!self.options_el.hasClass("set")) { - if (self.info.in_library) { - var in_library = []; - self.info.in_library.releases.each(function(release) { - in_library.include(release.quality.label); - }); - } - self.options_el.grab(new Element("div", { - class: self.info.in_wanted && self.info.in_wanted.profile_id || in_library ? "in_library_wanted" : "" - }).adopt(self.info.in_wanted && self.info.in_wanted.profile_id ? new Element("span.in_wanted", { - text: "Already in wanted list: " + Quality.getProfile(self.info.in_wanted.profile_id).get("label") - }) : in_library ? new Element("span.in_library", { - text: "Already in library: " + in_library.join(", ") - }) : null, self.title_select = new Element("select", { - name: "title" - }), self.profile_select = new Element("select", { - name: "profile" - }), self.category_select = new Element("select", { - name: "category" - }).grab(new Element("option", { - value: -1, - text: "None" - })), self.add_button = new Element("a.button", { - text: "Add", - events: { - click: self.add.bind(self) - } - }))); - Array.each(self.alternative_titles, function(alt) { - new Element("option", { - text: alt.title - }).inject(self.title_select); - }); - var categories = CategoryList.getAll(); - if (categories.length == 0) self.category_select.hide(); else { - self.category_select.show(); - categories.each(function(category) { - new Element("option", { - value: category.data._id, - text: category.data.label - }).inject(self.category_select); - }); - } - var profiles = Quality.getActiveProfiles(); - if (profiles.length == 1) self.profile_select.hide(); - profiles.each(function(profile) { - new Element("option", { - value: profile.get("_id"), - text: profile.get("label") - }).inject(self.profile_select); - }); - self.options_el.addClass("set"); - if (categories.length == 0 && self.title_select.getElements("option").length == 1 && profiles.length == 1 && !(self.info.in_wanted && self.info.in_wanted.profile_id || in_library)) self.add(); - } - }, - loadingMask: function() { - var self = this; - self.mask = new Element("div.mask").inject(self.el).fade("hide"); - createSpinner(self.mask); - self.mask.fade("in"); - }, - toElement: function() { - return this.el; - } -}); - -var Season = new Class({ - Extends: BlockBase, - action: {}, - initialize: function(show, options, data) { - var self = this; - self.setOptions(options); - self.show = show; - self.options = options; - self.data = data; - self.profile = self.show.profile; - self.el = new Element("div.item.season").adopt(self.detail = new Element("div.item.data")); - self.create(); - }, - create: function() { - var self = this; - self.detail.set("id", "season_" + self.data._id); - self.detail.adopt(new Element("span.name", { - text: self.getTitle() - }), self.quality = new Element("span.quality", { - events: { - click: function(e) { - var releases = self.detail.getElement(".item-actions .releases"); - if (releases.isVisible()) releases.fireEvent("click", [ e ]); - } - } - }), self.actions = new Element("div.item-actions")); - 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."); - } - }); - } - 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, 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; - var title = ""; - if (self.data.info.number) { - title = "Season " + self.data.info.number; - } else { - title = "Specials"; - } - return title; - }, - 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]; - } -}); - -var Episodes = new Class({ - initialize: function(show, options) { - var self = this; - self.show = show; - self.options = options; - }, - open: function() { + open: function() { var self = this; if (!self.container) { self.container = new Element("div.options").grab(self.episodes_container = new Element("div.episodes.table")); @@ -3867,247 +2927,28 @@ var Episodes = new Class({ }); 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, { - actions: [ EA.IMDB, EA.Release, EA.Refresh ] - }); - 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 = {}; - self.global_events["movie.update"] = function(notification) { - if (self.data._id != notification.data._id) return; - self.busy(false); - self.removeView(); - self.update.delay(2e3, self, notification); - }; - App.on("movie.update", self.global_events["movie.update"]); - [ "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]); - }); - 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"]); - 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(); - 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 || 1e3); - } 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")); - var eta = null, eta_date = null, now = Math.round(+new Date() / 1e3); - if (self.data.info.release_date) [ self.data.info.release_date.dvd, self.data.info.release_date.theater ].each(function(timestamp) { - if (timestamp > 0 && (eta == null || Math.abs(timestamp - now) < Math.abs(eta - now))) eta = timestamp; - }); - if (eta) { - eta_date = new Date(eta * 1e3); - eta_date = eta_date.toLocaleString("en-us", { - month: "long" - }) + " " + eta_date.getFullYear(); - } - 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.eta = eta_date && now + 8035200 > eta ? new Element("div.eta", { - text: eta_date, - title: "ETA" - }) : null, 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.select_checkbox_class = new Form.Check(self.select_checkbox); - 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."); - } - }); - 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, expand) { + Extends: Movie +}); + +var ShowsWanted = new Class({ + Extends: PageBase, + name: "wanted", + title: "List of TV Shows subscribed to", + folder_browser: null, + has_tab: false, + indexAction: function() { var self = this; - if (direction == "in") { - self.temp_view = self.view; - self.changeView("details"); - self.el.addEvent("outerClick", function() { - self.removeView(); - self.slide("out"); + if (!self.wanted) { + self.wanted = new ShowList({ + identifier: "wanted", + status: "active", + type: "show", + actions: [ MA.IMDB, MA.Release, MA.Refresh, MA.Delete ], + add_new: true, + on_empty_element: App.createUserscriptButtons().addClass("empty_wanted") }); - el.show(); - if (expand === true) { - 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"); + $(self.wanted).inject(self.content); } - }, - 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/static/style/combined.min.css b/couchpotato/static/style/combined.min.css index 51daefe..e8a57e9 100644 --- a/couchpotato/static/style/combined.min.css +++ b/couchpotato/static/style/combined.min.css @@ -392,6 +392,8 @@ .toggle_menu h2{height:40px} @media all and (max-width:480px){.toggle_menu h2{font-size:16px;text-align:center;height:30px} } +.header .navigation ul .tab_shows{display:none} +.support_show .header .navigation ul .tab_shows{display:block} .add_new_category{padding:20px;display:block;text-align:center;font-size:20px} .category{margin-bottom:20px;position:relative} .category>.delete{position:absolute;padding:16px;right:0;cursor:pointer;opacity:.6;color:#fd5353}