Merge branch 'refs/heads/develop' into desktop
Conflicts: couchpotato/core/_base/updater/main.py
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -9,6 +9,7 @@ config = [{
|
||||
{
|
||||
'tab': 'notifications',
|
||||
'name': 'growl',
|
||||
'description': 'Version 1.4+',
|
||||
'options': [
|
||||
{
|
||||
'name': 'enabled',
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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')}),
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -74,8 +74,6 @@ class Scanner(Plugin):
|
||||
|
||||
cp_imdb = '(\.cp\((?P<id>tt[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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
setVersion();
|
||||
|
||||
}
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
33
couchpotato/core/providers/automation/movies_io/__init__.py
Normal file
33
couchpotato/core/providers/automation/movies_io/__init__.py
Normal file
@@ -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
Normal file
69
couchpotato/core/providers/automation/movies_io/main.py
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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', '')),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
from .main import MoviesIO
|
||||
|
||||
def start():
|
||||
return MoviesIO()
|
||||
|
||||
config = []
|
||||
6
couchpotato/core/providers/userscript/moviesio/main.py
Normal file
6
couchpotato/core/providers/userscript/moviesio/main.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from couchpotato.core.providers.userscript.base import UserscriptBase
|
||||
|
||||
|
||||
class MoviesIO(UserscriptBase):
|
||||
|
||||
includes = ['*://movies.io/m/*']
|
||||
@@ -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):
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
VERSION = '2.0.0.pre1'
|
||||
BRANCH = 'desktop'
|
||||
|
||||
Reference in New Issue
Block a user