diff --git a/couchpotato/core/_base/_core/main.py b/couchpotato/core/_base/_core/main.py index 58bd1d1..0e178de 100644 --- a/couchpotato/core/_base/_core/main.py +++ b/couchpotato/core/_base/_core/main.py @@ -53,7 +53,7 @@ class Core(Plugin): def md5Password(self, value): - return md5(value) if value else '' + return md5(value.encode(Env.get('encoding'))) if value else '' def checkApikey(self, value): return value if value and len(value) > 3 else uuid4().hex diff --git a/couchpotato/core/_base/updater/main.py b/couchpotato/core/_base/updater/main.py index 73b5f68..980e247 100644 --- a/couchpotato/core/_base/updater/main.py +++ b/couchpotato/core/_base/updater/main.py @@ -14,6 +14,7 @@ import shutil import tarfile import time import traceback +import version log = CPLog(__name__) @@ -102,6 +103,8 @@ class Updater(Plugin): success = False else: success = self.updater.doUpdate() + if success: + fireEventAsync('app.restart') return jsonified({ 'success': success @@ -112,7 +115,7 @@ class BaseUpdater(Plugin): repo_user = 'RuudBurger' repo_name = 'CouchPotatoServer' - branch = 'desktop' + branch = version.BRANCH version = None update_failed = False diff --git a/couchpotato/core/auth.py b/couchpotato/core/auth.py index 032bdf2..0111b9a 100644 --- a/couchpotato/core/auth.py +++ b/couchpotato/core/auth.py @@ -17,8 +17,9 @@ def requires_auth(f): @wraps(f) def decorated(*args, **kwargs): auth = getattr(request, 'authorization') - if Env.setting('username') and Env.setting('password') and (not auth or not check_auth(auth.username, md5(auth.password))): - return authenticate() + if Env.setting('username') and Env.setting('password'): + if (not auth or not check_auth(auth.username.decode('latin1'), md5(auth.password.decode('latin1').encode(Env.get('encoding'))))): + return authenticate() return f(*args, **kwargs) diff --git a/couchpotato/core/downloaders/transmission/main.py b/couchpotato/core/downloaders/transmission/main.py index 1819f31..5bdd65b 100644 --- a/couchpotato/core/downloaders/transmission/main.py +++ b/couchpotato/core/downloaders/transmission/main.py @@ -4,6 +4,7 @@ from couchpotato.core.helpers.encoding import isInt from couchpotato.core.logger import CPLog import httplib import json +import os.path import re import urllib2 @@ -31,7 +32,7 @@ class Transmission(Downloader): # Set parameters for Transmission params = { 'paused': self.conf('paused', default = 0), - 'download-dir': self.conf('directory', default = None) + 'download-dir': self.conf('directory', default = '').rstrip(os.path.sep) } torrent_params = { diff --git a/couchpotato/core/helpers/request.py b/couchpotato/core/helpers/request.py index 07aa18e..3c6558b 100644 --- a/couchpotato/core/helpers/request.py +++ b/couchpotato/core/helpers/request.py @@ -2,8 +2,8 @@ from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.variable import natcmp from flask.globals import current_app from flask.helpers import json, make_response -from libs.werkzeug.urls import url_decode from urllib import unquote +from werkzeug.urls import url_decode import flask import re @@ -57,7 +57,7 @@ def dictToList(params): def getParam(attr, default = None): try: - return toUnicode(unquote(getattr(flask.request, 'args').get(attr, default))) + return getParams().get(attr, default) except: return default diff --git a/couchpotato/core/helpers/variable.py b/couchpotato/core/helpers/variable.py index 1f1d3ba..5312177 100644 --- a/couchpotato/core/helpers/variable.py +++ b/couchpotato/core/helpers/variable.py @@ -105,7 +105,7 @@ def tryInt(s): def tryFloat(s): try: return float(s) if '.' in s else tryInt(s) - except: return s + except: return 0 def natsortKey(s): return map(tryInt, re.findall(r'(\d+|\D+)', s)) diff --git a/couchpotato/core/notifications/growl/__init__.py b/couchpotato/core/notifications/growl/__init__.py index 3e882b4..82a6636 100644 --- a/couchpotato/core/notifications/growl/__init__.py +++ b/couchpotato/core/notifications/growl/__init__.py @@ -9,6 +9,7 @@ config = [{ { 'tab': 'notifications', 'name': 'growl', + 'description': 'Version 1.4+', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/notifications/plex/main.py b/couchpotato/core/notifications/plex/main.py index 23fd39d..fed9f5e 100644 --- a/couchpotato/core/notifications/plex/main.py +++ b/couchpotato/core/notifications/plex/main.py @@ -1,8 +1,10 @@ from couchpotato.core.event import addEvent from couchpotato.core.helpers.encoding import tryUrlencode +from couchpotato.core.helpers.request import jsonified from couchpotato.core.helpers.variable import cleanHost from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification +from urllib2 import URLError from xml.dom import minidom import traceback @@ -38,7 +40,7 @@ class Plex(Notification): x = self.urlopen(url) except: - log.error('Plex library update failed for %s: %s', (host, traceback.format_exc())) + log.error('Plex library update failed for %s, Media Server not running: %s', (host, traceback.format_exc(1))) return False return True @@ -62,9 +64,27 @@ class Plex(Notification): try: self.urlopen(url, headers = headers, show_error = False) + except URLError: + log.error("Couldn't sent command to Plex, probably just running Media Server") + return False except: log.error("Couldn't sent command to Plex: %s", traceback.format_exc()) return False log.info('Plex notification to %s successful.', host) return True + + def test(self): + + test_type = self.testNotifyName() + + log.info('Sending test to %s', test_type) + + success = self.notify( + message = self.test_message, + data = {}, + listener = 'test' + ) + success2 = self.addToLibrary() + + return jsonified({'success': success or success2}) diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 92f6f8c..32e4fab 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -1,3 +1,4 @@ +from StringIO import StringIO from couchpotato import addView from couchpotato.core.event import fireEvent, addEvent from couchpotato.core.helpers.encoding import tryUrlencode, simplifyString, ss @@ -9,6 +10,7 @@ from multipartpost import MultipartPostHandler from urlparse import urlparse import cookielib import glob +import gzip import math import os.path import re @@ -101,10 +103,10 @@ class Plugin(object): if not params: params = {} # Fill in some headers - if not headers.get('Referer'): - headers['Referer'] = urlparse(url).hostname - if not headers.get('User-Agent'): - headers['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0.2) Gecko/20100101 Firefox/10.0.2' + headers['Referer'] = headers.get('Referer', urlparse(url).hostname) + headers['Host'] = headers.get('Host', urlparse(url).hostname) + headers['User-Agent'] = headers.get('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0.2) Gecko/20100101 Firefox/10.0.2') + headers['Accept-encoding'] = headers.get('Accept-encoding', 'gzip') host = urlparse(url).hostname @@ -127,16 +129,24 @@ class Plugin(object): cookies = cookielib.CookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookies), MultipartPostHandler) - data = opener.open(request, timeout = timeout).read() + response = opener.open(request, timeout = timeout) else: log.info('Opening url: %s, params: %s', (url, [x for x in params.iterkeys()])) data = tryUrlencode(params) if len(params) > 0 else None request = urllib2.Request(url, data, headers) if opener: - data = opener.open(request, timeout = timeout).read() + response = opener.open(request, timeout = timeout) else: - data = urllib2.urlopen(request, timeout = timeout).read() + response = urllib2.urlopen(request, timeout = timeout) + + # unzip if needed + if response.info().get('Content-Encoding') == 'gzip': + buf = StringIO(response.read()) + f = gzip.GzipFile(fileobj = buf) + data = f.read() + else: + data = response.read() self.http_failed_request[host] = 0 except IOError: diff --git a/couchpotato/core/plugins/manage/main.py b/couchpotato/core/plugins/manage/main.py index bf739a6..aa46d70 100644 --- a/couchpotato/core/plugins/manage/main.py +++ b/couchpotato/core/plugins/manage/main.py @@ -1,5 +1,6 @@ from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, addEvent, fireEventAsync +from couchpotato.core.helpers.encoding import ss from couchpotato.core.helpers.request import jsonified, getParam from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin @@ -77,7 +78,7 @@ class Manage(Plugin): 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']): + if not os.path.isfile(ss(release_file['path'])): fireEvent('release.clean', release['id']) break diff --git a/couchpotato/core/plugins/movie/static/movie.js b/couchpotato/core/plugins/movie/static/movie.js index 1ce0af7..92a66ef 100644 --- a/couchpotato/core/plugins/movie/static/movie.js +++ b/couchpotato/core/plugins/movie/static/movie.js @@ -370,7 +370,7 @@ var ReleaseAction = new Class({ }).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}), - new Element('span.quality', {'text': quality.get('label')}), + new Element('span.quality', {'text': quality.label || 'n/a'}), new Element('span.size', {'text': (self.get(release, 'size'))}), new Element('span.age', {'text': self.get(release, 'age')}), new Element('span.score', {'text': self.get(release, 'score')}), diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index ba79d9f..0abc065 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -1,6 +1,7 @@ from couchpotato import get_session from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, addEvent +from couchpotato.core.helpers.encoding import ss from couchpotato.core.helpers.request import getParam, jsonified from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin @@ -131,7 +132,7 @@ class Release(Plugin): 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): + if not os.path.isfile(ss(release_file.path)): db.delete(release_file) db.commit() diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index e75ab5c..2cd09e4 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -1,7 +1,7 @@ from couchpotato import get_session from couchpotato.api import addApiView from couchpotato.core.event import addEvent, fireEvent, fireEventAsync -from couchpotato.core.helpers.encoding import toUnicode +from couchpotato.core.helpers.encoding import toUnicode, ss from couchpotato.core.helpers.request import jsonified from couchpotato.core.helpers.variable import getExt, mergeDicts, getTitle from couchpotato.core.logger import CPLog @@ -12,6 +12,7 @@ import os import re import shutil import traceback +import errno log = CPLog(__name__) @@ -419,6 +420,7 @@ class Renamer(Plugin): raise def moveFile(self, old, dest): + dest = ss(dest) try: shutil.move(old, dest) @@ -427,6 +429,14 @@ class Renamer(Plugin): except: log.error('Failed setting permissions for file: %s, %s', (dest, traceback.format_exc(1))) + except OSError, err: + # Copying from a filesystem with octal permission to an NTFS file system causes a permission error. In this case ignore it. + if not hasattr(os, 'chmod') or err.errno != errno.EPERM: + raise + else: + if os.path.exists(dest): + os.unlink(old) + except: log.error('Couldn\'t move file "%s" to "%s": %s', (old, dest, traceback.format_exc())) raise Exception diff --git a/couchpotato/core/plugins/scanner/main.py b/couchpotato/core/plugins/scanner/main.py index 43547b8..7e47ed9 100644 --- a/couchpotato/core/plugins/scanner/main.py +++ b/couchpotato/core/plugins/scanner/main.py @@ -74,8 +74,6 @@ class Scanner(Plugin): cp_imdb = '(\.cp\((?Ptt[0-9{7}]+)\))' - path_identifiers = {} # bind identifier to filepath - def __init__(self): addEvent('scanner.create_file_identifier', self.createStringIdentifier) @@ -222,18 +220,19 @@ class Scanner(Plugin): # Create identifiers for all leftover files + path_identifiers = {} for file_path in leftovers: identifier = self.createStringIdentifier(file_path, folder) - if not self.path_identifiers.get(identifier): - self.path_identifiers[identifier] = [] + if not path_identifiers.get(identifier): + path_identifiers[identifier] = [] - self.path_identifiers[identifier].append(file_path) + path_identifiers[identifier].append(file_path) # Group the files based on the identifier delete_identifiers = [] - for identifier, found_files in self.path_identifiers.iteritems(): + for identifier, found_files in path_identifiers.iteritems(): log.debug('Grouping files on identifier: %s', identifier) group = movie_files.get(identifier) @@ -250,13 +249,13 @@ class Scanner(Plugin): # Cleaning up used for identifier in delete_identifiers: - if self.path_identifiers.get(identifier): - del self.path_identifiers[identifier] + if path_identifiers.get(identifier): + del path_identifiers[identifier] del delete_identifiers # Group based on folder delete_identifiers = [] - for identifier, found_files in self.path_identifiers.iteritems(): + for identifier, found_files in path_identifiers.iteritems(): log.debug('Grouping files on foldername: %s', identifier) for ff in found_files: @@ -276,8 +275,8 @@ class Scanner(Plugin): # Cleaning up used for identifier in delete_identifiers: - if self.path_identifiers.get(identifier): - del self.path_identifiers[identifier] + if path_identifiers.get(identifier): + del path_identifiers[identifier] del delete_identifiers # Determine file types @@ -388,14 +387,11 @@ class Scanner(Plugin): processed_movies[identifier] = group - - # Clean up - self.path_identifiers = {} - if len(processed_movies) > 0: log.info('Found %s movies in the folder %s', (len(processed_movies), folder)) else: log.debug('Found no movies in the folder %s', (folder)) + return processed_movies def getMetaData(self, group): diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 03eb6cf..dfefdab 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -429,8 +429,8 @@ class Searcher(Plugin): if dates.get('dvd') > 0: - # 3 weeks before dvd release - if dates.get('dvd') - 1814400 < now: + # 4 weeks before dvd release + if dates.get('dvd') - 2419200 < now: return True # Dvd should be released diff --git a/couchpotato/core/plugins/userscript/template.js b/couchpotato/core/plugins/userscript/template.js index e200afb..8b07272 100644 --- a/couchpotato/core/plugins/userscript/template.js +++ b/couchpotato/core/plugins/userscript/template.js @@ -12,8 +12,7 @@ // ==/UserScript== -if (window.top != window.self) // Only run on top window - return; +if (window.top == window.self){ // Only run on top window var version = {{version}}, host = '{{host}}', @@ -135,4 +134,6 @@ var setVersion = function(){ if(document.location.href.indexOf(host) == -1) osd(); else - setVersion(); \ No newline at end of file + setVersion(); + +} \ No newline at end of file diff --git a/couchpotato/core/providers/automation/base.py b/couchpotato/core/providers/automation/base.py index df04b13..d3af263 100644 --- a/couchpotato/core/providers/automation/base.py +++ b/couchpotato/core/providers/automation/base.py @@ -27,36 +27,31 @@ class Automation(Plugin): return self.getIMDBids() - def search(self, name, year = None): + def search(self, name, year = None, imdb_only = False): result = fireEvent('movie.search', q = '%s %s' % (name, year if year else ''), limit = 1, merge = True) if len(result) > 0: - return result[0].get('imdb') + return result[0].get('imdb') if imdb_only else result[0] else: return None def isMinimalMovie(self, movie): + if not movie.get('rating'): + return False + if movie['rating'] and movie['rating'].get('imdb'): movie['votes'] = movie['rating']['imdb'][1] movie['rating'] = movie['rating']['imdb'][0] - identifier = movie['imdb'] + for minimal_type in ['year', 'rating', 'votes']: type_value = movie.get(minimal_type, 0) type_min = self.getMinimal(minimal_type) if type_value < type_min: - log.info('%s too low for %s, need %s has %s', (minimal_type, identifier, type_min, type_value)) + log.info('%s too low for %s, need %s has %s', (minimal_type, movie['imdb'], type_min, type_value)) return False return True - def getIMDBFromTitle(self, name, year = None): - result = fireEvent('movie.search', q = '%s %s' % (name, year), limit = 1, merge = True) - - if len(result) > 0: - return result[0] - else: - return None - def getMinimal(self, min_type): return Env.setting(min_type, 'automation') diff --git a/couchpotato/core/providers/automation/bluray/main.py b/couchpotato/core/providers/automation/bluray/main.py index cd7c0c9..20f733b 100644 --- a/couchpotato/core/providers/automation/bluray/main.py +++ b/couchpotato/core/providers/automation/bluray/main.py @@ -1,5 +1,5 @@ from couchpotato.core.helpers.rss import RSS -from couchpotato.core.helpers.variable import md5 +from couchpotato.core.helpers.variable import md5, tryInt from couchpotato.core.logger import CPLog from couchpotato.core.providers.automation.base import Automation from couchpotato.environment import Env @@ -19,41 +19,25 @@ class Bluray(Automation, RSS): return movies = [] - RSSMovie = {'name': 'placeholder', 'year' : 'placeholder'} - RSSMovies = [] cache_key = 'bluray.%s' % md5(self.rss_url) rss_data = self.getCache(cache_key, self.rss_url) data = XMLTree.fromstring(rss_data) - if data: + if data is not None: rss_movies = self.getElements(data, 'channel/item') for movie in rss_movies: - RSSMovie['name'] = self.getTextElement(movie, "title").lower().split("blu-ray")[0].strip("(").rstrip() - RSSMovie['year'] = self.getTextElement(movie, "description").split("|")[1].strip("(").strip() + name = self.getTextElement(movie, "title").lower().split("blu-ray")[0].strip("(").rstrip() + year = self.getTextElement(movie, "description").split("|")[1].strip("(").strip() - if not RSSMovie['name'].find("/") == -1: # make sure it is not a double movie release + if not name.find("/") == -1: # make sure it is not a double movie release continue - if int(RSSMovie['year']) < Env.setting('year', 'automation'): #do year filtering + if tryInt(year) < self.getMinimal('year'): continue - for test in RSSMovies: - if test.values() == RSSMovie.values(): # make sure we did not already include it... - break - else: - log.info('Release found: %s.' % RSSMovie) - RSSMovies.append(RSSMovie.copy()) - - if not RSSMovies: - log.info('No movies found.') - return - - log.debug("Applying IMDB filter to found movies...") - - for RSSMovie in RSSMovies: - imdb = self.getIMDBFromTitle(RSSMovie['name'] + ' ' + RSSMovie['year']) + imdb = self.search(name, year) if imdb: if self.isMinimalMovie(imdb): diff --git a/couchpotato/core/providers/automation/kinepolis/main.py b/couchpotato/core/providers/automation/kinepolis/main.py index 031bb44..f6633af 100644 --- a/couchpotato/core/providers/automation/kinepolis/main.py +++ b/couchpotato/core/providers/automation/kinepolis/main.py @@ -19,7 +19,6 @@ class Kinepolis(Automation, RSS): return movies = [] - RSSMovie = {'name': 'placeholder', 'year' : 'placeholder'} cache_key = 'kinepolis.%s' % md5(self.rss_url) rss_data = self.getCache(cache_key, self.rss_url) @@ -29,14 +28,12 @@ class Kinepolis(Automation, RSS): rss_movies = self.getElements(data, 'channel/item') for movie in rss_movies: - RSSMovie['name'] = self.getTextElement(movie, "title") - currentYear = datetime.datetime.now().strftime("%Y") - RSSMovie['year'] = currentYear + name = self.getTextElement(movie, "title") + year = datetime.datetime.now().strftime("%Y") - log.debug('Release found: %s.', RSSMovie) - imdb = self.getIMDBFromTitle(RSSMovie['name'], RSSMovie['year']) + imdb = self.search(name, year) - if imdb: + if imdb and self.isMinimalMovie(imdb): movies.append(imdb['imdb']) return movies diff --git a/couchpotato/core/providers/automation/movies_io/__init__.py b/couchpotato/core/providers/automation/movies_io/__init__.py new file mode 100644 index 0000000..5d997e9 --- /dev/null +++ b/couchpotato/core/providers/automation/movies_io/__init__.py @@ -0,0 +1,33 @@ +from .main import MoviesIO + +def start(): + return MoviesIO() + +config = [{ + 'name': 'moviesio', + 'groups': [ + { + 'tab': 'automation', + 'name': 'moviesio', + 'label': 'Movies.IO', + 'description': 'Imports movies from Movies.io RSS watchlists', + 'options': [ + { + 'name': 'automation_enabled', + 'default': False, + 'type': 'enabler', + }, + { + 'name': 'automation_urls_use', + 'label': 'Use', + }, + { + 'name': 'automation_urls', + 'label': 'url', + 'type': 'combined', + 'combine': ['automation_urls_use', 'automation_urls'], + }, + ], + }, + ], +}] diff --git a/couchpotato/core/providers/automation/movies_io/main.py b/couchpotato/core/providers/automation/movies_io/main.py new file mode 100644 index 0000000..3a5a2f0 --- /dev/null +++ b/couchpotato/core/providers/automation/movies_io/main.py @@ -0,0 +1,69 @@ +from couchpotato.core.event import fireEvent +from couchpotato.core.helpers.rss import RSS +from couchpotato.core.helpers.variable import md5 +from couchpotato.core.logger import CPLog +from couchpotato.core.providers.automation.base import Automation +from couchpotato.environment import Env +from dateutil.parser import parse +from xml.etree.ElementTree import ParseError +import time +import traceback +import xml.etree.ElementTree as XMLTree + +log = CPLog(__name__) + + +class MoviesIO(Automation, RSS): + + interval = 1800 + + def getIMDBids(self): + + if self.isDisabled(): + return + + movies = [] + + enablers = self.conf('automation_urls_use').split(',') + + index = -1 + for rss_url in self.conf('automation_urls').split(','): + + index += 1 + if not enablers[index]: + continue + + prop_name = 'automation.moviesio.last_update.%s' % md5(rss_url) + last_update = float(Env.prop(prop_name, default = 0)) + + last_movie_added = 0 + try: + cache_key = 'imdb.rss.%s' % md5(rss_url) + + rss_data = self.getCache(cache_key, rss_url, headers = {'Referer': ''}) + data = XMLTree.fromstring(rss_data) + rss_movies = self.getElements(data, 'channel/item') + + for movie in rss_movies: + created = int(time.mktime(parse(self.getTextElement(movie, "pubDate")).timetuple())) + + if created > last_movie_added: + last_movie_added = created + if created <= last_update: + continue + + nameyear = fireEvent('scanner.name_year', self.getTextElement(movie, "title"), single = True) + imdb = self.search(nameyear.get('name'), nameyear.get('year'), imdb_only = True) + + if not imdb: + continue + + movies.append(imdb) + except ParseError: + log.debug('Failed loading Movies.io watchlist, probably empty: %s', (rss_url)) + except: + log.error('Failed loading Movies.io watchlist: %s %s', (rss_url, traceback.format_exc())) + + Env.prop(prop_name, last_movie_added) + + return movies diff --git a/couchpotato/core/providers/base.py b/couchpotato/core/providers/base.py index d25377b..3e9ef26 100644 --- a/couchpotato/core/providers/base.py +++ b/couchpotato/core/providers/base.py @@ -1,14 +1,13 @@ from couchpotato.core.event import addEvent +from couchpotato.core.helpers.variable import tryFloat from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.environment import Env from urlparse import urlparse -from urllib import quote_plus -from couchpotato.core.helpers.encoding import simplifyString - import re import time + log = CPLog(__name__) @@ -86,19 +85,19 @@ class YarrProvider(Provider): def parseSize(self, size): sizeRaw = size.lower() - size = float(re.sub(r'[^0-9.]', '', size).strip()) + size = tryFloat(re.sub(r'[^0-9.]', '', size).strip()) for s in self.sizeGb: if s in sizeRaw: - return int(size) * 1024 + return size * 1024 for s in self.sizeMb: if s in sizeRaw: - return int(size) + return size for s in self.sizeKb: if s in sizeRaw: - return int(size) / 1024 + return size / 1024 return 0 diff --git a/couchpotato/core/providers/movie/imdbapi/main.py b/couchpotato/core/providers/movie/imdbapi/main.py index 535e6b2..c81a9ab 100644 --- a/couchpotato/core/providers/movie/imdbapi/main.py +++ b/couchpotato/core/providers/movie/imdbapi/main.py @@ -13,15 +13,14 @@ log = CPLog(__name__) class IMDBAPI(MovieProvider): urls = { - 'search': 'http://www.imdbapi.com/?%s', - 'info': 'http://www.imdbapi.com/?i=%s', + 'search': 'http://www.imdbapi.com/?tomatoes=true&%s', + 'info': 'http://www.imdbapi.com/?tomatoes=true&i=%s', } http_time_between_calls = 0 def __init__(self): addEvent('movie.search', self.search) - addEvent('movie.searchimdb', self.search) addEvent('movie.info', self.getInfo) def search(self, q, limit = 12): @@ -72,7 +71,7 @@ class IMDBAPI(MovieProvider): log.info('No proper json to decode') return movie_data - if movie.get('Response') == 'Parse Error': + if movie.get('Response') == 'Parse Error' or movie.get('Response') == 'False': return movie_data tmp_movie = movie.copy() @@ -91,7 +90,7 @@ class IMDBAPI(MovieProvider): }, 'rating': { 'imdb': (tryFloat(movie.get('imdbRating', 0)), tryInt(movie.get('imdbVotes', '').replace(',', ''))), - #'rotten': (tryFloat(movie.get('tomatoRating', 0)), tryInt(movie.get('tomatoReviews', 0))), + 'rotten': (tryFloat(movie.get('tomatoRating', 0)), tryInt(movie.get('tomatoReviews', '').replace(',', ''))), }, 'imdb': str(movie.get('imdbID', '')), 'runtime': self.runtimeToMinutes(movie.get('Runtime', '')), diff --git a/couchpotato/core/providers/nzb/nzbmatrix/main.py b/couchpotato/core/providers/nzb/nzbmatrix/main.py index 203ada1..c6c5be9 100644 --- a/couchpotato/core/providers/nzb/nzbmatrix/main.py +++ b/couchpotato/core/providers/nzb/nzbmatrix/main.py @@ -43,7 +43,7 @@ class NZBMatrix(NZBProvider, RSS): 'username': self.conf('username'), 'apikey': self.conf('api_key'), 'searchin': 'weblink', - 'age': Env.setting('retention', section = 'nzb'), + 'maxage': Env.setting('retention', section = 'nzb'), 'english': self.conf('english_only'), }) url = "%s?%s" % (self.urls['search'], arguments) diff --git a/couchpotato/core/providers/torrent/sceneaccess/main.py b/couchpotato/core/providers/torrent/sceneaccess/main.py index 2054294..62cd7dc 100644 --- a/couchpotato/core/providers/torrent/sceneaccess/main.py +++ b/couchpotato/core/providers/torrent/sceneaccess/main.py @@ -1,8 +1,7 @@ from bs4 import BeautifulSoup from couchpotato.core.event import fireEvent -from couchpotato.core.helpers.encoding import simplifyString, tryUrlencode, \ - toUnicode -from couchpotato.core.helpers.variable import getTitle, tryInt +from couchpotato.core.helpers.encoding import tryUrlencode, toUnicode +from couchpotato.core.helpers.variable import tryInt from couchpotato.core.logger import CPLog from couchpotato.core.providers.torrent.base import TorrentProvider import traceback @@ -39,9 +38,10 @@ class SceneAccess(TorrentProvider): self.getCatId(quality['identifier'])[0] ) - q = '"%s %s" %s' % (simplifyString(getTitle(movie['library'])), movie['library']['year'], quality.get('identifier')) + q = '%s %s' % (movie['library']['identifier'], quality.get('identifier')) arguments = tryUrlencode({ 'search': q, + 'method': 1, }) url = "%s&%s" % (url, arguments) @@ -57,7 +57,10 @@ class SceneAccess(TorrentProvider): try: resultsTable = html.find('table', attrs = {'id' : 'torrents-table'}) - entries = resultsTable.findAll('tr', attrs = {'class' : 'tt_row'}) + if resultsTable is None: + return results + + entries = resultsTable.find_all('tr', attrs = {'class' : 'tt_row'}) for result in entries: link = result.find('td', attrs = {'class' : 'ttr_name'}).find('a') diff --git a/couchpotato/core/providers/userscript/moviesio/__init__.py b/couchpotato/core/providers/userscript/moviesio/__init__.py new file mode 100644 index 0000000..473f847 --- /dev/null +++ b/couchpotato/core/providers/userscript/moviesio/__init__.py @@ -0,0 +1,6 @@ +from .main import MoviesIO + +def start(): + return MoviesIO() + +config = [] diff --git a/couchpotato/core/providers/userscript/moviesio/main.py b/couchpotato/core/providers/userscript/moviesio/main.py new file mode 100644 index 0000000..5dab618 --- /dev/null +++ b/couchpotato/core/providers/userscript/moviesio/main.py @@ -0,0 +1,6 @@ +from couchpotato.core.providers.userscript.base import UserscriptBase + + +class MoviesIO(UserscriptBase): + + includes = ['*://movies.io/m/*'] diff --git a/couchpotato/core/providers/userscript/rottentomatoes/main.py b/couchpotato/core/providers/userscript/rottentomatoes/main.py index cd869b8..c611779 100644 --- a/couchpotato/core/providers/userscript/rottentomatoes/main.py +++ b/couchpotato/core/providers/userscript/rottentomatoes/main.py @@ -4,7 +4,10 @@ from couchpotato.core.providers.userscript.base import UserscriptBase class RottenTomatoes(UserscriptBase): - includes = ['*://www.rottentomatoes.com/m/*'] + includes = ['*://www.rottentomatoes.com/m/*/'] + excludes = ['*://www.rottentomatoes.com/m/*/*/'] + + version = 2 def getMovie(self, url): diff --git a/init/fedora b/init/fedora index 488027c..0adefd0 100644 --- a/init/fedora +++ b/init/fedora @@ -28,7 +28,7 @@ pidfile=${CP_PIDFILE-/var/run/couchpotato/couchpotato.pid} ## pidpath=`dirname ${pidfile}` -options=" --daemon --pidfile=${pidfile} --datadir=${datadir}" +options=" --daemon --pid_file=${pidfile} --datadir=${datadir}" # create PID directory if not exist and ensure the couchpotato user can write to it if [ ! -d $pidpath ]; then diff --git a/libs/tornado/netutil.py b/libs/tornado/netutil.py index ba0b27d..1f3f2e5 100755 --- a/libs/tornado/netutil.py +++ b/libs/tornado/netutil.py @@ -258,12 +258,6 @@ def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128): if address == "": address = None flags = socket.AI_PASSIVE - if hasattr(socket, "AI_ADDRCONFIG"): - # AI_ADDRCONFIG ensures that we only try to bind on ipv6 - # if the system is configured for it, but the flag doesn't - # exist on some platforms (specifically WinXP, although - # newer versions of windows have it) - flags |= socket.AI_ADDRCONFIG for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM, 0, flags)): af, socktype, proto, canonname, sockaddr = res diff --git a/version.py b/version.py index 3808ef1..2f61766 100644 --- a/version.py +++ b/version.py @@ -1 +1,2 @@ VERSION = '2.0.0.pre1' +BRANCH = 'desktop'