diff --git a/couchpotato/core/downloaders/putio/__init__.py b/couchpotato/core/downloaders/putio/__init__.py
index 60ccad5..48794d9 100644
--- a/couchpotato/core/downloaders/putio/__init__.py
+++ b/couchpotato/core/downloaders/putio/__init__.py
@@ -30,7 +30,7 @@ config = [{
},
{
'name': 'folder',
- 'description': ('The folder on putio where you want the upload to go','Must be a folder in the root directory'),
+ 'description': ('The folder on putio where you want the upload to go','Will find the first first folder that matches this name'),
'default': 0,
},
{
diff --git a/couchpotato/core/downloaders/putio/main.py b/couchpotato/core/downloaders/putio/main.py
index ce58ff7..c568582 100644
--- a/couchpotato/core/downloaders/putio/main.py
+++ b/couchpotato/core/downloaders/putio/main.py
@@ -28,16 +28,25 @@ class PutIO(DownloaderBase):
return super(PutIO, self).__init__()
+ # This is a recusive function to check for the folders
+ def recursionFolder(self, client, folder = 0, tfolder = ''):
+ files = client.File.list(folder)
+ for f in files:
+ if f.content_type == 'application/x-directory':
+ if f.name == tfolder:
+ return f.id
+ else:
+ result = self.recursionFolder(client, f.id, tfolder)
+ if result != 0:
+ return result
+ return 0
+
+ # This will check the root for the folder, and kick of recusively checking sub folder
def convertFolder(self, client, folder):
if folder == 0:
return 0
else:
- files = client.File.list()
- for f in files:
- if f.name == folder and f.content_type == "application/x-directory":
- return f.id
- #If we get through the whole list and don't get a match we will use the root
- return 0
+ return self.recursionFolder(client, 0, folder)
def download(self, data = None, media = None, filedata = None):
if not media: media = {}
diff --git a/couchpotato/core/downloaders/synology.py b/couchpotato/core/downloaders/synology.py
index b5327cc..8368eb1 100644
--- a/couchpotato/core/downloaders/synology.py
+++ b/couchpotato/core/downloaders/synology.py
@@ -137,7 +137,7 @@ class SynologyRPC(object):
def _req(self, url, args, files = None):
response = {'success': False}
try:
- req = requests.post(url, data = args, files = files)
+ req = requests.post(url, data = args, files = files, verify = False)
req.raise_for_status()
response = json.loads(req.text)
if response['success']:
diff --git a/couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py b/couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py
index ea5f90f..3d002fb 100644
--- a/couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py
+++ b/couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py
@@ -18,20 +18,13 @@ class Base(NZBProvider, RSS):
http_time_between_calls = 1 # Seconds
cat_ids = [
- ([15], ['dvdrip']),
+ ([15], ['dvdrip', 'scr', 'r5', 'tc', 'ts', 'cam']),
([15, 16], ['brrip']),
([16], ['720p', '1080p', 'bd50']),
([17], ['dvdr']),
]
cat_backup_id = 'movie'
- def search(self, movie, quality):
-
- if quality['identifier'] in fireEvent('quality.pre_releases', single = True):
- return []
-
- return super(Base, self).search(movie, quality)
-
def _searchOnTitle(self, title, movie, quality, results):
q = '%s %s' % (title, movie['info']['year'])
diff --git a/couchpotato/core/media/_base/providers/torrent/hdaccess.py b/couchpotato/core/media/_base/providers/torrent/hdaccess.py
new file mode 100644
index 0000000..1a6b0ed
--- /dev/null
+++ b/couchpotato/core/media/_base/providers/torrent/hdaccess.py
@@ -0,0 +1,130 @@
+import re
+import traceback
+
+from couchpotato.core.helpers.variable import tryInt, getIdentifier
+from couchpotato.core.logger import CPLog
+from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
+
+
+log = CPLog(__name__)
+
+
+class Base(TorrentProvider):
+
+ urls = {
+ 'test': 'https://hdaccess.net/',
+ 'detail': 'https://hdaccess.net/details.php?id=%s',
+ 'search': 'https://hdaccess.net/searchapi.php?apikey=%s&username=%s&imdbid=%s&internal=%s',
+ 'download': 'https://hdaccess.net/grab.php?torrent=%s&apikey=%s',
+ }
+
+ http_time_between_calls = 1 # Seconds
+
+ def _search(self, movie, quality, results):
+ data = self.getJsonData(self.urls['search'] % (self.conf('apikey'), self.conf('username'), getIdentifier(movie), self.conf('internal_only')))
+
+ if data:
+ try:
+ #for result in data[]:
+ for key, result in data.iteritems():
+ if tryInt(result['total_results']) == 0:
+ return
+ torrentscore = self.conf('extra_score')
+ releasegroup = result['releasegroup']
+ resolution = result['resolution']
+ encoding = result['encoding']
+ freeleech = tryInt(result['freeleech'])
+ seeders = tryInt(result['seeders'])
+ torrent_desc = '/ %s / %s / %s / %s seeders' % (releasegroup, resolution, encoding, seeders)
+
+ if freeleech > 0 and self.conf('prefer_internal'):
+ torrent_desc += '/ Internal'
+ torrentscore += 200
+
+ if seeders == 0:
+ torrentscore = 0
+
+ name = result['release_name']
+ year = tryInt(result['year'])
+
+ results.append({
+ 'id': tryInt(result['torrentid']),
+ 'name': re.sub('[^A-Za-z0-9\-_ \(\).]+', '', '%s (%s) %s' % (name, year, torrent_desc)),
+ 'url': self.urls['download'] % (result['torrentid'], self.conf('apikey')),
+ 'detail_url': self.urls['detail'] % result['torrentid'],
+ 'size': tryInt(result['size']),
+ 'seeders': tryInt(result['seeders']),
+ 'leechers': tryInt(result['leechers']),
+ 'age': tryInt(result['age']),
+ 'score': torrentscore
+ })
+ except:
+ log.error('Failed getting results from %s: %s', (self.getName(), traceback.format_exc()))
+config = [{
+ 'name': 'hdaccess',
+ 'groups': [
+ {
+ 'tab': 'searcher',
+ 'list': 'torrent_providers',
+ 'name': 'HDAccess',
+ 'wizard': True,
+ 'description': 'HDAccess',
+ 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADuUlEQVQ4yz3T209bdQAH8O/vnNNzWno5FIpAKZdSLi23gWMDtumWuSXOyzJj9M1kyIOPS1xiYuKe9GUPezZZnGIiMTqTxS1bdIuYkG2MWKBAKYVszOgKFkrbA+259HfO+fli/PwPHzI+Pg5CCEAI2VcUlEsl1tHdU7P5bGOkWChEaaUCwvHpmkD93POn6bwgCMQGAMYYYwyCruuQnE7SPzjIstvb8l+bm5fXkokJSmlQEkUQAIpSRH5vd0tyum7I/sA1Z5VH2ctmiGWZjHw4McE1NAZtQ9fD25kXt1VN7es7dNjuGRjiJFeVpWo6slsZPhF/Ys/PPeIs2056ff7zIOS5rpU5/viJEwwEnu3Mi18dojjw0aWP6amz57h9RSE/35zinq2nuGjvIQwOj7K2SKeZWkk0auXSSZ+/ZopSy+CbW1pQKpWu6Jr2/qVPPqWRjm6HWi6Tm999g3RyGbndLCqGgVBrO3F7fHykK0YX47NNtGLYlBq/c+H2iD+3k704dHQUDcFmQVXLyP6zhfTqCl45fQYjx17FemoJunoAk1bQFGoVhkdPwNC0ix2dMT+3llodM02rKdo7gN3dHAEhuH/vNgDg3Pl3cPaNt2GZJpYX5lBbFwClBukfGobL5WrayW6NccVCISY4HIQxYts2Q3J5CXOPHuLlo6NoCoXQ2hbG0JFRpJYWcVDIQ5ZlyL5qW5b9hNlWjKsYBgzDgKppMCoGHty7A0orOHbyNNweL+obGnDm9TdhWSYS8Vn4a2shOZ0QJRGSKIHjeGGtWNhjqqpyG+k04k8eozPai9ZwByavf4kfpyZxZGwMfYOHsbwQx34hB5dL4syKweRq/xpXHwzNapqWSSYWMDszzYqFPEaOn4KiKJiZfoCZ6d8Am+GtC++iXCpjaf4P9vefT8HzfKarp3eWRKMxCILwuWXSz977YIK2RTodDoGH1+OG1+tDlbsKkuiAJEngeWBjNUUnv7rucIiOLyzTvMKJTgnVtbVXLctK3L31g+NAUajL5bEptaDpOnTdgGkzVHl9drms0ju3fnJIkphoaQtfbQiFwAcCAY5wnCE5Xff3i8XX4o9nGksH+8zl9hAGZlWMCivkc9z0L3fZ999+LTCGZKi55YJTFHfye3sc6e/vB88LpK6+iWlqSS4WcpcNXZtwOp3B6mo/REmCSSkEgd+qq3vpRkt75Fp9Y1BZWZwnhq4zEovF/u/MATAti4U7umvyu9kR27aikihC9vvTnV2xufVUMu/2uIksy/9tZvgX49fLmAMx3bsAAAAASUVORK5CYII=',
+ 'options': [
+ {
+ 'name': 'enabled',
+ 'type': 'enabler',
+ 'default': False,
+ },
+ {
+ 'name': 'username',
+ 'default': '',
+ 'description': 'Enter your site username.',
+ },
+ {
+ 'name': 'apikey',
+ 'default': '',
+ 'label': 'API Key',
+ 'description': 'Enter your site api key. This can be find on Profile Security',
+ },
+ {
+ 'name': 'seed_ratio',
+ 'label': 'Seed ratio',
+ 'type': 'float',
+ 'default': 0,
+ 'description': 'Will not be (re)moved until this seed ratio is met. HDAccess minimum is 1:1.',
+ },
+ {
+ 'name': 'seed_time',
+ 'label': 'Seed time',
+ 'type': 'int',
+ 'default': 0,
+ 'description': 'Will not be (re)moved until this seed time (in hours) is met. HDAccess minimum is 48 hours.',
+ },
+ {
+ 'name': 'prefer_internal',
+ 'advanced': True,
+ 'type': 'bool',
+ 'default': 1,
+ 'description': 'Favors internal releases over non-internal releases.',
+ },
+ {
+ 'name': 'internal_only',
+ 'advanced': True,
+ 'label': 'Internal Only',
+ 'type': 'bool',
+ 'default': False,
+ 'description': 'Only download releases marked as HDAccess internal',
+ },
+ {
+ 'name': 'extra_score',
+ 'advanced': True,
+ 'label': 'Extra Score',
+ 'type': 'int',
+ 'default': 0,
+ 'description': 'Starting score for each release found via this provider.',
+ }
+ ],
+ },
+ ],
+}]
diff --git a/couchpotato/core/media/_base/providers/torrent/iptorrents.py b/couchpotato/core/media/_base/providers/torrent/iptorrents.py
index 0915ca3..61ced9c 100644
--- a/couchpotato/core/media/_base/providers/torrent/iptorrents.py
+++ b/couchpotato/core/media/_base/providers/torrent/iptorrents.py
@@ -14,11 +14,11 @@ log = CPLog(__name__)
class Base(TorrentProvider):
urls = {
- 'test': 'https://www.iptorrents.com/',
- 'base_url': 'https://www.iptorrents.com',
- 'login': 'https://www.iptorrents.com/torrents/',
- 'login_check': 'https://www.iptorrents.com/inbox.php',
- 'search': 'https://www.iptorrents.com/torrents/?%s%%s&q=%s&qf=ti&p=%%d',
+ 'test': 'https://iptorrents.eu/',
+ 'base_url': 'https://iptorrents.eu',
+ 'login': 'https://iptorrents.eu/torrents/',
+ 'login_check': 'https://iptorrents.eu/inbox.php',
+ 'search': 'https://iptorrents.eu/torrents/?%s%%s&q=%s&qf=ti&p=%%d',
}
http_time_between_calls = 1 # Seconds
@@ -120,7 +120,7 @@ config = [{
'tab': 'searcher',
'list': 'torrent_providers',
'name': 'IPTorrents',
- 'description': 'IPTorrents',
+ 'description': 'IPTorrents',
'wizard': True,
'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABRklEQVR42qWQO0vDUBiG8zeKY3EqQUtNO7g0J6ZJ1+ifKIIFQXAqDYKCyaaYxM3udrZLHdRFhXrZ6liCW6mubfk874EESgqaeOCF7/Y8hEh41aq6yZi2nyZgBGya9XKtZs4No05pAkZV2YbEmyMMsoSxLQeC46wCTdPPY4HruPQyGIhF97qLWsS78Miydn4XdK46NJ9OsQAYBzMIMf8MQ9wtCnTdWCaIDx/u7uljOIQEe0hiIWPamSTLay3+RxOCSPI9+RJAo7Er9r2bnqjBFAqyK+VyK4f5/Cr5ni8OFKVCz49PFI5GdNvvU7ttE1M1zMU+8AMqFksEhrMnQsBDzqmDAwzx2ehRLwT7yyCI+vSC99c3mozH1NxrJgWWtR1BOECfEJSVCm6WCzJGCA7+IWhBsM4zywDPwEp4vCjx2DzBH2ODAfsDb33Ps6dQwJgAAAAASUVORK5CYII=',
'options': [
diff --git a/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py b/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py
index fb58814..d6e3ee7 100644
--- a/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py
+++ b/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py
@@ -30,7 +30,7 @@ class Base(TorrentMagnetProvider):
cat_backup_id = None
proxy_list = [
- 'https://kickass.so',
+ 'https://kickass.to',
'http://kickass.pw',
'http://kickassto.come.in',
'http://katproxy.ws',
diff --git a/couchpotato/core/media/_base/providers/torrent/torrentbytes.py b/couchpotato/core/media/_base/providers/torrent/torrentbytes.py
index fadd2ea..32221d8 100644
--- a/couchpotato/core/media/_base/providers/torrent/torrentbytes.py
+++ b/couchpotato/core/media/_base/providers/torrent/torrentbytes.py
@@ -56,7 +56,7 @@ class Base(TorrentProvider):
full_id = link['href'].replace('details.php?id=', '')
torrent_id = full_id[:6]
- name = toUnicode(link.contents[0].encode('ISO-8859-1')).strip()
+ name = toUnicode(link.get('title', link.contents[0]).encode('ISO-8859-1')).strip()
results.append({
'id': torrent_id,
diff --git a/couchpotato/core/media/_base/providers/torrent/torrentday.py b/couchpotato/core/media/_base/providers/torrent/torrentday.py
index a3e9b78..7301433 100644
--- a/couchpotato/core/media/_base/providers/torrent/torrentday.py
+++ b/couchpotato/core/media/_base/providers/torrent/torrentday.py
@@ -1,3 +1,4 @@
+import re
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
@@ -8,12 +9,12 @@ log = CPLog(__name__)
class Base(TorrentProvider):
urls = {
- 'test': 'http://www.td.af/',
- 'login': 'http://www.td.af/torrents/',
- 'login_check': 'http://www.torrentday.com/userdetails.php',
- 'detail': 'http://www.td.af/details.php?id=%s',
- 'search': 'http://www.td.af/V3/API/API.php',
- 'download': 'http://www.td.af/download.php/%s/%s',
+ 'test': 'https://torrentday.eu/',
+ 'login': 'https://torrentday.eu/torrents/',
+ 'login_check': 'https://torrentday.eu/userdetails.php',
+ 'detail': 'https://torrentday.eu/details.php?id=%s',
+ 'search': 'https://torrentday.eu/V3/API/API.php',
+ 'download': 'https://torrentday.eu/download.php/%s/%s',
}
http_time_between_calls = 1 # Seconds
@@ -55,6 +56,10 @@ class Base(TorrentProvider):
}
def loginSuccess(self, output):
+ often = re.search('You tried too often, please wait .*', output)
+ if often:
+ raise Exception(often.group(0)[:-6].strip())
+
return 'Password not correct' not in output
def loginCheckSuccess(self, output):
@@ -68,7 +73,7 @@ config = [{
'tab': 'searcher',
'list': 'torrent_providers',
'name': 'TorrentDay',
- 'description': 'TorrentDay',
+ 'description': 'TorrentDay',
'wizard': True,
'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAC5ElEQVQ4y12TXUgUURTH//fO7Di7foeQJH6gEEEIZZllVohfSG/6UA+RSFAQQj74VA8+Bj30lmAlRVSEvZRfhNhaka5ZUG1paKaW39tq5O6Ou+PM3M4o6m6X+XPPzD3zm/+dcy574r515WfIW8CZBM4YAA5Gc/aQC3yd7oXYEONcsISE5dTDh91HS0t7FEWhBUAeN9ynV/d9qJAgE4AECURAcVsGlCCnly26LMA0IQwTa52dje3d3e3hcPi8qqrrMjcVYI3EHCQZlkFOHBwR2QHh2ASAAIJxWGAQEDxjePhs3527XjJwnb37OHBq0T+Tyyjh+9KnEzNJ7nouc1Q/3A3HGsOvnJy+PSUlj81w2Lny9WuJ6+3AmTjD4HOcrdR2dWXLRQePvyaSLfQOPMPC8mC9iHCsOxSyzJCelzdSXlNzD5ujpb25Wbfc/XXJemTXF4+nnCNq+AMLe50uFfEJTiw4GXSFtiHL0SnIq66+p0kSArqO+eH3RdsAv9+f5vW7L7GICq6rmM8XBCAXlBw90rOyxibn5yzfkg/L09M52/jxqdESaIrBXHYZZbB1GX8cEpySxKIB8S5XcOnvqpli1zuwmrTtoLjw5LOK/eeuWsE4JH5IRPaPZKiKigmPp+5pa+u1aEjIMhEgrRkmi9mgxGUhM7LNJSzOzsE3+cOeExovXOjdytE0LV4zqNZUtV0uZzAGoGkhDH/2YHZiErmv4uyWQnZZWc+hoqL3WzlTExN5hhA8IEwkZWZOxwB++30YG/9GkYCPvqAaHAW5uWPROW86OmqCprUR7z1yZDAGQNuCvkoB/baIKUBWMTYymv+gra3eJNvjXu+B562tFyXqTJ6YuHK8rKwvBmC3vR7cOCPQLWFz8LnfXWUrJo9U19BwMyUlJRjTSMJ2ENxUiGxq9KXQfwqYlnWstvbR5aamG9g0uzM8Q4OFt++3NNixQ2NgYmeN03FOTUv7XVpV9aKisvLl1vN/WVhNc/Fi1NEAAAAASUVORK5CYII=',
'options': [
diff --git a/couchpotato/core/media/_base/providers/torrent/torrentz.py b/couchpotato/core/media/_base/providers/torrent/torrentz.py
index 8a5455c..a5c1ed0 100644
--- a/couchpotato/core/media/_base/providers/torrent/torrentz.py
+++ b/couchpotato/core/media/_base/providers/torrent/torrentz.py
@@ -22,12 +22,12 @@ class Base(TorrentMagnetProvider, RSS):
http_time_between_calls = 0
- def _search(self, media, quality, results):
+ def _searchOnTitle(self, title, media, quality, results):
search_url = self.urls['verified_search'] if self.conf('verified_only') else self.urls['search']
# Create search parameters
- search_params = self.buildUrl(media)
+ search_params = self.buildUrl(title, media, quality)
smin = quality.get('size_min')
smax = quality.get('size_max')
diff --git a/couchpotato/core/media/_base/providers/torrent/yify.py b/couchpotato/core/media/_base/providers/torrent/yify.py
index 725aabb..492eeb6 100644
--- a/couchpotato/core/media/_base/providers/torrent/yify.py
+++ b/couchpotato/core/media/_base/providers/torrent/yify.py
@@ -2,27 +2,25 @@ import traceback
from couchpotato.core.helpers.variable import tryInt, getIdentifier
from couchpotato.core.logger import CPLog
-from couchpotato.core.media._base.providers.torrent.base import TorrentMagnetProvider
+from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
log = CPLog(__name__)
-class Base(TorrentMagnetProvider):
+class Base(TorrentProvider):
urls = {
- 'test': '%s/api',
- 'search': '%s/api/list.json?keywords=%s',
- 'detail': '%s/api/movie.json?id=%s'
+ 'test': '%s/api/v2',
+ 'search': '%s/api/v2/list_movies.json?limit=50&query_term=%s'
}
http_time_between_calls = 1 # seconds
proxy_list = [
'https://yts.re',
- 'http://ytsproxy.come.in',
- 'http://yts.im',
- 'http://yify-torrents.im',
+ 'https://yts.wf',
+ 'https://yts.im',
]
def search(self, movie, quality):
@@ -41,25 +39,28 @@ class Base(TorrentMagnetProvider):
search_url = self.urls['search'] % (domain, getIdentifier(movie))
data = self.getJsonData(search_url)
+ data = data.get('data')
- if data and data.get('MovieList'):
+ if data and data.get('movies'):
try:
- for result in data.get('MovieList'):
-
- if result['Quality'] and result['Quality'] not in result['MovieTitle']:
- title = result['MovieTitle'] + ' BrRip ' + result['Quality']
- else:
- title = result['MovieTitle'] + ' BrRip'
-
- results.append({
- 'id': result['MovieID'],
- 'name': title,
- 'url': result['TorrentMagnetUrl'],
- 'detail_url': self.urls['detail'] % (domain, result['MovieID']),
- 'size': self.parseSize(result['Size']),
- 'seeders': tryInt(result['TorrentSeeds']),
- 'leechers': tryInt(result['TorrentPeers']),
- })
+ for result in data.get('movies'):
+
+ for release in result.get('torrents', []):
+
+ if release['quality'] and release['quality'] not in result['title_long']:
+ title = result['title_long'] + ' BRRip ' + release['quality']
+ else:
+ title = result['title_long'] + ' BRRip'
+
+ results.append({
+ 'id': release['hash'],
+ 'name': title,
+ 'url': release['url'],
+ 'detail_url': result['url'],
+ 'size': self.parseSize(release['size']),
+ 'seeders': tryInt(release['seeds']),
+ 'leechers': tryInt(release['peers']),
+ })
except:
log.error('Failed getting results from %s: %s', (self.getName(), traceback.format_exc()))
diff --git a/couchpotato/core/media/movie/providers/automation/crowdai.py b/couchpotato/core/media/movie/providers/automation/crowdai.py
new file mode 100644
index 0000000..56f1fb2
--- /dev/null
+++ b/couchpotato/core/media/movie/providers/automation/crowdai.py
@@ -0,0 +1,89 @@
+import re
+
+from couchpotato.core.helpers.rss import RSS
+from couchpotato.core.helpers.variable import tryInt, splitString
+from couchpotato.core.logger import CPLog
+from couchpotato.core.media.movie.providers.automation.base import Automation
+
+
+log = CPLog(__name__)
+
+autoload = 'CrowdAI'
+
+
+class CrowdAI(Automation, RSS):
+
+ interval = 1800
+
+ def getIMDBids(self):
+
+ movies = []
+
+ urls = dict(zip(splitString(self.conf('automation_urls')), [tryInt(x) for x in splitString(self.conf('automation_urls_use'))]))
+
+ for url in urls:
+
+ if not urls[url]:
+ continue
+
+ rss_movies = self.getRSSData(url)
+
+ for movie in rss_movies:
+
+ description = self.getTextElement(movie, 'description')
+ grabs = 0
+
+ for item in movie:
+ if item.attrib.get('name') == 'grabs':
+ grabs = item.attrib.get('value')
+ break
+
+ if int(grabs) > tryInt(self.conf('number_grabs')):
+ title = re.match(r'.*Title: .a href.*/">(.*) \(\d{4}\).*', description).group(1)
+ log.info2('%s grabs for movie: %s, enqueue...', (grabs, title))
+ year = re.match(r'.*Year: (\d{4}).*', description).group(1)
+ imdb = self.search(title, year)
+
+ if imdb and self.isMinimalMovie(imdb):
+ movies.append(imdb['imdb'])
+
+ return movies
+
+
+config = [{
+ 'name': 'crowdai',
+ 'groups': [
+ {
+ 'tab': 'automation',
+ 'list': 'automation_providers',
+ 'name': 'crowdai_automation',
+ 'label': 'CrowdAI',
+ 'description': 'Imports from any newznab powered NZB providers RSS feed depending on the number of grabs per movie. Go to your newznab site and find the RSS section. Then copy the copy paste the link under "Movies > x264 feed" here.',
+ 'options': [
+ {
+ 'name': 'automation_enabled',
+ 'default': False,
+ 'type': 'enabler',
+ },
+ {
+ 'name': 'automation_urls_use',
+ 'label': 'Use',
+ 'default': '1',
+ },
+ {
+ 'name': 'automation_urls',
+ 'label': 'url',
+ 'type': 'combined',
+ 'combine': ['automation_urls_use', 'automation_urls'],
+ 'default': 'http://YOUR_PROVIDER/rss?t=THE_MOVIE_CATEGORY&i=YOUR_USER_ID&r=YOUR_API_KEY&res=2&rls=2&num=100',
+ },
+ {
+ 'name': 'number_grabs',
+ 'default': '500',
+ 'label': 'Grab threshold',
+ 'description': 'Number of grabs required',
+ },
+ ],
+ },
+ ],
+}]
diff --git a/couchpotato/core/media/movie/providers/automation/letterboxd.py b/couchpotato/core/media/movie/providers/automation/letterboxd.py
index e9fc874..d43821c 100644
--- a/couchpotato/core/media/movie/providers/automation/letterboxd.py
+++ b/couchpotato/core/media/movie/providers/automation/letterboxd.py
@@ -48,11 +48,12 @@ class Letterboxd(Automation):
soup = BeautifulSoup(self.getHTMLData(self.url % username))
- for movie in soup.find_all('a', attrs = {'class': 'frame'}):
- match = removeEmpty(self.pattern.split(movie['title']))
+ for movie in soup.find_all('li', attrs = {'class': 'poster-container'}):
+ img = movie.find('img', movie)
+ title = img.get('alt')
+
movies.append({
- 'title': match[0],
- 'year': match[1]
+ 'title': title
})
return movies
diff --git a/couchpotato/core/media/movie/providers/automation/rottentomatoes.py b/couchpotato/core/media/movie/providers/automation/rottentomatoes.py
index a01f76d..65d54f1 100644
--- a/couchpotato/core/media/movie/providers/automation/rottentomatoes.py
+++ b/couchpotato/core/media/movie/providers/automation/rottentomatoes.py
@@ -39,15 +39,14 @@ class Rottentomatoes(Automation, RSS):
if result:
- log.info2('Something smells...')
rating = tryInt(self.getTextElement(movie, rating_tag))
name = result.group(0)
+ print rating, tryInt(self.conf('tomatometer_percent'))
if rating < tryInt(self.conf('tomatometer_percent')):
log.info2('%s seems to be rotten...', name)
else:
-
- log.info2('Found %s fresh enough movies, enqueuing: %s', (rating, name))
+ log.info2('Found %s with fresh rating %s', (name, rating))
year = datetime.datetime.now().strftime("%Y")
imdb = self.search(name, year)
diff --git a/couchpotato/core/media/movie/providers/torrent/bitsoup.py b/couchpotato/core/media/movie/providers/torrent/bitsoup.py
index e9d69fe..b0c8ede 100644
--- a/couchpotato/core/media/movie/providers/torrent/bitsoup.py
+++ b/couchpotato/core/media/movie/providers/torrent/bitsoup.py
@@ -11,7 +11,7 @@ autoload = 'Bitsoup'
class Bitsoup(MovieProvider, Base):
cat_ids = [
([17], ['3d']),
- ([41], ['720p', '1080p']),
+ ([80], ['720p', '1080p']),
([20], ['dvdr']),
([19], ['brrip', 'dvdrip']),
]
diff --git a/couchpotato/core/media/movie/providers/torrent/hdaccess.py b/couchpotato/core/media/movie/providers/torrent/hdaccess.py
new file mode 100644
index 0000000..fae2cf5
--- /dev/null
+++ b/couchpotato/core/media/movie/providers/torrent/hdaccess.py
@@ -0,0 +1,11 @@
+from couchpotato.core.logger import CPLog
+from couchpotato.core.media._base.providers.torrent.hdaccess import Base
+from couchpotato.core.media.movie.providers.base import MovieProvider
+
+log = CPLog(__name__)
+
+autoload = 'HDAccess'
+
+
+class HDAccess(MovieProvider, Base):
+ pass
diff --git a/couchpotato/core/media/movie/providers/torrent/torrentz.py b/couchpotato/core/media/movie/providers/torrent/torrentz.py
index 742554c..011ec43 100644
--- a/couchpotato/core/media/movie/providers/torrent/torrentz.py
+++ b/couchpotato/core/media/movie/providers/torrent/torrentz.py
@@ -1,6 +1,5 @@
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.logger import CPLog
-from couchpotato.core.event import fireEvent
from couchpotato.core.media._base.providers.torrent.torrentz import Base
from couchpotato.core.media.movie.providers.base import MovieProvider
@@ -11,5 +10,5 @@ autoload = 'Torrentz'
class Torrentz(MovieProvider, Base):
- def buildUrl(self, media):
- return tryUrlencode('"%s"' % fireEvent('library.query', media, single = True))
+ def buildUrl(self, title, media, quality):
+ return tryUrlencode('"%s %s"' % (title, media['info']['year']))
\ No newline at end of file
diff --git a/couchpotato/core/notifications/plex/__init__.py b/couchpotato/core/notifications/plex/__init__.py
index 4a64ec5..957369b 100755
--- a/couchpotato/core/notifications/plex/__init__.py
+++ b/couchpotato/core/notifications/plex/__init__.py
@@ -24,6 +24,26 @@ config = [{
'description': 'Hostname/IP, default localhost'
},
{
+ 'name': 'username',
+ 'label': 'Username',
+ 'default': '',
+ 'description': 'Required for myPlex'
+ },
+ {
+ 'name': 'password',
+ 'label': 'Password',
+ 'default': '',
+ 'type': 'password',
+ 'description': 'Required for myPlex'
+ },
+ {
+ 'name': 'auth_token',
+ 'label': 'Auth Token',
+ 'default': '',
+ 'advanced': True,
+ 'description': 'Required for myPlex'
+ },
+ {
'name': 'clients',
'default': '',
'description': 'Comma separated list of client names\'s (computer names). Top right when you start Plex'
diff --git a/couchpotato/core/notifications/plex/server.py b/couchpotato/core/notifications/plex/server.py
index cd11f49..4b8ea05 100644
--- a/couchpotato/core/notifications/plex/server.py
+++ b/couchpotato/core/notifications/plex/server.py
@@ -35,11 +35,46 @@ class PlexServer(object):
if path.startswith('/'):
path = path[1:]
- data = self.plex.urlopen('%s/%s' % (
- self.createHost(self.plex.conf('media_server'), port = 32400),
- path
- ))
-
+ #Maintain support for older Plex installations without myPlex
+ if not self.plex.conf('auth_token') and not self.plex.conf('username') and not self.plex.conf('password'):
+ data = self.plex.urlopen('%s/%s' % (
+ self.createHost(self.plex.conf('media_server'), port = 32400),
+ path
+ ))
+ else:
+ #Fetch X-Plex-Token if it doesn't exist but a username/password do
+ if not self.plex.conf('auth_token') and (self.plex.conf('username') and self.plex.conf('password')):
+ import urllib2, base64
+ log.info("Fetching a new X-Plex-Token from plex.tv")
+ username = self.plex.conf('username')
+ password = self.plex.conf('password')
+ req = urllib2.Request("https://plex.tv/users/sign_in.xml", data="")
+ authheader = "Basic %s" % base64.encodestring('%s:%s' % (username, password))[:-1]
+ req.add_header("Authorization", authheader)
+ req.add_header("X-Plex-Product", "Couchpotato Notifier")
+ req.add_header("X-Plex-Client-Identifier", "b3a6b24dcab2224bdb101fc6aa08ea5e2f3147d6")
+ req.add_header("X-Plex-Version", "1.0")
+
+ try:
+ response = urllib2.urlopen(req)
+ except urllib2.URLError, e:
+ log.info("Error fetching token from plex.tv")
+
+ try:
+ auth_tree = etree.parse(response)
+ token = auth_tree.findall(".//authentication-token")[0].text
+ self.plex.conf('auth_token', token)
+
+ except (ValueError, IndexError) as e:
+ log.info("Error parsing plex.tv response: " + ex(e))
+
+ #Add X-Plex-Token header for myPlex support workaround
+ data = self.plex.urlopen('%s/%s?X-Plex-Token=%s' % (
+ self.createHost(self.plex.conf('media_server'), port = 32400),
+ path,
+ self.plex.conf('auth_token')
+ ))
+
if data_type == 'xml':
return etree.fromstring(data)
else:
diff --git a/couchpotato/core/notifications/webhook.py b/couchpotato/core/notifications/webhook.py
new file mode 100644
index 0000000..8dc6329
--- /dev/null
+++ b/couchpotato/core/notifications/webhook.py
@@ -0,0 +1,68 @@
+import traceback
+
+from couchpotato.core.helpers.encoding import toUnicode
+from couchpotato.core.helpers.variable import getIdentifier
+from couchpotato.core.logger import CPLog
+from couchpotato.core.notifications.base import Notification
+
+
+log = CPLog(__name__)
+
+autoload = 'Webhook'
+
+class Webhook(Notification):
+
+ def notify(self, message = '', data = None, listener = None):
+ if not data: data = {}
+
+ post_data = {
+ 'message': toUnicode(message)
+ }
+
+ if getIdentifier(data):
+ post_data.update({
+ 'imdb_id': getIdentifier(data)
+ })
+
+ headers = {
+ 'Content-type': 'application/x-www-form-urlencoded'
+ }
+
+ try:
+ self.urlopen(self.conf('url'), headers = headers, data = post_data, show_error = False)
+ return True
+ except:
+ log.error('Webhook notification failed: %s', traceback.format_exc())
+
+ return False
+
+
+config = [{
+ 'name': 'webhook',
+ 'groups': [
+ {
+ 'tab': 'notifications',
+ 'list': 'notification_providers',
+ 'name': 'webhook',
+ 'label': 'Webhook',
+ 'options': [
+ {
+ 'name': 'enabled',
+ 'default': 0,
+ 'type': 'enabler',
+ },
+ {
+ 'name': 'url',
+ 'description': 'The URL to send notification data to when '
+ },
+ {
+ 'name': 'on_snatch',
+ 'default': 0,
+ 'type': 'bool',
+ 'advanced': True,
+ 'description': 'Also send message when movie is snatched.',
+ }
+ ]
+ }
+ ]
+}]
diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py
index c02e8f7..e4b27c9 100644
--- a/couchpotato/core/plugins/base.py
+++ b/couchpotato/core/plugins/base.py
@@ -206,7 +206,7 @@ class Plugin(object):
if self.http_failed_disabled[host] > (time.time() - 900):
log.info2('Disabled calls to %s for 15 minutes because so many failed requests.', host)
if not show_error:
- raise Exception('Disabled calls to %s for 15 minutes because so many failed requests')
+ raise Exception('Disabled calls to %s for 15 minutes because so many failed requests' % host)
else:
return ''
else:
diff --git a/couchpotato/core/plugins/browser.py b/couchpotato/core/plugins/browser.py
index 632375d..660070a 100644
--- a/couchpotato/core/plugins/browser.py
+++ b/couchpotato/core/plugins/browser.py
@@ -87,6 +87,7 @@ class FileBrowser(Plugin):
try:
dirs = self.getDirectories(path = path, show_hidden = show_hidden)
except:
+ log.error('Failed getting directory "%s" : %s', (path, traceback.format_exc()))
dirs = []
parent = os.path.dirname(path.rstrip(os.path.sep))
diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py
index d0720d0..60b4f8b 100755
--- a/couchpotato/core/plugins/renamer.py
+++ b/couchpotato/core/plugins/renamer.py
@@ -885,7 +885,9 @@ Remove it if you want it to be renamed (again, or at least let it try again)
#If information is not available, we don't want the tag in the filename
replaced = replaced.replace('<' + x + '>', '')
- replaced = self.replaceDoubles(replaced.lstrip('. '))
+ if self.conf('replace_doubles'):
+ replaced = self.replaceDoubles(replaced.lstrip('. '))
+
for x, r in replacements.items():
if x in ['thename', 'namethe']:
replaced = replaced.replace(six.u('<%s>') % toUnicode(x), toUnicode(r))
@@ -1343,6 +1345,14 @@ config = [{
'options': rename_options
},
{
+ 'advanced': True,
+ 'name': 'replace_doubles',
+ 'type': 'bool',
+ 'label': 'Clean Name',
+ 'description': ('Attempt to clean up double separaters due to missing data for fields.','Sometimes this eliminates wanted white space (see #2782).'),
+ 'default': True
+ },
+ {
'name': 'unrar',
'type': 'bool',
'description': 'Extract rar files if found.',
diff --git a/init/ubuntu b/init/ubuntu
index a21e2d3..cbe20e0 100755
--- a/init/ubuntu
+++ b/init/ubuntu
@@ -95,6 +95,8 @@ fi
case "$1" in
start)
+ touch $PID_FILE
+ chown $RUN_AS $PID_FILE
echo "Starting $DESC"
start-stop-daemon -d $APP_PATH -c $RUN_AS $EXTRA_SSD_OPTS --start --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_OPTS
;;