diff --git a/couchpotato/core/_base/updater/main.py b/couchpotato/core/_base/updater/main.py index aeec429..73b5f68 100644 --- a/couchpotato/core/_base/updater/main.py +++ b/couchpotato/core/_base/updater/main.py @@ -32,7 +32,7 @@ class Updater(Plugin): self.updater = SourceUpdater() fireEvent('schedule.interval', 'updater.check', self.autoUpdate, hours = 6) - addEvent('app.load', self.check) + addEvent('app.load', self.autoUpdate) addEvent('updater.info', self.info) addApiView('updater.info', self.getInfo, docs = { @@ -208,7 +208,7 @@ class GitUpdater(BaseUpdater): def check(self): if self.update_version: - return + return True log.info('Checking for new version on github for %s', self.repo_name) if not Env.get('dev'): diff --git a/couchpotato/core/_base/updater/static/updater.js b/couchpotato/core/_base/updater/static/updater.js index df6cf35..9f51b0c 100644 --- a/couchpotato/core/_base/updater/static/updater.js +++ b/couchpotato/core/_base/updater/static/updater.js @@ -62,6 +62,8 @@ var UpdaterBase = new Class({ createMessage: function(data){ var self = this; + if(self.message) return; + var changelog = 'https://github.com/'+data.repo_name+'/compare/'+data.version.hash+'...'+data.branch; if(data.update_version.changelog) changelog = data.update_version.changelog + '#' + data.version.hash+'...'+data.update_version.hash diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 3d1682c..92f6f8c 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -95,7 +95,10 @@ class Plugin(object): return False # http request - def urlopen(self, url, timeout = 30, params = {}, headers = {}, opener = None, multipart = False, show_error = True): + def urlopen(self, url, timeout = 30, params = None, headers = None, opener = None, multipart = False, show_error = True): + + if not headers: headers = {} + if not params: params = {} # Fill in some headers if not headers.get('Referer'): diff --git a/couchpotato/core/plugins/manage/main.py b/couchpotato/core/plugins/manage/main.py index bea2fe4..bf739a6 100644 --- a/couchpotato/core/plugins/manage/main.py +++ b/couchpotato/core/plugins/manage/main.py @@ -73,6 +73,13 @@ class Manage(Plugin): for done_movie in done_movies: if done_movie['library']['identifier'] not in added_identifiers: fireEvent('movie.delete', movie_id = done_movie['id'], delete_from = 'all') + else: + for release in done_movie.get('releases', []): + for release_file in release.get('files', []): + # Remove release not available anymore + if not os.path.isfile(release_file['path']): + fireEvent('release.clean', release['id']) + break Env.prop('manage.last_update', time.time()) diff --git a/couchpotato/core/plugins/movie/static/movie.js b/couchpotato/core/plugins/movie/static/movie.js index d71eb64..1ce0af7 100644 --- a/couchpotato/core/plugins/movie/static/movie.js +++ b/couchpotato/core/plugins/movie/static/movie.js @@ -357,7 +357,7 @@ var ReleaseAction = new Class({ Array.each(self.movie.data.releases, function(release){ var status = Status.get(release.status_id), - quality = Quality.getProfile(release.quality_id), + quality = Quality.getProfile(release.quality_id) || {}, info = release.info; try { @@ -365,7 +365,8 @@ var ReleaseAction = new Class({ } catch(e){} new Element('div', { - 'class': 'item '+status.identifier + 'class': 'item '+status.identifier, + 'id': 'release_'+release.id }).adopt( new Element('span.name', {'text': self.get(release, 'name'), 'title': self.get(release, 'name')}), new Element('span.status', {'text': status.identifier, 'class': 'release_status '+status.identifier}), @@ -382,7 +383,8 @@ var ReleaseAction = new Class({ 'events': { 'click': function(e){ (e).preventDefault(); - self.download(release); + if(!this.hasClass('completed')) + self.download(release); } } }), @@ -414,9 +416,21 @@ var ReleaseAction = new Class({ download: function(release){ var self = this; + var release_el = self.release_container.getElement('#release_'+release.id), + icon = release_el.getElement('.download.icon'); + + icon.addClass('spinner'); + Api.request('release.download', { 'data': { 'id': release.id + }, + 'onComplete': function(json){ + icon.removeClass('spinner') + if(json.success) + icon.addClass('completed'); + else + icon.addClass('attention').set('title', 'Something went wrong when downloading, please check logs.'); } }); }, @@ -456,7 +470,7 @@ var TrailerAction = new Class({ var data_url = 'http://gdata.youtube.com/feeds/videos?vq="{title}" {year} trailer&max-results=1&alt=json-in-script&orderby=relevance&sortorder=descending&format=5&fmt=18' var url = data_url.substitute({ - 'title': self.movie.getTitle(), + 'title': encodeURI(self.movie.getTitle()), 'year': self.movie.get('year'), 'offset': offset || 1 }), diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index 10de054..ba79d9f 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -7,6 +7,7 @@ from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.scanner.main import Scanner from couchpotato.core.settings.model import File, Release as Relea, Movie from sqlalchemy.sql.expression import and_, or_ +import os log = CPLog(__name__) @@ -22,7 +23,7 @@ class Release(Plugin): 'id': {'type': 'id', 'desc': 'ID of the release object in release-table'} } }) - addApiView('release.delete', self.delete, docs = { + addApiView('release.delete', self.deleteView, docs = { 'desc': 'Delete releases', 'params': { 'id': {'type': 'id', 'desc': 'ID of the release object in release-table'} @@ -35,6 +36,9 @@ class Release(Plugin): } }) + addEvent('release.delete', self.delete) + addEvent('release.clean', self.clean) + def add(self, group): db = get_session() @@ -99,20 +103,41 @@ class Release(Plugin): # Check database and update/insert if necessary return fireEvent('file.add', path = filepath, part = fireEvent('scanner.partnumber', file, single = True), type_tuple = Scanner.file_types.get(type), properties = properties, single = True) - def delete(self): + def deleteView(self): + + release_id = getParam('id') + + #db.close() + return jsonified({ + 'success': self.delete(release_id) + }) + + def delete(self, id): db = get_session() - id = getParam('id') rel = db.query(Relea).filter_by(id = id).first() if rel: rel.delete() db.commit() + return True - #db.close() - return jsonified({ - 'success': True - }) + return False + + def clean(self, id): + + db = get_session() + + rel = db.query(Relea).filter_by(id = id).first() + if rel: + for release_file in rel.files: + if not os.path.isfile(release_file.path): + db.delete(release_file) + db.commit() + + return True + + return False def ignore(self): @@ -146,16 +171,16 @@ class Release(Plugin): provider = fireEvent('provider.belongs_to', item['url'], provider = item.get('provider'), single = True) item['download'] = provider.download - fireEvent('searcher.download', data = item, movie = rel.movie.to_dict({ + success = fireEvent('searcher.download', data = item, movie = rel.movie.to_dict({ 'profile': {'types': {'quality': {}}}, 'releases': {'status': {}, 'quality': {}}, 'library': {'titles': {}, 'files':{}}, 'files': {} - }), manual = True) + }), manual = True, single = True) #db.close() return jsonified({ - 'success': True + 'success': success }) else: log.error('Couldn\'t find release with id: %s', id) diff --git a/couchpotato/core/plugins/renamer/__init__.py b/couchpotato/core/plugins/renamer/__init__.py index 9ceccb8..5943954 100644 --- a/couchpotato/core/plugins/renamer/__init__.py +++ b/couchpotato/core/plugins/renamer/__init__.py @@ -84,7 +84,7 @@ config = [{ 'advanced': True, 'name': 'separator', 'label': 'Separator', - 'description': 'Replace all the spaces with a character. Example: ".", "-". Leave empty to use spaces.', + 'description': 'Replace all the spaces with a character. Example: ".", "-" (without quotes). Leave empty to use spaces.', }, { 'advanced': True, diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 50f7e13..e75ab5c 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -165,7 +165,6 @@ class Renamer(Plugin): # Group filename without cd extension replacements['cd'] = '' replacements['cd_nr'] = '' - group['filename'] = self.doReplace(file_name, replacements)[:-(len(getExt(final_file_name)) + 1)] # Meta naming if file_type is 'trailer': @@ -238,6 +237,7 @@ class Renamer(Plugin): ) rename_files = mergeDicts(rename_files, rename_extras) + group['filename'] = self.doReplace(file_name, replacements)[:-(len(getExt(final_file_name)) + 1)] group['destination_dir'] = os.path.join(destination, final_folder_name) if multiple: diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 9ebdec6..03eb6cf 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -29,9 +29,6 @@ class Searcher(Plugin): # Schedule cronjob fireEvent('schedule.cron', 'searcher.all', self.all_movies, day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute')) - - addEvent('app.load', self.all_movies) - def all_movies(self): if self.in_progress: diff --git a/couchpotato/core/plugins/subtitle/main.py b/couchpotato/core/plugins/subtitle/main.py index 0efb911..9ff39f4 100644 --- a/couchpotato/core/plugins/subtitle/main.py +++ b/couchpotato/core/plugins/subtitle/main.py @@ -54,11 +54,12 @@ class Subtitle(Plugin): for lang in self.getLanguages(): if lang not in available_languages: download = subliminal.download_subtitles(files, multi = True, force = False, languages = [lang], services = self.services, cache_dir = Env.get('cache_dir')) - downloaded.extend(download) + for subtitle in download: + downloaded.extend(download[subtitle]) for d_sub in downloaded: group['files']['subtitle'].add(d_sub.path) - group['subtitle_language'][d_sub.path] = [d_sub.language] + group['subtitle_language'][d_sub.path] = [d_sub.language.alpha2] return True diff --git a/couchpotato/core/providers/torrent/kickasstorrents/main.py b/couchpotato/core/providers/torrent/kickasstorrents/main.py index 2c9b893..c57ae8a 100644 --- a/couchpotato/core/providers/torrent/kickasstorrents/main.py +++ b/couchpotato/core/providers/torrent/kickasstorrents/main.py @@ -1,6 +1,6 @@ from bs4 import BeautifulSoup from couchpotato.core.event import fireEvent -from couchpotato.core.helpers.variable import tryInt, getTitle +from couchpotato.core.helpers.variable import tryInt from couchpotato.core.logger import CPLog from couchpotato.core.providers.torrent.base import TorrentProvider import StringIO @@ -16,7 +16,7 @@ class KickAssTorrents(TorrentProvider): urls = { 'test': 'http://www.kat.ph/', 'detail': 'http://www.kat.ph/%s-t%s.html', - 'search': 'http://www.kat.ph/%s-i%s/', + 'search': 'http://www.kat.ph/i%s/', 'download': 'http://torcache.net/', } @@ -30,6 +30,7 @@ class KickAssTorrents(TorrentProvider): ] http_time_between_calls = 1 #seconds + cat_backup_id = None def search(self, movie, quality): @@ -38,7 +39,7 @@ class KickAssTorrents(TorrentProvider): return results cache_key = 'kickasstorrents.%s.%s' % (movie['library']['identifier'], quality.get('identifier')) - data = self.getCache(cache_key, self.urls['search'] % (getTitle(movie['library']), movie['library']['identifier'].replace('tt', ''))) + data = self.getCache(cache_key, self.urls['search'] % (movie['library']['identifier'].replace('tt', ''))) if data: cat_ids = self.getCatId(quality['identifier']) diff --git a/couchpotato/core/providers/torrent/torrentleech/main.py b/couchpotato/core/providers/torrent/torrentleech/main.py index e106a5a..c174a3d 100644 --- a/couchpotato/core/providers/torrent/torrentleech/main.py +++ b/couchpotato/core/providers/torrent/torrentleech/main.py @@ -52,6 +52,9 @@ class TorrentLeech(TorrentProvider): try: result_table = html.find('table', attrs = {'id' : 'torrenttable'}) + if not result_table: + return results + entries = result_table.find_all('tr') for result in entries[1:]: diff --git a/couchpotato/static/images/icon.attention.png b/couchpotato/static/images/icon.attention.png new file mode 100644 index 0000000..9878676 Binary files /dev/null and b/couchpotato/static/images/icon.attention.png differ diff --git a/couchpotato/static/images/icon.spinner.gif b/couchpotato/static/images/icon.spinner.gif new file mode 100644 index 0000000..4abd886 Binary files /dev/null and b/couchpotato/static/images/icon.spinner.gif differ diff --git a/couchpotato/static/scripts/page/wanted.js b/couchpotato/static/scripts/page/wanted.js index 6c918ce..5f2dcf7 100644 --- a/couchpotato/static/scripts/page/wanted.js +++ b/couchpotato/static/scripts/page/wanted.js @@ -244,6 +244,7 @@ window.addEvent('domready', function(){ MovieActions.Done = { 'IMDB': IMDBAction ,'Edit': MovieActions.Wanted.Edit + ,'Trailer': TrailerAction ,'Files': new Class({ Extends: MovieAction, diff --git a/couchpotato/static/style/main.css b/couchpotato/static/style/main.css index f5630f3..183374b 100644 --- a/couchpotato/static/style/main.css +++ b/couchpotato/static/style/main.css @@ -147,7 +147,7 @@ body > .spinner, .mask{ .icon.delete { background-image: url('../images/icon.delete.png'); } .icon.download { background-image: url('../images/icon.download.png'); } .icon.edit { background-image: url('../images/icon.edit.png'); } -.icon.check { background-image: url('../images/icon.check.png'); } +.icon.completed { background-image: url('../images/icon.check.png'); } .icon.folder { background-image: url('../images/icon.folder.png'); } .icon.imdb { background-image: url('../images/icon.imdb.png'); } .icon.refresh { background-image: url('../images/icon.refresh.png'); } @@ -155,6 +155,8 @@ body > .spinner, .mask{ .icon.files { background-image: url('../images/icon.files.png'); } .icon.info { background-image: url('../images/icon.info.png'); } .icon.trailer { background-image: url('../images/icon.trailer.png'); } +.icon.spinner { background-image: url('../images/icon.spinner.gif'); } +.icon.attention { background-image: url('../images/icon.attention.png'); } /*** Navigation ***/ .header { @@ -313,7 +315,7 @@ body > .spinner, .mask{ .header .message.update { text-align: center; position: relative; - top: -100px; + top: -70px; padding: 2px 0; background: #ff6134; font-size: 12px;