Browse Source

Merge branch 'refs/heads/develop' into desktop

Conflicts:
	couchpotato/core/_base/updater/main.py
tags/build/2.0.0.pre1
Ruud 13 years ago
parent
commit
cc408b980c
  1. 2
      couchpotato/core/_base/_core/main.py
  2. 5
      couchpotato/core/_base/updater/main.py
  3. 5
      couchpotato/core/auth.py
  4. 3
      couchpotato/core/downloaders/transmission/main.py
  5. 4
      couchpotato/core/helpers/request.py
  6. 2
      couchpotato/core/helpers/variable.py
  7. 1
      couchpotato/core/notifications/growl/__init__.py
  8. 22
      couchpotato/core/notifications/plex/main.py
  9. 24
      couchpotato/core/plugins/base.py
  10. 3
      couchpotato/core/plugins/manage/main.py
  11. 2
      couchpotato/core/plugins/movie/static/movie.js
  12. 3
      couchpotato/core/plugins/release/main.py
  13. 12
      couchpotato/core/plugins/renamer/main.py
  14. 26
      couchpotato/core/plugins/scanner/main.py
  15. 4
      couchpotato/core/plugins/searcher/main.py
  16. 7
      couchpotato/core/plugins/userscript/template.js
  17. 19
      couchpotato/core/providers/automation/base.py
  18. 30
      couchpotato/core/providers/automation/bluray/main.py
  19. 11
      couchpotato/core/providers/automation/kinepolis/main.py
  20. 33
      couchpotato/core/providers/automation/movies_io/__init__.py
  21. 69
      couchpotato/core/providers/automation/movies_io/main.py
  22. 13
      couchpotato/core/providers/base.py
  23. 9
      couchpotato/core/providers/movie/imdbapi/main.py
  24. 2
      couchpotato/core/providers/nzb/nzbmatrix/main.py
  25. 13
      couchpotato/core/providers/torrent/sceneaccess/main.py
  26. 6
      couchpotato/core/providers/userscript/moviesio/__init__.py
  27. 6
      couchpotato/core/providers/userscript/moviesio/main.py
  28. 5
      couchpotato/core/providers/userscript/rottentomatoes/main.py
  29. 2
      init/fedora
  30. 6
      libs/tornado/netutil.py
  31. 1
      version.py

2
couchpotato/core/_base/_core/main.py

@ -53,7 +53,7 @@ class Core(Plugin):
def md5Password(self, value): def md5Password(self, value):
return md5(value) if value else '' return md5(value.encode(Env.get('encoding'))) if value else ''
def checkApikey(self, value): def checkApikey(self, value):
return value if value and len(value) > 3 else uuid4().hex return value if value and len(value) > 3 else uuid4().hex

5
couchpotato/core/_base/updater/main.py

@ -14,6 +14,7 @@ import shutil
import tarfile import tarfile
import time import time
import traceback import traceback
import version
log = CPLog(__name__) log = CPLog(__name__)
@ -102,6 +103,8 @@ class Updater(Plugin):
success = False success = False
else: else:
success = self.updater.doUpdate() success = self.updater.doUpdate()
if success:
fireEventAsync('app.restart')
return jsonified({ return jsonified({
'success': success 'success': success
@ -112,7 +115,7 @@ class BaseUpdater(Plugin):
repo_user = 'RuudBurger' repo_user = 'RuudBurger'
repo_name = 'CouchPotatoServer' repo_name = 'CouchPotatoServer'
branch = 'desktop' branch = version.BRANCH
version = None version = None
update_failed = False update_failed = False

5
couchpotato/core/auth.py

@ -17,8 +17,9 @@ def requires_auth(f):
@wraps(f) @wraps(f)
def decorated(*args, **kwargs): def decorated(*args, **kwargs):
auth = getattr(request, 'authorization') auth = getattr(request, 'authorization')
if Env.setting('username') and Env.setting('password') and (not auth or not check_auth(auth.username, md5(auth.password))): if Env.setting('username') and Env.setting('password'):
return authenticate() 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) return f(*args, **kwargs)

3
couchpotato/core/downloaders/transmission/main.py

@ -4,6 +4,7 @@ from couchpotato.core.helpers.encoding import isInt
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
import httplib import httplib
import json import json
import os.path
import re import re
import urllib2 import urllib2
@ -31,7 +32,7 @@ class Transmission(Downloader):
# Set parameters for Transmission # Set parameters for Transmission
params = { params = {
'paused': self.conf('paused', default = 0), '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 = { torrent_params = {

4
couchpotato/core/helpers/request.py

@ -2,8 +2,8 @@ from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import natcmp from couchpotato.core.helpers.variable import natcmp
from flask.globals import current_app from flask.globals import current_app
from flask.helpers import json, make_response from flask.helpers import json, make_response
from libs.werkzeug.urls import url_decode
from urllib import unquote from urllib import unquote
from werkzeug.urls import url_decode
import flask import flask
import re import re
@ -57,7 +57,7 @@ def dictToList(params):
def getParam(attr, default = None): def getParam(attr, default = None):
try: try:
return toUnicode(unquote(getattr(flask.request, 'args').get(attr, default))) return getParams().get(attr, default)
except: except:
return default return default

2
couchpotato/core/helpers/variable.py

@ -105,7 +105,7 @@ def tryInt(s):
def tryFloat(s): def tryFloat(s):
try: return float(s) if '.' in s else tryInt(s) try: return float(s) if '.' in s else tryInt(s)
except: return s except: return 0
def natsortKey(s): def natsortKey(s):
return map(tryInt, re.findall(r'(\d+|\D+)', s)) return map(tryInt, re.findall(r'(\d+|\D+)', s))

1
couchpotato/core/notifications/growl/__init__.py

@ -9,6 +9,7 @@ config = [{
{ {
'tab': 'notifications', 'tab': 'notifications',
'name': 'growl', 'name': 'growl',
'description': 'Version 1.4+',
'options': [ 'options': [
{ {
'name': 'enabled', 'name': 'enabled',

22
couchpotato/core/notifications/plex/main.py

@ -1,8 +1,10 @@
from couchpotato.core.event import addEvent from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.request import jsonified
from couchpotato.core.helpers.variable import cleanHost from couchpotato.core.helpers.variable import cleanHost
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.notifications.base import Notification from couchpotato.core.notifications.base import Notification
from urllib2 import URLError
from xml.dom import minidom from xml.dom import minidom
import traceback import traceback
@ -38,7 +40,7 @@ class Plex(Notification):
x = self.urlopen(url) x = self.urlopen(url)
except: 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 False
return True return True
@ -62,9 +64,27 @@ class Plex(Notification):
try: try:
self.urlopen(url, headers = headers, show_error = False) 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: except:
log.error("Couldn't sent command to Plex: %s", traceback.format_exc()) log.error("Couldn't sent command to Plex: %s", traceback.format_exc())
return False return False
log.info('Plex notification to %s successful.', host) log.info('Plex notification to %s successful.', host)
return True 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})

24
couchpotato/core/plugins/base.py

@ -1,3 +1,4 @@
from StringIO import StringIO
from couchpotato import addView from couchpotato import addView
from couchpotato.core.event import fireEvent, addEvent from couchpotato.core.event import fireEvent, addEvent
from couchpotato.core.helpers.encoding import tryUrlencode, simplifyString, ss from couchpotato.core.helpers.encoding import tryUrlencode, simplifyString, ss
@ -9,6 +10,7 @@ from multipartpost import MultipartPostHandler
from urlparse import urlparse from urlparse import urlparse
import cookielib import cookielib
import glob import glob
import gzip
import math import math
import os.path import os.path
import re import re
@ -101,10 +103,10 @@ class Plugin(object):
if not params: params = {} if not params: params = {}
# Fill in some headers # Fill in some headers
if not headers.get('Referer'): headers['Referer'] = headers.get('Referer', urlparse(url).hostname)
headers['Referer'] = urlparse(url).hostname headers['Host'] = headers.get('Host', urlparse(url).hostname)
if not headers.get('User-Agent'): 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['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 host = urlparse(url).hostname
@ -127,16 +129,24 @@ class Plugin(object):
cookies = cookielib.CookieJar() cookies = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookies), MultipartPostHandler) opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookies), MultipartPostHandler)
data = opener.open(request, timeout = timeout).read() response = opener.open(request, timeout = timeout)
else: else:
log.info('Opening url: %s, params: %s', (url, [x for x in params.iterkeys()])) log.info('Opening url: %s, params: %s', (url, [x for x in params.iterkeys()]))
data = tryUrlencode(params) if len(params) > 0 else None data = tryUrlencode(params) if len(params) > 0 else None
request = urllib2.Request(url, data, headers) request = urllib2.Request(url, data, headers)
if opener: if opener:
data = opener.open(request, timeout = timeout).read() response = opener.open(request, timeout = timeout)
else: 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 self.http_failed_request[host] = 0
except IOError: except IOError:

3
couchpotato/core/plugins/manage/main.py

@ -1,5 +1,6 @@
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, addEvent, fireEventAsync 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.helpers.request import jsonified, getParam
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
@ -77,7 +78,7 @@ class Manage(Plugin):
for release in done_movie.get('releases', []): for release in done_movie.get('releases', []):
for release_file in release.get('files', []): for release_file in release.get('files', []):
# Remove release not available anymore # 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']) fireEvent('release.clean', release['id'])
break break

2
couchpotato/core/plugins/movie/static/movie.js

@ -370,7 +370,7 @@ var ReleaseAction = new Class({
}).adopt( }).adopt(
new Element('span.name', {'text': self.get(release, 'name'), 'title': self.get(release, 'name')}), 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.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.size', {'text': (self.get(release, 'size'))}),
new Element('span.age', {'text': self.get(release, 'age')}), new Element('span.age', {'text': self.get(release, 'age')}),
new Element('span.score', {'text': self.get(release, 'score')}), new Element('span.score', {'text': self.get(release, 'score')}),

3
couchpotato/core/plugins/release/main.py

@ -1,6 +1,7 @@
from couchpotato import get_session from couchpotato import get_session
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, addEvent 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.helpers.request import getParam, jsonified
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
@ -131,7 +132,7 @@ class Release(Plugin):
rel = db.query(Relea).filter_by(id = id).first() rel = db.query(Relea).filter_by(id = id).first()
if rel: if rel:
for release_file in rel.files: 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.delete(release_file)
db.commit() db.commit()

12
couchpotato/core/plugins/renamer/main.py

@ -1,7 +1,7 @@
from couchpotato import get_session from couchpotato import get_session
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent, fireEventAsync 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.request import jsonified
from couchpotato.core.helpers.variable import getExt, mergeDicts, getTitle from couchpotato.core.helpers.variable import getExt, mergeDicts, getTitle
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
@ -12,6 +12,7 @@ import os
import re import re
import shutil import shutil
import traceback import traceback
import errno
log = CPLog(__name__) log = CPLog(__name__)
@ -419,6 +420,7 @@ class Renamer(Plugin):
raise raise
def moveFile(self, old, dest): def moveFile(self, old, dest):
dest = ss(dest)
try: try:
shutil.move(old, dest) shutil.move(old, dest)
@ -427,6 +429,14 @@ class Renamer(Plugin):
except: except:
log.error('Failed setting permissions for file: %s, %s', (dest, traceback.format_exc(1))) 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: except:
log.error('Couldn\'t move file "%s" to "%s": %s', (old, dest, traceback.format_exc())) log.error('Couldn\'t move file "%s" to "%s": %s', (old, dest, traceback.format_exc()))
raise Exception raise Exception

26
couchpotato/core/plugins/scanner/main.py

@ -74,8 +74,6 @@ class Scanner(Plugin):
cp_imdb = '(\.cp\((?P<id>tt[0-9{7}]+)\))' cp_imdb = '(\.cp\((?P<id>tt[0-9{7}]+)\))'
path_identifiers = {} # bind identifier to filepath
def __init__(self): def __init__(self):
addEvent('scanner.create_file_identifier', self.createStringIdentifier) addEvent('scanner.create_file_identifier', self.createStringIdentifier)
@ -222,18 +220,19 @@ class Scanner(Plugin):
# Create identifiers for all leftover files # Create identifiers for all leftover files
path_identifiers = {}
for file_path in leftovers: for file_path in leftovers:
identifier = self.createStringIdentifier(file_path, folder) identifier = self.createStringIdentifier(file_path, folder)
if not self.path_identifiers.get(identifier): if not path_identifiers.get(identifier):
self.path_identifiers[identifier] = [] path_identifiers[identifier] = []
self.path_identifiers[identifier].append(file_path) path_identifiers[identifier].append(file_path)
# Group the files based on the identifier # Group the files based on the identifier
delete_identifiers = [] 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) log.debug('Grouping files on identifier: %s', identifier)
group = movie_files.get(identifier) group = movie_files.get(identifier)
@ -250,13 +249,13 @@ class Scanner(Plugin):
# Cleaning up used # Cleaning up used
for identifier in delete_identifiers: for identifier in delete_identifiers:
if self.path_identifiers.get(identifier): if path_identifiers.get(identifier):
del self.path_identifiers[identifier] del path_identifiers[identifier]
del delete_identifiers del delete_identifiers
# Group based on folder # Group based on folder
delete_identifiers = [] 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) log.debug('Grouping files on foldername: %s', identifier)
for ff in found_files: for ff in found_files:
@ -276,8 +275,8 @@ class Scanner(Plugin):
# Cleaning up used # Cleaning up used
for identifier in delete_identifiers: for identifier in delete_identifiers:
if self.path_identifiers.get(identifier): if path_identifiers.get(identifier):
del self.path_identifiers[identifier] del path_identifiers[identifier]
del delete_identifiers del delete_identifiers
# Determine file types # Determine file types
@ -388,14 +387,11 @@ class Scanner(Plugin):
processed_movies[identifier] = group processed_movies[identifier] = group
# Clean up
self.path_identifiers = {}
if len(processed_movies) > 0: if len(processed_movies) > 0:
log.info('Found %s movies in the folder %s', (len(processed_movies), folder)) log.info('Found %s movies in the folder %s', (len(processed_movies), folder))
else: else:
log.debug('Found no movies in the folder %s', (folder)) log.debug('Found no movies in the folder %s', (folder))
return processed_movies return processed_movies
def getMetaData(self, group): def getMetaData(self, group):

4
couchpotato/core/plugins/searcher/main.py

@ -429,8 +429,8 @@ class Searcher(Plugin):
if dates.get('dvd') > 0: if dates.get('dvd') > 0:
# 3 weeks before dvd release # 4 weeks before dvd release
if dates.get('dvd') - 1814400 < now: if dates.get('dvd') - 2419200 < now:
return True return True
# Dvd should be released # Dvd should be released

7
couchpotato/core/plugins/userscript/template.js

@ -12,8 +12,7 @@
// ==/UserScript== // ==/UserScript==
if (window.top != window.self) // Only run on top window if (window.top == window.self){ // Only run on top window
return;
var version = {{version}}, var version = {{version}},
host = '{{host}}', host = '{{host}}',
@ -135,4 +134,6 @@ var setVersion = function(){
if(document.location.href.indexOf(host) == -1) if(document.location.href.indexOf(host) == -1)
osd(); osd();
else else
setVersion(); setVersion();
}

19
couchpotato/core/providers/automation/base.py

@ -27,36 +27,31 @@ class Automation(Plugin):
return self.getIMDBids() 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) result = fireEvent('movie.search', q = '%s %s' % (name, year if year else ''), limit = 1, merge = True)
if len(result) > 0: if len(result) > 0:
return result[0].get('imdb') return result[0].get('imdb') if imdb_only else result[0]
else: else:
return None return None
def isMinimalMovie(self, movie): def isMinimalMovie(self, movie):
if not movie.get('rating'):
return False
if movie['rating'] and movie['rating'].get('imdb'): if movie['rating'] and movie['rating'].get('imdb'):
movie['votes'] = movie['rating']['imdb'][1] movie['votes'] = movie['rating']['imdb'][1]
movie['rating'] = movie['rating']['imdb'][0] movie['rating'] = movie['rating']['imdb'][0]
identifier = movie['imdb']
for minimal_type in ['year', 'rating', 'votes']: for minimal_type in ['year', 'rating', 'votes']:
type_value = movie.get(minimal_type, 0) type_value = movie.get(minimal_type, 0)
type_min = self.getMinimal(minimal_type) type_min = self.getMinimal(minimal_type)
if type_value < type_min: 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 False
return True 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): def getMinimal(self, min_type):
return Env.setting(min_type, 'automation') return Env.setting(min_type, 'automation')

30
couchpotato/core/providers/automation/bluray/main.py

@ -1,5 +1,5 @@
from couchpotato.core.helpers.rss import RSS 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.logger import CPLog
from couchpotato.core.providers.automation.base import Automation from couchpotato.core.providers.automation.base import Automation
from couchpotato.environment import Env from couchpotato.environment import Env
@ -19,41 +19,25 @@ class Bluray(Automation, RSS):
return return
movies = [] movies = []
RSSMovie = {'name': 'placeholder', 'year' : 'placeholder'}
RSSMovies = []
cache_key = 'bluray.%s' % md5(self.rss_url) cache_key = 'bluray.%s' % md5(self.rss_url)
rss_data = self.getCache(cache_key, self.rss_url) rss_data = self.getCache(cache_key, self.rss_url)
data = XMLTree.fromstring(rss_data) data = XMLTree.fromstring(rss_data)
if data: if data is not None:
rss_movies = self.getElements(data, 'channel/item') rss_movies = self.getElements(data, 'channel/item')
for movie in rss_movies: for movie in rss_movies:
RSSMovie['name'] = self.getTextElement(movie, "title").lower().split("blu-ray")[0].strip("(").rstrip() name = self.getTextElement(movie, "title").lower().split("blu-ray")[0].strip("(").rstrip()
RSSMovie['year'] = self.getTextElement(movie, "description").split("|")[1].strip("(").strip() 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 continue
if int(RSSMovie['year']) < Env.setting('year', 'automation'): #do year filtering if tryInt(year) < self.getMinimal('year'):
continue continue
for test in RSSMovies: imdb = self.search(name, year)
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'])
if imdb: if imdb:
if self.isMinimalMovie(imdb): if self.isMinimalMovie(imdb):

11
couchpotato/core/providers/automation/kinepolis/main.py

@ -19,7 +19,6 @@ class Kinepolis(Automation, RSS):
return return
movies = [] movies = []
RSSMovie = {'name': 'placeholder', 'year' : 'placeholder'}
cache_key = 'kinepolis.%s' % md5(self.rss_url) cache_key = 'kinepolis.%s' % md5(self.rss_url)
rss_data = self.getCache(cache_key, 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') rss_movies = self.getElements(data, 'channel/item')
for movie in rss_movies: for movie in rss_movies:
RSSMovie['name'] = self.getTextElement(movie, "title") name = self.getTextElement(movie, "title")
currentYear = datetime.datetime.now().strftime("%Y") year = datetime.datetime.now().strftime("%Y")
RSSMovie['year'] = currentYear
log.debug('Release found: %s.', RSSMovie) imdb = self.search(name, year)
imdb = self.getIMDBFromTitle(RSSMovie['name'], RSSMovie['year'])
if imdb: if imdb and self.isMinimalMovie(imdb):
movies.append(imdb['imdb']) movies.append(imdb['imdb'])
return movies return movies

33
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 <a href="http://movies.io">Movies.io</a> 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'],
},
],
},
],
}]

69
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

13
couchpotato/core/providers/base.py

@ -1,14 +1,13 @@
from couchpotato.core.event import addEvent from couchpotato.core.event import addEvent
from couchpotato.core.helpers.variable import tryFloat
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
from couchpotato.environment import Env from couchpotato.environment import Env
from urlparse import urlparse from urlparse import urlparse
from urllib import quote_plus
from couchpotato.core.helpers.encoding import simplifyString
import re import re
import time import time
log = CPLog(__name__) log = CPLog(__name__)
@ -86,19 +85,19 @@ class YarrProvider(Provider):
def parseSize(self, size): def parseSize(self, size):
sizeRaw = size.lower() 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: for s in self.sizeGb:
if s in sizeRaw: if s in sizeRaw:
return int(size) * 1024 return size * 1024
for s in self.sizeMb: for s in self.sizeMb:
if s in sizeRaw: if s in sizeRaw:
return int(size) return size
for s in self.sizeKb: for s in self.sizeKb:
if s in sizeRaw: if s in sizeRaw:
return int(size) / 1024 return size / 1024
return 0 return 0

9
couchpotato/core/providers/movie/imdbapi/main.py

@ -13,15 +13,14 @@ log = CPLog(__name__)
class IMDBAPI(MovieProvider): class IMDBAPI(MovieProvider):
urls = { urls = {
'search': 'http://www.imdbapi.com/?%s', 'search': 'http://www.imdbapi.com/?tomatoes=true&%s',
'info': 'http://www.imdbapi.com/?i=%s', 'info': 'http://www.imdbapi.com/?tomatoes=true&i=%s',
} }
http_time_between_calls = 0 http_time_between_calls = 0
def __init__(self): def __init__(self):
addEvent('movie.search', self.search) addEvent('movie.search', self.search)
addEvent('movie.searchimdb', self.search)
addEvent('movie.info', self.getInfo) addEvent('movie.info', self.getInfo)
def search(self, q, limit = 12): def search(self, q, limit = 12):
@ -72,7 +71,7 @@ class IMDBAPI(MovieProvider):
log.info('No proper json to decode') log.info('No proper json to decode')
return movie_data return movie_data
if movie.get('Response') == 'Parse Error': if movie.get('Response') == 'Parse Error' or movie.get('Response') == 'False':
return movie_data return movie_data
tmp_movie = movie.copy() tmp_movie = movie.copy()
@ -91,7 +90,7 @@ class IMDBAPI(MovieProvider):
}, },
'rating': { 'rating': {
'imdb': (tryFloat(movie.get('imdbRating', 0)), tryInt(movie.get('imdbVotes', '').replace(',', ''))), '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', '')), 'imdb': str(movie.get('imdbID', '')),
'runtime': self.runtimeToMinutes(movie.get('Runtime', '')), 'runtime': self.runtimeToMinutes(movie.get('Runtime', '')),

2
couchpotato/core/providers/nzb/nzbmatrix/main.py

@ -43,7 +43,7 @@ class NZBMatrix(NZBProvider, RSS):
'username': self.conf('username'), 'username': self.conf('username'),
'apikey': self.conf('api_key'), 'apikey': self.conf('api_key'),
'searchin': 'weblink', 'searchin': 'weblink',
'age': Env.setting('retention', section = 'nzb'), 'maxage': Env.setting('retention', section = 'nzb'),
'english': self.conf('english_only'), 'english': self.conf('english_only'),
}) })
url = "%s?%s" % (self.urls['search'], arguments) url = "%s?%s" % (self.urls['search'], arguments)

13
couchpotato/core/providers/torrent/sceneaccess/main.py

@ -1,8 +1,7 @@
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from couchpotato.core.event import fireEvent from couchpotato.core.event import fireEvent
from couchpotato.core.helpers.encoding import simplifyString, tryUrlencode, \ from couchpotato.core.helpers.encoding import tryUrlencode, toUnicode
toUnicode from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.helpers.variable import getTitle, tryInt
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider from couchpotato.core.providers.torrent.base import TorrentProvider
import traceback import traceback
@ -39,9 +38,10 @@ class SceneAccess(TorrentProvider):
self.getCatId(quality['identifier'])[0] 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({ arguments = tryUrlencode({
'search': q, 'search': q,
'method': 1,
}) })
url = "%s&%s" % (url, arguments) url = "%s&%s" % (url, arguments)
@ -57,7 +57,10 @@ class SceneAccess(TorrentProvider):
try: try:
resultsTable = html.find('table', attrs = {'id' : 'torrents-table'}) 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: for result in entries:
link = result.find('td', attrs = {'class' : 'ttr_name'}).find('a') link = result.find('td', attrs = {'class' : 'ttr_name'}).find('a')

6
couchpotato/core/providers/userscript/moviesio/__init__.py

@ -0,0 +1,6 @@
from .main import MoviesIO
def start():
return MoviesIO()
config = []

6
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/*']

5
couchpotato/core/providers/userscript/rottentomatoes/main.py

@ -4,7 +4,10 @@ from couchpotato.core.providers.userscript.base import UserscriptBase
class RottenTomatoes(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): def getMovie(self, url):

2
init/fedora

@ -28,7 +28,7 @@ pidfile=${CP_PIDFILE-/var/run/couchpotato/couchpotato.pid}
## ##
pidpath=`dirname ${pidfile}` 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 # create PID directory if not exist and ensure the couchpotato user can write to it
if [ ! -d $pidpath ]; then if [ ! -d $pidpath ]; then

6
libs/tornado/netutil.py

@ -258,12 +258,6 @@ def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128):
if address == "": if address == "":
address = None address = None
flags = socket.AI_PASSIVE 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, for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM,
0, flags)): 0, flags)):
af, socktype, proto, canonname, sockaddr = res af, socktype, proto, canonname, sockaddr = res

1
version.py

@ -1 +1,2 @@
VERSION = '2.0.0.pre1' VERSION = '2.0.0.pre1'
BRANCH = 'desktop'

Loading…
Cancel
Save