Browse Source

Merge branch 'develop'

tags/build/2.6.2
Ruud 10 years ago
parent
commit
a4dff7a331
  1. 2
      couchpotato/core/downloaders/putio/__init__.py
  2. 21
      couchpotato/core/downloaders/putio/main.py
  3. 2
      couchpotato/core/downloaders/synology.py
  4. 9
      couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py
  5. 130
      couchpotato/core/media/_base/providers/torrent/hdaccess.py
  6. 12
      couchpotato/core/media/_base/providers/torrent/iptorrents.py
  7. 2
      couchpotato/core/media/_base/providers/torrent/kickasstorrents.py
  8. 2
      couchpotato/core/media/_base/providers/torrent/torrentbytes.py
  9. 19
      couchpotato/core/media/_base/providers/torrent/torrentday.py
  10. 4
      couchpotato/core/media/_base/providers/torrent/torrentz.py
  11. 51
      couchpotato/core/media/_base/providers/torrent/yify.py
  12. 89
      couchpotato/core/media/movie/providers/automation/crowdai.py
  13. 9
      couchpotato/core/media/movie/providers/automation/letterboxd.py
  14. 5
      couchpotato/core/media/movie/providers/automation/rottentomatoes.py
  15. 2
      couchpotato/core/media/movie/providers/torrent/bitsoup.py
  16. 11
      couchpotato/core/media/movie/providers/torrent/hdaccess.py
  17. 5
      couchpotato/core/media/movie/providers/torrent/torrentz.py
  18. 20
      couchpotato/core/notifications/plex/__init__.py
  19. 45
      couchpotato/core/notifications/plex/server.py
  20. 68
      couchpotato/core/notifications/webhook.py
  21. 2
      couchpotato/core/plugins/base.py
  22. 1
      couchpotato/core/plugins/browser.py
  23. 12
      couchpotato/core/plugins/renamer.py
  24. 2
      init/ubuntu

2
couchpotato/core/downloaders/putio/__init__.py

@ -30,7 +30,7 @@ config = [{
}, },
{ {
'name': 'folder', '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, 'default': 0,
}, },
{ {

21
couchpotato/core/downloaders/putio/main.py

@ -28,16 +28,25 @@ class PutIO(DownloaderBase):
return super(PutIO, self).__init__() 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): def convertFolder(self, client, folder):
if folder == 0: if folder == 0:
return 0 return 0
else: else:
files = client.File.list() return self.recursionFolder(client, 0, folder)
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
def download(self, data = None, media = None, filedata = None): def download(self, data = None, media = None, filedata = None):
if not media: media = {} if not media: media = {}

2
couchpotato/core/downloaders/synology.py

@ -137,7 +137,7 @@ class SynologyRPC(object):
def _req(self, url, args, files = None): def _req(self, url, args, files = None):
response = {'success': False} response = {'success': False}
try: try:
req = requests.post(url, data = args, files = files) req = requests.post(url, data = args, files = files, verify = False)
req.raise_for_status() req.raise_for_status()
response = json.loads(req.text) response = json.loads(req.text)
if response['success']: if response['success']:

9
couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py

@ -18,20 +18,13 @@ class Base(NZBProvider, RSS):
http_time_between_calls = 1 # Seconds http_time_between_calls = 1 # Seconds
cat_ids = [ cat_ids = [
([15], ['dvdrip']), ([15], ['dvdrip', 'scr', 'r5', 'tc', 'ts', 'cam']),
([15, 16], ['brrip']), ([15, 16], ['brrip']),
([16], ['720p', '1080p', 'bd50']), ([16], ['720p', '1080p', 'bd50']),
([17], ['dvdr']), ([17], ['dvdr']),
] ]
cat_backup_id = 'movie' 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): def _searchOnTitle(self, title, movie, quality, results):
q = '%s %s' % (title, movie['info']['year']) q = '%s %s' % (title, movie['info']['year'])

130
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': '<a href="https://hdaccess.net">HDAccess</a>',
'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 <a href="https://hdaccess.net/usercp.php?action=security">Profile Security</a>',
},
{
'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.',
}
],
},
],
}]

12
couchpotato/core/media/_base/providers/torrent/iptorrents.py

@ -14,11 +14,11 @@ log = CPLog(__name__)
class Base(TorrentProvider): class Base(TorrentProvider):
urls = { urls = {
'test': 'https://www.iptorrents.com/', 'test': 'https://iptorrents.eu/',
'base_url': 'https://www.iptorrents.com', 'base_url': 'https://iptorrents.eu',
'login': 'https://www.iptorrents.com/torrents/', 'login': 'https://iptorrents.eu/torrents/',
'login_check': 'https://www.iptorrents.com/inbox.php', 'login_check': 'https://iptorrents.eu/inbox.php',
'search': 'https://www.iptorrents.com/torrents/?%s%%s&q=%s&qf=ti&p=%%d', 'search': 'https://iptorrents.eu/torrents/?%s%%s&q=%s&qf=ti&p=%%d',
} }
http_time_between_calls = 1 # Seconds http_time_between_calls = 1 # Seconds
@ -120,7 +120,7 @@ config = [{
'tab': 'searcher', 'tab': 'searcher',
'list': 'torrent_providers', 'list': 'torrent_providers',
'name': 'IPTorrents', 'name': 'IPTorrents',
'description': '<a href="http://www.iptorrents.com">IPTorrents</a>', 'description': '<a href="https://iptorrents.eu">IPTorrents</a>',
'wizard': True, 'wizard': True,
'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABRklEQVR42qWQO0vDUBiG8zeKY3EqQUtNO7g0J6ZJ1+ifKIIFQXAqDYKCyaaYxM3udrZLHdRFhXrZ6liCW6mubfk874EESgqaeOCF7/Y8hEh41aq6yZi2nyZgBGya9XKtZs4No05pAkZV2YbEmyMMsoSxLQeC46wCTdPPY4HruPQyGIhF97qLWsS78Miydn4XdK46NJ9OsQAYBzMIMf8MQ9wtCnTdWCaIDx/u7uljOIQEe0hiIWPamSTLay3+RxOCSPI9+RJAo7Er9r2bnqjBFAqyK+VyK4f5/Cr5ni8OFKVCz49PFI5GdNvvU7ttE1M1zMU+8AMqFksEhrMnQsBDzqmDAwzx2ehRLwT7yyCI+vSC99c3mozH1NxrJgWWtR1BOECfEJSVCm6WCzJGCA7+IWhBsM4zywDPwEp4vCjx2DzBH2ODAfsDb33Ps6dQwJgAAAAASUVORK5CYII=', 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABRklEQVR42qWQO0vDUBiG8zeKY3EqQUtNO7g0J6ZJ1+ifKIIFQXAqDYKCyaaYxM3udrZLHdRFhXrZ6liCW6mubfk874EESgqaeOCF7/Y8hEh41aq6yZi2nyZgBGya9XKtZs4No05pAkZV2YbEmyMMsoSxLQeC46wCTdPPY4HruPQyGIhF97qLWsS78Miydn4XdK46NJ9OsQAYBzMIMf8MQ9wtCnTdWCaIDx/u7uljOIQEe0hiIWPamSTLay3+RxOCSPI9+RJAo7Er9r2bnqjBFAqyK+VyK4f5/Cr5ni8OFKVCz49PFI5GdNvvU7ttE1M1zMU+8AMqFksEhrMnQsBDzqmDAwzx2ehRLwT7yyCI+vSC99c3mozH1NxrJgWWtR1BOECfEJSVCm6WCzJGCA7+IWhBsM4zywDPwEp4vCjx2DzBH2ODAfsDb33Ps6dQwJgAAAAASUVORK5CYII=',
'options': [ 'options': [

2
couchpotato/core/media/_base/providers/torrent/kickasstorrents.py

@ -30,7 +30,7 @@ class Base(TorrentMagnetProvider):
cat_backup_id = None cat_backup_id = None
proxy_list = [ proxy_list = [
'https://kickass.so', 'https://kickass.to',
'http://kickass.pw', 'http://kickass.pw',
'http://kickassto.come.in', 'http://kickassto.come.in',
'http://katproxy.ws', 'http://katproxy.ws',

2
couchpotato/core/media/_base/providers/torrent/torrentbytes.py

@ -56,7 +56,7 @@ class Base(TorrentProvider):
full_id = link['href'].replace('details.php?id=', '') full_id = link['href'].replace('details.php?id=', '')
torrent_id = full_id[:6] 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({ results.append({
'id': torrent_id, 'id': torrent_id,

19
couchpotato/core/media/_base/providers/torrent/torrentday.py

@ -1,3 +1,4 @@
import re
from couchpotato.core.helpers.variable import tryInt from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
@ -8,12 +9,12 @@ log = CPLog(__name__)
class Base(TorrentProvider): class Base(TorrentProvider):
urls = { urls = {
'test': 'http://www.td.af/', 'test': 'https://torrentday.eu/',
'login': 'http://www.td.af/torrents/', 'login': 'https://torrentday.eu/torrents/',
'login_check': 'http://www.torrentday.com/userdetails.php', 'login_check': 'https://torrentday.eu/userdetails.php',
'detail': 'http://www.td.af/details.php?id=%s', 'detail': 'https://torrentday.eu/details.php?id=%s',
'search': 'http://www.td.af/V3/API/API.php', 'search': 'https://torrentday.eu/V3/API/API.php',
'download': 'http://www.td.af/download.php/%s/%s', 'download': 'https://torrentday.eu/download.php/%s/%s',
} }
http_time_between_calls = 1 # Seconds http_time_between_calls = 1 # Seconds
@ -55,6 +56,10 @@ class Base(TorrentProvider):
} }
def loginSuccess(self, output): def loginSuccess(self, output):
often = re.search('You tried too often, please wait .*</div>', output)
if often:
raise Exception(often.group(0)[:-6].strip())
return 'Password not correct' not in output return 'Password not correct' not in output
def loginCheckSuccess(self, output): def loginCheckSuccess(self, output):
@ -68,7 +73,7 @@ config = [{
'tab': 'searcher', 'tab': 'searcher',
'list': 'torrent_providers', 'list': 'torrent_providers',
'name': 'TorrentDay', 'name': 'TorrentDay',
'description': '<a href="http://www.td.af/">TorrentDay</a>', 'description': '<a href="https://torrentday.eu/">TorrentDay</a>',
'wizard': True, '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=', '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': [ 'options': [

4
couchpotato/core/media/_base/providers/torrent/torrentz.py

@ -22,12 +22,12 @@ class Base(TorrentMagnetProvider, RSS):
http_time_between_calls = 0 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'] search_url = self.urls['verified_search'] if self.conf('verified_only') else self.urls['search']
# Create search parameters # Create search parameters
search_params = self.buildUrl(media) search_params = self.buildUrl(title, media, quality)
smin = quality.get('size_min') smin = quality.get('size_min')
smax = quality.get('size_max') smax = quality.get('size_max')

51
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.helpers.variable import tryInt, getIdentifier
from couchpotato.core.logger import CPLog 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__) log = CPLog(__name__)
class Base(TorrentMagnetProvider): class Base(TorrentProvider):
urls = { urls = {
'test': '%s/api', 'test': '%s/api/v2',
'search': '%s/api/list.json?keywords=%s', 'search': '%s/api/v2/list_movies.json?limit=50&query_term=%s'
'detail': '%s/api/movie.json?id=%s'
} }
http_time_between_calls = 1 # seconds http_time_between_calls = 1 # seconds
proxy_list = [ proxy_list = [
'https://yts.re', 'https://yts.re',
'http://ytsproxy.come.in', 'https://yts.wf',
'http://yts.im', 'https://yts.im',
'http://yify-torrents.im',
] ]
def search(self, movie, quality): def search(self, movie, quality):
@ -41,25 +39,28 @@ class Base(TorrentMagnetProvider):
search_url = self.urls['search'] % (domain, getIdentifier(movie)) search_url = self.urls['search'] % (domain, getIdentifier(movie))
data = self.getJsonData(search_url) data = self.getJsonData(search_url)
data = data.get('data')
if data and data.get('MovieList'): if data and data.get('movies'):
try: try:
for result in data.get('MovieList'): for result in data.get('movies'):
if result['Quality'] and result['Quality'] not in result['MovieTitle']: for release in result.get('torrents', []):
title = result['MovieTitle'] + ' BrRip ' + result['Quality']
else: if release['quality'] and release['quality'] not in result['title_long']:
title = result['MovieTitle'] + ' BrRip' title = result['title_long'] + ' BRRip ' + release['quality']
else:
results.append({ title = result['title_long'] + ' BRRip'
'id': result['MovieID'],
'name': title, results.append({
'url': result['TorrentMagnetUrl'], 'id': release['hash'],
'detail_url': self.urls['detail'] % (domain, result['MovieID']), 'name': title,
'size': self.parseSize(result['Size']), 'url': release['url'],
'seeders': tryInt(result['TorrentSeeds']), 'detail_url': result['url'],
'leechers': tryInt(result['TorrentPeers']), 'size': self.parseSize(release['size']),
}) 'seeders': tryInt(release['seeds']),
'leechers': tryInt(release['peers']),
})
except: except:
log.error('Failed getting results from %s: %s', (self.getName(), traceback.format_exc())) log.error('Failed getting results from %s: %s', (self.getName(), traceback.format_exc()))

89
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',
},
],
},
],
}]

9
couchpotato/core/media/movie/providers/automation/letterboxd.py

@ -48,11 +48,12 @@ class Letterboxd(Automation):
soup = BeautifulSoup(self.getHTMLData(self.url % username)) soup = BeautifulSoup(self.getHTMLData(self.url % username))
for movie in soup.find_all('a', attrs = {'class': 'frame'}): for movie in soup.find_all('li', attrs = {'class': 'poster-container'}):
match = removeEmpty(self.pattern.split(movie['title'])) img = movie.find('img', movie)
title = img.get('alt')
movies.append({ movies.append({
'title': match[0], 'title': title
'year': match[1]
}) })
return movies return movies

5
couchpotato/core/media/movie/providers/automation/rottentomatoes.py

@ -39,15 +39,14 @@ class Rottentomatoes(Automation, RSS):
if result: if result:
log.info2('Something smells...')
rating = tryInt(self.getTextElement(movie, rating_tag)) rating = tryInt(self.getTextElement(movie, rating_tag))
name = result.group(0) name = result.group(0)
print rating, tryInt(self.conf('tomatometer_percent'))
if rating < tryInt(self.conf('tomatometer_percent')): if rating < tryInt(self.conf('tomatometer_percent')):
log.info2('%s seems to be rotten...', name) log.info2('%s seems to be rotten...', name)
else: else:
log.info2('Found %s with fresh rating %s', (name, rating))
log.info2('Found %s fresh enough movies, enqueuing: %s', (rating, name))
year = datetime.datetime.now().strftime("%Y") year = datetime.datetime.now().strftime("%Y")
imdb = self.search(name, year) imdb = self.search(name, year)

2
couchpotato/core/media/movie/providers/torrent/bitsoup.py

@ -11,7 +11,7 @@ autoload = 'Bitsoup'
class Bitsoup(MovieProvider, Base): class Bitsoup(MovieProvider, Base):
cat_ids = [ cat_ids = [
([17], ['3d']), ([17], ['3d']),
([41], ['720p', '1080p']), ([80], ['720p', '1080p']),
([20], ['dvdr']), ([20], ['dvdr']),
([19], ['brrip', 'dvdrip']), ([19], ['brrip', 'dvdrip']),
] ]

11
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

5
couchpotato/core/media/movie/providers/torrent/torrentz.py

@ -1,6 +1,5 @@
from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.logger import CPLog 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._base.providers.torrent.torrentz import Base
from couchpotato.core.media.movie.providers.base import MovieProvider from couchpotato.core.media.movie.providers.base import MovieProvider
@ -11,5 +10,5 @@ autoload = 'Torrentz'
class Torrentz(MovieProvider, Base): class Torrentz(MovieProvider, Base):
def buildUrl(self, media): def buildUrl(self, title, media, quality):
return tryUrlencode('"%s"' % fireEvent('library.query', media, single = True)) return tryUrlencode('"%s %s"' % (title, media['info']['year']))

20
couchpotato/core/notifications/plex/__init__.py

@ -24,6 +24,26 @@ config = [{
'description': 'Hostname/IP, default localhost' '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', 'name': 'clients',
'default': '', 'default': '',
'description': 'Comma separated list of client names\'s (computer names). Top right when you start Plex' 'description': 'Comma separated list of client names\'s (computer names). Top right when you start Plex'

45
couchpotato/core/notifications/plex/server.py

@ -35,11 +35,46 @@ class PlexServer(object):
if path.startswith('/'): if path.startswith('/'):
path = path[1:] path = path[1:]
data = self.plex.urlopen('%s/%s' % ( #Maintain support for older Plex installations without myPlex
self.createHost(self.plex.conf('media_server'), port = 32400), if not self.plex.conf('auth_token') and not self.plex.conf('username') and not self.plex.conf('password'):
path 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': if data_type == 'xml':
return etree.fromstring(data) return etree.fromstring(data)
else: else:

68
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.',
}
]
}
]
}]

2
couchpotato/core/plugins/base.py

@ -206,7 +206,7 @@ class Plugin(object):
if self.http_failed_disabled[host] > (time.time() - 900): if self.http_failed_disabled[host] > (time.time() - 900):
log.info2('Disabled calls to %s for 15 minutes because so many failed requests.', host) log.info2('Disabled calls to %s for 15 minutes because so many failed requests.', host)
if not show_error: 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: else:
return '' return ''
else: else:

1
couchpotato/core/plugins/browser.py

@ -87,6 +87,7 @@ class FileBrowser(Plugin):
try: try:
dirs = self.getDirectories(path = path, show_hidden = show_hidden) dirs = self.getDirectories(path = path, show_hidden = show_hidden)
except: except:
log.error('Failed getting directory "%s" : %s', (path, traceback.format_exc()))
dirs = [] dirs = []
parent = os.path.dirname(path.rstrip(os.path.sep)) parent = os.path.dirname(path.rstrip(os.path.sep))

12
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 #If information is not available, we don't want the tag in the filename
replaced = replaced.replace('<' + x + '>', '') 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(): for x, r in replacements.items():
if x in ['thename', 'namethe']: if x in ['thename', 'namethe']:
replaced = replaced.replace(six.u('<%s>') % toUnicode(x), toUnicode(r)) replaced = replaced.replace(six.u('<%s>') % toUnicode(x), toUnicode(r))
@ -1343,6 +1345,14 @@ config = [{
'options': rename_options '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 <a href="https://github.com/RuudBurger/CouchPotatoServer/issues/2782">#2782</a>).'),
'default': True
},
{
'name': 'unrar', 'name': 'unrar',
'type': 'bool', 'type': 'bool',
'description': 'Extract rar files if found.', 'description': 'Extract rar files if found.',

2
init/ubuntu

@ -95,6 +95,8 @@ fi
case "$1" in case "$1" in
start) start)
touch $PID_FILE
chown $RUN_AS $PID_FILE
echo "Starting $DESC" echo "Starting $DESC"
start-stop-daemon -d $APP_PATH -c $RUN_AS $EXTRA_SSD_OPTS --start --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_OPTS start-stop-daemon -d $APP_PATH -c $RUN_AS $EXTRA_SSD_OPTS --start --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_OPTS
;; ;;

Loading…
Cancel
Save