diff --git a/couchpotato/core/_base/updater/main.py b/couchpotato/core/_base/updater/main.py
index f1ffe40..1750de5 100644
--- a/couchpotato/core/_base/updater/main.py
+++ b/couchpotato/core/_base/updater/main.py
@@ -56,7 +56,7 @@ class Updater(Plugin):
fireEventAsync('app.crappy_restart')
else:
if self.conf('notification'):
- fireEvent('updater.available', message = 'A new update is available', data = self.updater.getVersion())
+ fireEvent('updater.available', message = 'A new update is available', data = self.updater.info())
def info(self):
return self.updater.info()
diff --git a/couchpotato/core/helpers/encoding.py b/couchpotato/core/helpers/encoding.py
index 31a85db..a9f09ed 100644
--- a/couchpotato/core/helpers/encoding.py
+++ b/couchpotato/core/helpers/encoding.py
@@ -15,7 +15,7 @@ def toSafeString(original):
def simplifyString(original):
string = stripAccents(original.lower())
string = toSafeString(' '.join(re.split('\W+', string)))
- split = re.split('\W+', string.lower())
+ split = re.split('\W+|_', string.lower())
return toUnicode(' '.join(split))
def toUnicode(original, *args):
diff --git a/couchpotato/core/helpers/request.py b/couchpotato/core/helpers/request.py
index e00880b..8bedf6c 100644
--- a/couchpotato/core/helpers/request.py
+++ b/couchpotato/core/helpers/request.py
@@ -3,7 +3,7 @@ from couchpotato.core.helpers.variable import natcmp
from flask.globals import current_app
from flask.helpers import json
from libs.werkzeug.urls import url_decode
-from urllib import unquote_plus
+from urllib import unquote
import flask
import re
@@ -26,7 +26,7 @@ def getParams():
for item in nested:
if item is nested[-1]:
- current[item] = toUnicode(unquote_plus(value)).encode('utf-8')
+ current[item] = toUnicode(unquote(value)).encode('utf-8')
else:
try:
current[item]
@@ -35,7 +35,7 @@ def getParams():
current = current[item]
else:
- temp[param] = toUnicode(unquote_plus(value)).encode('utf-8')
+ temp[param] = toUnicode(unquote(value)).encode('utf-8')
return dictToList(temp)
@@ -57,7 +57,7 @@ def dictToList(params):
def getParam(attr, default = None):
try:
- return toUnicode(unquote_plus(getattr(flask.request, 'args').get(attr, default))).encode('utf-8')
+ return toUnicode(unquote(getattr(flask.request, 'args').get(attr, default))).encode('utf-8')
except:
return default
diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py
index d91fc6c..998097d 100644
--- a/couchpotato/core/plugins/base.py
+++ b/couchpotato/core/plugins/base.py
@@ -198,7 +198,7 @@ class Plugin(object):
log.error("Something went wrong when finishing the plugin function. Could not find the 'is_running' key")
- def getCache(self, cache_key, url = None, timeout = 300, url_timeout = 10):
+ def getCache(self, cache_key, url = None, **kwargs):
cache = Env.get('cache').get(cache_key)
if cache:
if not Env.get('dev'): log.debug('Getting cache %s' % cache_key)
@@ -206,8 +206,14 @@ class Plugin(object):
if url:
try:
- data = self.urlopen(url, timeout = url_timeout)
- self.setCache(cache_key, data, timeout = timeout)
+
+ cache_timeout = 300
+ if kwargs.get('cache_timeout'):
+ cache_timeout = kwargs.get('cache_timeout')
+ del kwargs['cache_timeout']
+
+ data = self.urlopen(url, **kwargs)
+ self.setCache(cache_key, data, timeout = cache_timeout)
return data
except:
pass
diff --git a/couchpotato/core/plugins/library/main.py b/couchpotato/core/plugins/library/main.py
index 11c212a..1a4880c 100644
--- a/couchpotato/core/plugins/library/main.py
+++ b/couchpotato/core/plugins/library/main.py
@@ -68,6 +68,7 @@ class LibraryPlugin(Plugin):
do_update = False
else:
info = fireEvent('movie.info', merge = True, identifier = identifier)
+ del info['in_wanted'], info['in_library'] # Don't need those here
if not info or len(info) == 0:
log.error('Could not update, no movie info to work with: %s' % identifier)
return False
diff --git a/couchpotato/core/plugins/movie/main.py b/couchpotato/core/plugins/movie/main.py
index 63518bb..fbad471 100644
--- a/couchpotato/core/plugins/movie/main.py
+++ b/couchpotato/core/plugins/movie/main.py
@@ -51,6 +51,12 @@ class MoviePlugin(Plugin):
'movies': array, movies found,
}"""}
})
+ addApiView('movie.get', self.getView, docs = {
+ 'desc': 'Get a movie by id',
+ 'params': {
+ 'id': {'desc': 'The id of the movie'},
+ }
+ })
addApiView('movie.refresh', self.refresh, docs = {
'desc': 'Refresh a movie by id',
'params': {
@@ -88,12 +94,25 @@ class MoviePlugin(Plugin):
addEvent('movie.list', self.list)
addEvent('movie.restatus', self.restatus)
+ def getView(self):
+
+ movie_id = getParam('id')
+ movie = self.get(movie_id) if movie_id else None
+
+ return jsonified({
+ 'success': movie is not None,
+ 'movie': movie,
+ })
+
def get(self, movie_id):
db = get_session()
m = db.query(Movie).filter_by(id = movie_id).first()
- return m.to_dict(self.default_dict)
+ if m:
+ return m.to_dict(self.default_dict)
+
+ return None
def list(self, status = ['active'], limit_offset = None, starts_with = None, search = None):
@@ -169,11 +188,9 @@ class MoviePlugin(Plugin):
status = [status]
q = db.query(Movie) \
- .join(Movie.library, Library.titles) \
+ .join(Movie.library, Library.titles, Movie.status) \
.options(joinedload_all('library.titles')) \
- .filter(LibraryTitle.default == True) \
- .filter(or_(*[Movie.status.has(identifier = s) for s in status])) \
- .group_by(Movie.id)
+ .filter(or_(*[Movie.status.has(identifier = s) for s in status]))
results = q.all()
@@ -380,13 +397,15 @@ class MoviePlugin(Plugin):
total_deleted = 0
new_movie_status = None
for release in movie.releases:
- if delete_from == 'wanted' and release.status_id != done_status.get('id'):
- db.delete(release)
- total_deleted += 1
+ if delete_from == 'wanted':
+ if release.status_id != done_status.get('id'):
+ db.delete(release)
+ total_deleted += 1
new_movie_status = 'done'
- elif delete_from == 'manage' and release.status_id == done_status.get('id'):
- db.delete(release)
- total_deleted += 1
+ elif delete_from == 'manage':
+ if release.status_id == done_status.get('id'):
+ db.delete(release)
+ total_deleted += 1
new_movie_status = 'active'
db.commit()
@@ -397,6 +416,8 @@ class MoviePlugin(Plugin):
new_status = fireEvent('status.get', new_movie_status, single = True)
movie.status_id = new_status.get('id')
db.commit()
+ else:
+ fireEvent('movie.restatus', movie.id, single = True)
return True
diff --git a/couchpotato/core/plugins/movie/static/movie.css b/couchpotato/core/plugins/movie/static/movie.css
index 56521c2..a6f7e4c 100644
--- a/couchpotato/core/plugins/movie/static/movie.css
+++ b/couchpotato/core/plugins/movie/static/movie.css
@@ -288,7 +288,7 @@
text-align: left;
padding: 0 10px;
}
- .movies .options .table.files .name { width: 605px; }
+ .movies .options .table.files .name { width: 590px; }
.movies .options .table .type { width: 130px; }
.movies .options .table .is_available { width: 90px; }
.movies .options .table .age,
diff --git a/couchpotato/core/providers/movie/imdbapi/main.py b/couchpotato/core/providers/movie/imdbapi/main.py
index 933538c..e65a358 100644
--- a/couchpotato/core/providers/movie/imdbapi/main.py
+++ b/couchpotato/core/providers/movie/imdbapi/main.py
@@ -31,7 +31,7 @@ class IMDBAPI(MovieProvider):
return []
cache_key = 'imdbapi.cache.%s' % q
- cached = self.getCache(cache_key, self.urls['search'] % tryUrlencode({'t': name_year.get('name'), 'y': name_year.get('year', '')}), url_timeout = 3)
+ cached = self.getCache(cache_key, self.urls['search'] % tryUrlencode({'t': name_year.get('name'), 'y': name_year.get('year', '')}), timeout = 3)
if cached:
result = self.parseMovie(cached)
@@ -49,7 +49,7 @@ class IMDBAPI(MovieProvider):
return {}
cache_key = 'imdbapi.cache.%s' % identifier
- cached = self.getCache(cache_key, self.urls['info'] % identifier, url_timeout = 3)
+ cached = self.getCache(cache_key, self.urls['info'] % identifier, timeout = 3)
if cached:
result = self.parseMovie(cached)
diff --git a/couchpotato/core/providers/nzb/mysterbin/main.py b/couchpotato/core/providers/nzb/mysterbin/main.py
index 06936f9..0f7ffb3 100644
--- a/couchpotato/core/providers/nzb/mysterbin/main.py
+++ b/couchpotato/core/providers/nzb/mysterbin/main.py
@@ -67,7 +67,7 @@ class Mysterbin(NZBProvider):
description = ''
if result.find('a', text = 'View NFO'):
- description = toUnicode(self.getCache('mysterbin.%s' % myster_id, self.urls['nfo'] % myster_id, timeout = 25920000))
+ description = toUnicode(self.getCache('mysterbin.%s' % myster_id, self.urls['nfo'] % myster_id, cache_timeout = 25920000))
new = {
'id': myster_id,
diff --git a/couchpotato/core/providers/nzb/newznab/__init__.py b/couchpotato/core/providers/nzb/newznab/__init__.py
index b637ca8..e54db34 100644
--- a/couchpotato/core/providers/nzb/newznab/__init__.py
+++ b/couchpotato/core/providers/nzb/newznab/__init__.py
@@ -10,7 +10,7 @@ config = [{
'tab': 'searcher',
'subtab': 'providers',
'name': 'newznab',
- 'description': 'Enable multiple NewzNab providers such as NZB.su',
+ 'description': 'Enable multiple NewzNab providers such as NZB.su and nzbs.org',
'wizard': True,
'options': [
{
@@ -23,7 +23,7 @@ config = [{
},
{
'name': 'host',
- 'default': 'nzb.su,dognzb.cr,beta.nzbs.org',
+ 'default': 'nzb.su,dognzb.cr,nzbs.org',
'description': 'The hostname of your newznab provider',
},
{
diff --git a/couchpotato/core/providers/nzb/nzbclub/main.py b/couchpotato/core/providers/nzb/nzbclub/main.py
index eb33fe1..2c672f8 100644
--- a/couchpotato/core/providers/nzb/nzbclub/main.py
+++ b/couchpotato/core/providers/nzb/nzbclub/main.py
@@ -1,3 +1,4 @@
+from BeautifulSoup import BeautifulSoup
from couchpotato.core.event import fireEvent
from couchpotato.core.helpers.encoding import toUnicode, tryUrlencode
from couchpotato.core.helpers.rss import RSS
@@ -57,7 +58,10 @@ class NZBClub(NZBProvider, RSS):
size = enclosure['length']
date = self.getTextElement(nzb, "pubDate")
- description = toUnicode(self.getCache('nzbclub.%s' % nzbclub_id, self.getTextElement(nzb, "link"), timeout = 25920000))
+ full_description = self.getCache('nzbclub.%s' % nzbclub_id, self.getTextElement(nzb, "link"), cache_timeout = 25920000)
+ html = BeautifulSoup(full_description)
+ nfo_pre = html.find('pre', attrs = {'class':'nfo'})
+ description = toUnicode(nfo_pre.text) if nfo_pre else ''
new = {
'id': nzbclub_id,
@@ -73,7 +77,7 @@ class NZBClub(NZBProvider, RSS):
}
new['score'] = fireEvent('score.calculate', new, movie, single = True)
- if 'ARCHIVE inside ARCHIVE' in description:
+ if 'ARCHIVE inside ARCHIVE' in full_description:
log.info('Wrong: Seems to be passworded files: %s' % new['name'])
continue
diff --git a/couchpotato/core/providers/nzb/nzbindex/main.py b/couchpotato/core/providers/nzb/nzbindex/main.py
index 22e202b..0b708b2 100644
--- a/couchpotato/core/providers/nzb/nzbindex/main.py
+++ b/couchpotato/core/providers/nzb/nzbindex/main.py
@@ -1,3 +1,4 @@
+from BeautifulSoup import BeautifulSoup
from couchpotato.core.event import fireEvent
from couchpotato.core.helpers.encoding import toUnicode, tryUrlencode
from couchpotato.core.helpers.rss import RSS
@@ -62,9 +63,11 @@ class NzbIndex(NZBProvider, RSS):
try:
description = self.getTextElement(nzb, "description")
- if ' nfo' in description.lower():
- nfo_url = re.search('href="(?P.+)"', description).group('nfo')
- description = toUnicode(self.getCache('nzbindex.%s' % nzbindex_id, nfo_url, timeout = 25920000))
+ if '/nfo/' in description.lower():
+ nfo_url = re.search('href=\"(?P.+)\" ', description).group('nfo')
+ full_description = self.getCache('nzbindex.%s' % nzbindex_id, url = nfo_url, cache_timeout = 25920000)
+ html = BeautifulSoup(full_description)
+ description = toUnicode(html.find('pre', attrs = {'id':'nfo0'}).text)
except:
pass
diff --git a/couchpotato/core/providers/nzb/nzbmatrix/main.py b/couchpotato/core/providers/nzb/nzbmatrix/main.py
index 8e82133..e2b426b 100644
--- a/couchpotato/core/providers/nzb/nzbmatrix/main.py
+++ b/couchpotato/core/providers/nzb/nzbmatrix/main.py
@@ -51,7 +51,7 @@ class NZBMatrix(NZBProvider, RSS):
cache_key = 'nzbmatrix.%s.%s' % (movie['library'].get('identifier'), cat_ids)
single_cat = True
- data = self.getCache(cache_key, url)
+ data = self.getCache(cache_key, url, cache_timeout = 1800, headers = {'User-Agent': 'CouchPotato'})
if data:
try:
try:
diff --git a/couchpotato/core/providers/nzb/nzbs/__init__.py b/couchpotato/core/providers/nzb/nzbs/__init__.py
deleted file mode 100644
index 2ca8917..0000000
--- a/couchpotato/core/providers/nzb/nzbs/__init__.py
+++ /dev/null
@@ -1,33 +0,0 @@
-from .main import Nzbs
-
-def start():
- return Nzbs()
-
-config = [{
- 'name': 'nzbs',
- 'groups': [
- {
- 'tab': 'searcher',
- 'subtab': 'providers',
- 'name': 'nzbs',
- 'description': 'Id and Key can be found on your nzbs.org RSS page.',
- 'wizard': True,
- 'options': [
- {
- 'name': 'enabled',
- 'type': 'enabler',
- },
- {
- 'name': 'id',
- 'label': 'Id',
- 'description': 'The number after "&i="',
- },
- {
- 'name': 'api_key',
- 'label': 'Api Key',
- 'description': 'The string after "&h="'
- },
- ],
- },
- ],
-}]
diff --git a/couchpotato/core/providers/nzb/nzbs/main.py b/couchpotato/core/providers/nzb/nzbs/main.py
deleted file mode 100644
index 4281f81..0000000
--- a/couchpotato/core/providers/nzb/nzbs/main.py
+++ /dev/null
@@ -1,96 +0,0 @@
-from couchpotato.core.event import fireEvent
-from couchpotato.core.helpers.encoding import simplifyString, tryUrlencode
-from couchpotato.core.helpers.rss import RSS
-from couchpotato.core.logger import CPLog
-from couchpotato.core.providers.nzb.base import NZBProvider
-from dateutil.parser import parse
-import time
-import xml.etree.ElementTree as XMLTree
-
-log = CPLog(__name__)
-
-
-class Nzbs(NZBProvider, RSS):
-
- urls = {
- 'download': 'https://nzbs.org/index.php?action=getnzb&nzbid=%s%s',
- 'nfo': 'https://nzbs.org/index.php?action=view&nzbid=%s&nfo=1',
- 'detail': 'https://nzbs.org/index.php?action=view&nzbid=%s',
- 'api': 'https://nzbs.org/rss.php',
- }
-
- cat_ids = [
- ([4], ['720p', '1080p']),
- ([2], ['cam', 'ts', 'dvdrip', 'tc', 'brrip', 'r5', 'scr']),
- ([9], ['dvdr']),
- ]
- cat_backup_id = 't2'
-
- http_time_between_calls = 3 # Seconds
-
- def search(self, movie, quality):
-
- results = []
- if self.isDisabled() or not self.isAvailable(self.urls['api'] + '?test' + self.getApiExt()):
- return results
-
- cat_id = self.getCatId(quality.get('identifier'))
- arguments = tryUrlencode({
- 'action':'search',
- 'q': simplifyString(movie['library']['titles'][0]['title']),
- 'catid': cat_id[0],
- 'i': self.conf('id'),
- 'h': self.conf('api_key'),
- })
- url = "%s?%s" % (self.urls['api'], arguments)
-
- cache_key = 'nzbs.%s.%s' % (movie['library'].get('identifier'), str(cat_id))
-
- data = self.getCache(cache_key, url)
- if data:
- try:
- try:
- data = XMLTree.fromstring(data)
- nzbs = self.getElements(data, 'channel/item')
- except Exception, e:
- log.debug('%s, %s' % (self.getName(), e))
- return results
-
- for nzb in nzbs:
-
- id = int(self.getTextElement(nzb, "link").partition('nzbid=')[2])
- new = {
- 'id': id,
- 'type': 'nzb',
- 'provider': self.getName(),
- 'name': self.getTextElement(nzb, "title"),
- 'age': self.calculateAge(int(time.mktime(parse(self.getTextElement(nzb, "pubDate")).timetuple()))),
- 'size': self.parseSize(self.getTextElement(nzb, "description").split('
')[1].split('">')[1]),
- 'url': self.urls['download'] % (id, self.getApiExt()),
- 'download': self.download,
- 'detail_url': self.urls['detail'] % id,
- 'description': self.getTextElement(nzb, "description"),
- 'check_nzb': True,
- }
- new['score'] = fireEvent('score.calculate', new, movie, single = True)
-
- is_correct_movie = fireEvent('searcher.correct_movie',
- nzb = new, movie = movie, quality = quality,
- imdb_results = False, single_category = False, single = True)
-
- if is_correct_movie:
- results.append(new)
- self.found(new)
-
- return results
- except SyntaxError:
- log.error('Failed to parse XML response from NZBMatrix.com')
-
- return results
-
-
- def isEnabled(self):
- return NZBProvider.isEnabled(self) and self.conf('enabled') and self.conf('id') and self.conf('api_key')
-
- def getApiExt(self):
- return '&i=%s&h=%s' % (self.conf('id'), self.conf('api_key'))
diff --git a/couchpotato/static/scripts/page/wanted.js b/couchpotato/static/scripts/page/wanted.js
index ef7ddc8..b5a82cf 100644
--- a/couchpotato/static/scripts/page/wanted.js
+++ b/couchpotato/static/scripts/page/wanted.js
@@ -243,7 +243,7 @@ window.addEvent('domready', function(){
create: function(){
var self = this;
- self.el = new Element('a.files', {
+ self.el = new Element('a.directory', {
'title': 'Available files',
'events': {
'click': self.showFiles.bind(self)