Browse Source

Merge branch 'refs/heads/develop' into tv

pull/3111/head
Ruud 11 years ago
parent
commit
0f555dbb85
  1. 51
      contributing.md
  2. 4
      couchpotato/__init__.py
  3. 4
      couchpotato/core/database.py
  4. 2
      couchpotato/core/downloaders/base.py
  5. 2
      couchpotato/core/downloaders/deluge.py
  6. 2
      couchpotato/core/downloaders/qbittorrent_.py
  7. 20
      couchpotato/core/downloaders/rtorrent_.py
  8. 14
      couchpotato/core/downloaders/synology.py
  9. 2
      couchpotato/core/downloaders/transmission.py
  10. 2
      couchpotato/core/downloaders/utorrent.py
  11. 10
      couchpotato/core/helpers/variable.py
  12. 5
      couchpotato/core/media/__init__.py
  13. 25
      couchpotato/core/media/_base/media/index.py
  14. 63
      couchpotato/core/media/_base/media/main.py
  15. 4
      couchpotato/core/media/_base/providers/torrent/awesomehd.py
  16. 6
      couchpotato/core/media/_base/providers/torrent/hdbits.py
  17. 4
      couchpotato/core/media/_base/providers/torrent/kickasstorrents.py
  18. 4
      couchpotato/core/media/_base/providers/torrent/passthepopcorn.py
  19. 4
      couchpotato/core/media/_base/providers/torrent/thepiratebay.py
  20. 4
      couchpotato/core/media/_base/providers/torrent/yify.py
  21. 39
      couchpotato/core/media/movie/_base/main.py
  22. 2
      couchpotato/core/media/movie/_base/static/movie.actions.js
  23. 2
      couchpotato/core/media/movie/providers/automation/itunes.py
  24. 4
      couchpotato/core/media/movie/providers/info/_modifier.py
  25. 3
      couchpotato/core/media/movie/providers/nzb/binsearch.py
  26. 3
      couchpotato/core/media/movie/providers/nzb/newznab.py
  27. 2
      couchpotato/core/media/movie/providers/nzb/nzbindex.py
  28. 2
      couchpotato/core/media/movie/providers/torrent/bitsoup.py
  29. 2
      couchpotato/core/media/movie/providers/torrent/iptorrents.py
  30. 3
      couchpotato/core/media/movie/providers/torrent/torrentpotato.py
  31. 33
      couchpotato/core/media/movie/searcher.py
  32. 11
      couchpotato/core/media/movie/suggestion/main.py
  33. 2
      couchpotato/core/notifications/boxcar.py
  34. 2
      couchpotato/core/notifications/boxcar2.py
  35. 2
      couchpotato/core/notifications/email_.py
  36. 2
      couchpotato/core/notifications/growl.py
  37. 2
      couchpotato/core/notifications/nmj.py
  38. 2
      couchpotato/core/notifications/notifymyandroid.py
  39. 2
      couchpotato/core/notifications/notifymywp.py
  40. 2
      couchpotato/core/notifications/prowl.py
  41. 2
      couchpotato/core/notifications/pushalot.py
  42. 2
      couchpotato/core/notifications/pushbullet.py
  43. 10
      couchpotato/core/plugins/base.py
  44. 2
      couchpotato/core/plugins/dashboard.py
  45. 5
      couchpotato/core/plugins/file.py
  46. 7
      couchpotato/core/plugins/manage.py
  47. 4
      couchpotato/core/plugins/profile/main.py
  48. 8
      couchpotato/core/plugins/quality/main.py
  49. 18
      couchpotato/core/plugins/release/index.py
  50. 23
      couchpotato/core/plugins/release/main.py
  51. 47
      couchpotato/core/plugins/renamer.py
  52. 4
      couchpotato/core/plugins/scanner.py
  53. 7
      libs/rtorrent/__init__.py
  54. 38
      libs/rtorrent/lib/xmlrpc/basic_auth.py

51
contributing.md

@ -1,25 +1,36 @@
## Got a issue/feature request or submitting a pull request? # Contributing to CouchPotatoServer
Make sure you think of the following things: 1. [Contributing](#contributing)
2. [Submitting an Issue](#issues)
3. [Submitting a Pull Request](#pull-requests)
## Issue ## Contributing
* Search through the existing (and closed) issues first, see if you can get your answer there. Thank you for your interest in contributing to CouchPotato. There are several ways to help out, even if you've never worked on an open source project before.
* Double check the result manually, because it could be an external issue. If you've found a bug or want to request a feature, you can report it by [posting an issue](https://github.com/RuudBurger/CouchPotatoServer/issues/new) - be sure to read the [guidelines](#issues) first!
* Post logs! Without seeing what is going on, I can't reproduce the error. If you want to contribute your own work, please read the [guidelines](#pull-requests) for submitting a pull request.
* Also check the logs before submitting, obvious errors like permission or http errors are often not related to CP. Lastly, for anything related to CouchPotato, feel free to stop by the [forum](http://couchpota.to/forum/) or the [#couchpotato](http://webchat.freenode.net/?channels=couchpotato) IRC channel at irc.freenode.net.
* What is the movie + quality you are searching for?
* What are you're settings for the specific problem? ## Issues
* What providers are you using? (While you're logs include these, scanning through hundred of lines of log isn't our hobby) Issues are intended for reporting bugs and weird behaviour or suggesting improvements to CouchPotatoServer.
* Post the logs from config directory, please do not copy paste the UI. Use pastebin to store these logs! Before you submit an issue, please go through the following checklist:
* Search through existing issues (*including closed issues!*) first: you might be able to get your answer there.
* Double check your issue manually, because it could be an external issue.
* Post logs with your issue: Without seeing what is going on, the developers can't reproduce the error.
* Check the logs yourself before submitting them. Obvious errors like permission or HTTP errors are often not related to CouchPotato.
* What movie and quality are you searching for?
* What are your settings for the specific problem?
* What providers are you using? (While your logs include these, scanning through hundreds of lines of logs isn't our hobby)
* Post the logs from the *config* directory, please do not copy paste the UI. Use pastebin to store these logs!
* Give a short step by step of how to reproduce the error. * Give a short step by step of how to reproduce the error.
* What hardware / OS are you using and what are the limits? NAS can be slow and maybe have a different python installed then when you use CP on OSX or Windows for example. * What hardware / OS are you using and what are its limitations? For example: NAS can be slow and maybe have a different version of python installed then when you use CP on OSX or Windows.
* I will mark issues with the "can't reproduce" tag. Don't go asking "why closed" if it clearly says the issue in the tag ;) * Your issue might be marked with the "can't reproduce" tag. Don't ask why your issue was closed if it says so in the tag.
* If you're running on a NAS (QNAP, Austor etc..) with pre-made packages, make sure these are setup to use our source repo (RuudBurger/CouchPotatoServer) and nothing else!! * If you're running on a NAS (QNAP, Austor etc..) with pre-made packages, make sure these are set up to use our source repository (RuudBurger/CouchPotatoServer) and nothing else!!
## Pull Request The more relevant information you can provide, the more likely it is the issue will be resolved rather than closed.
* Make sure you're pull request is made for develop branch (or relevant feature branch)
* Have you tested your PR? If not, why?
* Are there any limitations of your PR we should know of?
* Make sure to keep you're PR up-to-date with the branch you're trying to push into.
**If we don't get enough info, the chance of the issue getting closed is a lot bigger ;)** ## Pull Requests
Pull requests are intended for contributing code or documentation to the project. Before you submit a pull request, consider the following:
* Make sure your pull request is made for the *develop* branch (or relevant feature branch).
* Have you tested your PR? If not, why?
* Does your PR have any limitations we should know of?
* Is your PR up-to-date with the branch you're trying to push into?

4
couchpotato/__init__.py

@ -48,10 +48,6 @@ def addView(route, func, static = False):
views[route] = func views[route] = func
def get_session():
return None
def get_db(): def get_db():
return Env.get('db') return Env.get('db')

4
couchpotato/core/database.py

@ -279,8 +279,8 @@ class Database(object):
quality = db.get('id', q_id) quality = db.get('id', q_id)
quality['order'] = q.get('order') quality['order'] = q.get('order')
quality['size_min'] = q.get('size_min') quality['size_min'] = tryInt(q.get('size_min'))
quality['size_max'] = q.get('size_max') quality['size_max'] = tryInt(q.get('size_max'))
db.update(quality) db.update(quality)
quality_link[x] = quality quality_link[x] = quality

2
couchpotato/core/downloaders/base.py

@ -210,7 +210,7 @@ class ReleaseDownloadList(list):
'status': 'busy', 'status': 'busy',
'downloader': self.provider.getName(), 'downloader': self.provider.getName(),
'folder': '', 'folder': '',
'files': '', 'files': [],
} }
return mergeDicts(defaults, result) return mergeDicts(defaults, result)

2
couchpotato/core/downloaders/deluge.py

@ -147,7 +147,7 @@ class Deluge(Downloader):
'seed_ratio': torrent['ratio'], 'seed_ratio': torrent['ratio'],
'timeleft': str(timedelta(seconds = torrent['eta'])), 'timeleft': str(timedelta(seconds = torrent['eta'])),
'folder': sp(download_dir if len(torrent_files) == 1 else os.path.join(download_dir, torrent['name'])), 'folder': sp(download_dir if len(torrent_files) == 1 else os.path.join(download_dir, torrent['name'])),
'files': '|'.join(torrent_files), 'files': torrent_files,
}) })
return release_downloads return release_downloads

2
couchpotato/core/downloaders/qbittorrent_.py

@ -135,7 +135,7 @@ class qBittorrent(Downloader):
'original_status': torrent.state, 'original_status': torrent.state,
'timeleft': torrent.progress * 100 if torrent.progress else -1, # percentage 'timeleft': torrent.progress * 100 if torrent.progress else -1, # percentage
'folder': sp(torrent.save_path), 'folder': sp(torrent.save_path),
'files': '|'.join(torrent_files) 'files': torrent_files
}) })
return release_downloads return release_downloads

20
couchpotato/core/downloaders/rtorrent_.py

@ -59,20 +59,22 @@ class rTorrent(Downloader):
return self.rt return self.rt
url = cleanHost(self.conf('host'), protocol = True, ssl = self.conf('ssl')) url = cleanHost(self.conf('host'), protocol = True, ssl = self.conf('ssl'))
# Automatically add '+https' to 'httprpc' protocol if SSL is enabled
if self.conf('ssl') and url.startswith('httprpc://'):
url = url.replace('httprpc://', 'httprpc+https://')
parsed = urlparse(url) parsed = urlparse(url)
# rpc_url is only used on http/https scgi pass-through # rpc_url is only used on http/https scgi pass-through
if parsed.scheme in ['http', 'https']: if parsed.scheme in ['http', 'https']:
url += self.conf('rpc_url') url += self.conf('rpc_url')
if self.conf('username') and self.conf('password'): self.rt = RTorrent(
self.rt = RTorrent( url,
url, self.conf('username'),
self.conf('username'), self.conf('password')
self.conf('password') )
)
else:
self.rt = RTorrent(url)
self.error_msg = '' self.error_msg = ''
try: try:
@ -243,7 +245,7 @@ class rTorrent(Downloader):
'original_status': torrent.state, 'original_status': torrent.state,
'timeleft': str(timedelta(seconds = float(torrent.left_bytes) / torrent.down_rate)) if torrent.down_rate > 0 else -1, 'timeleft': str(timedelta(seconds = float(torrent.left_bytes) / torrent.down_rate)) if torrent.down_rate > 0 else -1,
'folder': sp(torrent.directory), 'folder': sp(torrent.directory),
'files': '|'.join(torrent_files) 'files': torrent_files
}) })
return release_downloads return release_downloads

14
couchpotato/core/downloaders/synology.py

@ -33,7 +33,7 @@ class Synology(Downloader):
try: try:
# Send request to Synology # Send request to Synology
srpc = SynologyRPC(host[0], host[1], self.conf('username'), self.conf('password')) srpc = SynologyRPC(host[0], host[1], self.conf('username'), self.conf('password'), self.conf('destination'))
if data['protocol'] == 'torrent_magnet': if data['protocol'] == 'torrent_magnet':
log.info('Adding torrent URL %s', data['url']) log.info('Adding torrent URL %s', data['url'])
response = srpc.create_task(url = data['url']) response = srpc.create_task(url = data['url'])
@ -84,7 +84,7 @@ class SynologyRPC(object):
"""SynologyRPC lite library""" """SynologyRPC lite library"""
def __init__(self, host = 'localhost', port = 5000, username = None, password = None): def __init__(self, host = 'localhost', port = 5000, username = None, password = None, destination = None):
super(SynologyRPC, self).__init__() super(SynologyRPC, self).__init__()
@ -92,6 +92,7 @@ class SynologyRPC(object):
self.auth_url = 'http://%s:%s/webapi/auth.cgi' % (host, port) self.auth_url = 'http://%s:%s/webapi/auth.cgi' % (host, port)
self.username = username self.username = username
self.password = password self.password = password
self.destination = destination
self.session_name = 'DownloadStation' self.session_name = 'DownloadStation'
def _login(self): def _login(self):
@ -144,6 +145,10 @@ class SynologyRPC(object):
'version': '1', 'version': '1',
'method': 'create', 'method': 'create',
'_sid': self.sid} '_sid': self.sid}
if self.destination and len(self.destination) > 0:
args['destination'] = self.destination
if url: if url:
log.info('Login success, adding torrent URI') log.info('Login success, adding torrent URI')
args['uri'] = url args['uri'] = url
@ -196,6 +201,11 @@ config = [{
'type': 'password', 'type': 'password',
}, },
{ {
'name': 'destination',
'description': 'Specify <strong>existing</strong> destination share to where your files will be downloaded, usually <strong>Downloads</strong>',
'advanced': True,
},
{
'name': 'use_for', 'name': 'use_for',
'label': 'Use for', 'label': 'Use for',
'default': 'both', 'default': 'both',

2
couchpotato/core/downloaders/transmission.py

@ -141,7 +141,7 @@ class Transmission(Downloader):
'seed_ratio': torrent['uploadRatio'], 'seed_ratio': torrent['uploadRatio'],
'timeleft': str(timedelta(seconds = torrent['eta'])), 'timeleft': str(timedelta(seconds = torrent['eta'])),
'folder': sp(torrent_folder if len(torrent_files) == 1 else os.path.join(torrent_folder, torrent['name'])), 'folder': sp(torrent_folder if len(torrent_files) == 1 else os.path.join(torrent_folder, torrent['name'])),
'files': '|'.join(torrent_files) 'files': torrent_files
}) })
return release_downloads return release_downloads

2
couchpotato/core/downloaders/utorrent.py

@ -184,7 +184,7 @@ class uTorrent(Downloader):
'original_status': torrent[1], 'original_status': torrent[1],
'timeleft': str(timedelta(seconds = torrent[10])), 'timeleft': str(timedelta(seconds = torrent[10])),
'folder': sp(torrent[26]), 'folder': sp(torrent[26]),
'files': '|'.join(torrent_files) 'files': torrent_files
}) })
return release_downloads return release_downloads

10
couchpotato/core/helpers/variable.py

@ -227,6 +227,10 @@ def toIterable(value):
return [value] return [value]
def getIdentifier(media):
return media.get('identifier') or media.get('identifiers', {}).get('imdb')
def getTitle(media_dict): def getTitle(media_dict):
try: try:
try: try:
@ -241,10 +245,10 @@ def getTitle(media_dict):
try: try:
return media_dict['media']['info']['titles'][0] return media_dict['media']['info']['titles'][0]
except: except:
log.error('Could not get title for %s', media_dict.get('identifier')) log.error('Could not get title for %s', getIdentifier(media_dict))
return None return None
log.error('Could not get title for %s', media_dict['identifier']) log.error('Could not get title for %s', getIdentifier(media_dict))
return None return None
except: except:
log.error('Could not get title for library item: %s', media_dict) log.error('Could not get title for library item: %s', media_dict)
@ -293,7 +297,7 @@ def isSubFolder(sub_folder, base_folder):
return base_folder and sub_folder and ss(os.path.normpath(base_folder).rstrip(os.path.sep) + os.path.sep) in ss(os.path.normpath(sub_folder).rstrip(os.path.sep) + os.path.sep) return base_folder and sub_folder and ss(os.path.normpath(base_folder).rstrip(os.path.sep) + os.path.sep) in ss(os.path.normpath(sub_folder).rstrip(os.path.sep) + os.path.sep)
# From SABNZBD # From SABNZBD
re_password = [re.compile(r'([^/\\]+)[/\\](.+)'), re.compile(r'(.+){{([^{}]+)}}$'), re.compile(r'(.+)\s+password\s*=\s*(.+)$', re.I)] re_password = [re.compile(r'(.+){{([^{}]+)}}$'), re.compile(r'(.+)\s+password\s*=\s*(.+)$', re.I)]
def scanForPassword(name): def scanForPassword(name):
m = None m = None
for reg in re_password: for reg in re_password:

5
couchpotato/core/media/__init__.py

@ -25,7 +25,7 @@ class MediaBase(Plugin):
def onComplete(): def onComplete():
try: try:
db = get_db() db = get_db()
media = db.get('id', media_id) media = fireEvent('media.get', media_id, single = True)
event_name = '%s.searcher.single' % media.get('type') event_name = '%s.searcher.single' % media.get('type')
fireEventAsync(event_name, media, on_complete = self.createNotifyFront(media_id)) fireEventAsync(event_name, media, on_complete = self.createNotifyFront(media_id))
@ -38,8 +38,7 @@ class MediaBase(Plugin):
def notifyFront(): def notifyFront():
try: try:
db = get_db() media = fireEvent('media.get', media_id, single = True)
media = db.get('id', media_id)
event_name = '%s.update' % media.get('type') event_name = '%s.update' % media.get('type')
fireEvent('notify.frontend', type = event_name, data = media) fireEvent('notify.frontend', type = event_name, data = media)

25
couchpotato/core/media/_base/media/index.py

@ -6,7 +6,7 @@ from couchpotato.core.helpers.encoding import toUnicode, simplifyString
class MediaIndex(MultiTreeBasedIndex): class MediaIndex(MultiTreeBasedIndex):
_version = 2 _version = 3
custom_header = """from CodernityDB.tree_index import MultiTreeBasedIndex""" custom_header = """from CodernityDB.tree_index import MultiTreeBasedIndex"""
@ -26,31 +26,10 @@ class MediaIndex(MultiTreeBasedIndex):
ids = [] ids = []
for x in identifiers: for x in identifiers:
ids.append(md5('%s-%s' % (x, data['identifiers'][x])).hexdigest()) ids.append(md5('%s-%s' % (x, identifiers[x])).hexdigest())
return ids, None return ids, None
def run_to_dict(self, db, media_id, dict_dept = None):
if not dict_dept: dict_dept = {}
return db.get('id', media_id)
def run_identifiers(self, db, identifiers, with_doc = False):
for x in identifiers:
try:
media = db.get('media', '%s-%s' % (x, identifiers[x]), with_doc = with_doc)
return media
except:
pass
def run_with_status(self, db, status = [], with_doc = True):
status = list(status if isinstance(status, (list, tuple)) else [status])
for s in status:
for ms in db.get_many('media_status', s, with_doc = with_doc):
yield ms['doc'] if with_doc else ms
class MediaStatusIndex(TreeBasedIndex): class MediaStatusIndex(TreeBasedIndex):
_version = 1 _version = 1

63
couchpotato/core/media/_base/media/main.py

@ -74,6 +74,8 @@ class MediaPlugin(MediaBase):
addEvent('app.load', self.addSingleDeleteView, priority = 100) addEvent('app.load', self.addSingleDeleteView, priority = 100)
addEvent('media.get', self.get) addEvent('media.get', self.get)
addEvent('media.with_status', self.withStatus)
addEvent('media.with_identifiers', self.withIdentifiers)
addEvent('media.list', self.list) addEvent('media.list', self.list)
addEvent('media.delete', self.delete) addEvent('media.delete', self.delete)
addEvent('media.restatus', self.restatus) addEvent('media.restatus', self.restatus)
@ -99,13 +101,10 @@ class MediaPlugin(MediaBase):
try: try:
media = get_db().get('id', media_id) media = get_db().get('id', media_id)
default_title = getTitle(media)
event = '%s.update_info' % media.get('type') event = '%s.update_info' % media.get('type')
def handler(): def handler():
fireEvent(event, identifier = media.get('identifier'), default_title = default_title, on_complete = self.createOnComplete(media_id)) fireEvent(event, media_id = media_id, on_complete = self.createOnComplete(media_id))
if handler: if handler:
return handler return handler
@ -124,16 +123,21 @@ class MediaPlugin(MediaBase):
imdb_id = getImdb(str(media_id)) imdb_id = getImdb(str(media_id))
media = None
if imdb_id: if imdb_id:
m = db.get('media', 'imdb-%s' % imdb_id, with_doc = True)['doc'] media = db.get('media', 'imdb-%s' % imdb_id, with_doc = True)['doc']
else: else:
m = db.get('id', media_id) media = db.get('id', media_id)
if media:
results = None # Attach category
if m: if media.get('category_id'):
results = db.run('media', 'to_dict', m['_id']) media['category'] = db.get('id', media.get('category_id'))
return results media['releases'] = list(fireEvent('release.for_media', media['_id'], single = True))
return media
def getView(self, id = None, **kwargs): def getView(self, id = None, **kwargs):
@ -144,6 +148,29 @@ class MediaPlugin(MediaBase):
'media': media, 'media': media,
} }
def withStatus(self, status, with_doc = True):
db = get_db()
status = list(status if isinstance(status, (list, tuple)) else [status])
for s in status:
for ms in db.get_many('media_status', s, with_doc = with_doc):
yield ms['doc'] if with_doc else ms
def withIdentifiers(self, identifiers, with_doc = False):
db = get_db()
for x in identifiers:
try:
media = db.get('media', '%s-%s' % (x, identifiers[x]), with_doc = with_doc)
return media
except:
pass
log.error('No media found with identifiers: %s', identifiers)
def list(self, types = None, status = None, release_status = None, status_or = False, limit_offset = None, starts_with = None, search = None): def list(self, types = None, status = None, release_status = None, status_or = False, limit_offset = None, starts_with = None, search = None):
db = get_db() db = get_db()
@ -170,13 +197,13 @@ class MediaPlugin(MediaBase):
# Filter on movie status # Filter on movie status
if status and len(status) > 0: if status and len(status) > 0:
filter_by['media_status'] = set() filter_by['media_status'] = set()
for media_status in db.run('media', 'with_status', status, with_doc = False): for media_status in fireEvent('media.with_status', status, with_doc = False, single = True):
filter_by['media_status'].add(media_status.get('_id')) filter_by['media_status'].add(media_status.get('_id'))
# Filter on release status # Filter on release status
if release_status and len(release_status) > 0: if release_status and len(release_status) > 0:
filter_by['release_status'] = set() filter_by['release_status'] = set()
for release_status in db.run('release', 'with_status', release_status, with_doc = False): for release_status in fireEvent('release.with_status', release_status, with_doc = False, single = True):
filter_by['release_status'].add(release_status.get('media_id')) filter_by['release_status'].add(release_status.get('media_id'))
# Add search filters # Add search filters
@ -220,9 +247,7 @@ class MediaPlugin(MediaBase):
offset -= 1 offset -= 1
continue continue
media = db.run('media', 'to_dict', media_id) media = fireEvent('media.get', media_id, single = True)
media['releases'] = list(db.run('release', 'for_media', media_id))
# Merge releases with movie dict # Merge releases with movie dict
medias.append(media) medias.append(media)
@ -285,13 +310,13 @@ class MediaPlugin(MediaBase):
# Filter on movie status # Filter on movie status
if status and len(status) > 0: if status and len(status) > 0:
filter_by['media_status'] = set() filter_by['media_status'] = set()
for media_status in db.run('media', 'with_status', status, with_doc = False): for media_status in fireEvent('media.with_status', status, with_doc = False, single = True):
filter_by['media_status'].add(media_status.get('_id')) filter_by['media_status'].add(media_status.get('_id'))
# Filter on release status # Filter on release status
if release_status and len(release_status) > 0: if release_status and len(release_status) > 0:
filter_by['release_status'] = set() filter_by['release_status'] = set()
for release_status in db.run('release', 'with_status', release_status, with_doc = False): for release_status in fireEvent('release.with_status', release_status, with_doc = False, single = True):
filter_by['release_status'].add(release_status.get('media_id')) filter_by['release_status'].add(release_status.get('media_id'))
# Filter by combining ids # Filter by combining ids
@ -341,7 +366,7 @@ class MediaPlugin(MediaBase):
deleted = True deleted = True
else: else:
media_releases = list(db.run('release', 'for_media', media['_id'])) media_releases = list(fireEvent('release.for_media', media['_id'], single = True))
total_releases = len(media_releases) total_releases = len(media_releases)
total_deleted = 0 total_deleted = 0
@ -407,7 +432,7 @@ class MediaPlugin(MediaBase):
move_to_wanted = True move_to_wanted = True
profile = db.get('id', m['profile_id']) profile = db.get('id', m['profile_id'])
media_releases = list(db.run('release', 'for_media', m['_id'])) media_releases = list(fireEvent('release.for_media', m['_id'], single = True))
for q_identifier in profile['qualities']: for q_identifier in profile['qualities']:
index = profile['qualities'].index(q_identifier) index = profile['qualities'].index(q_identifier)

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

@ -2,7 +2,7 @@ import re
import traceback import traceback
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from couchpotato.core.helpers.variable import tryInt 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 TorrentProvider from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
@ -22,7 +22,7 @@ class Base(TorrentProvider):
def _search(self, movie, quality, results): def _search(self, movie, quality, results):
data = self.getHTMLData(self.urls['search'] % (self.conf('passkey'), movie['identifier'], self.conf('only_internal'))) data = self.getHTMLData(self.urls['search'] % (self.conf('passkey'), getIdentifier(movie), self.conf('only_internal')))
if data: if data:
try: try:

6
couchpotato/core/media/_base/providers/torrent/hdbits.py

@ -2,7 +2,7 @@ import re
import json import json
import traceback import traceback
from couchpotato.core.helpers.variable import tryInt 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 TorrentProvider from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
@ -44,7 +44,7 @@ class Base(TorrentProvider):
def _search(self, movie, quality, results): def _search(self, movie, quality, results):
match = re.match(r'tt(\d{7})', movie['identifier']) match = re.match(r'tt(\d{7})', getIdentifier(movie))
data = self._post_query(imdb = {'id': match.group(1)}) data = self._post_query(imdb = {'id': match.group(1)})
@ -56,7 +56,7 @@ class Base(TorrentProvider):
'name': result['name'], 'name': result['name'],
'url': self.urls['download'] % (result['id'], self.conf('passkey')), 'url': self.urls['download'] % (result['id'], self.conf('passkey')),
'detail_url': self.urls['detail'] % result['id'], 'detail_url': self.urls['detail'] % result['id'],
'size': self.parseSize(result['size']), 'size': tryInt(result['size'])/1024/1024,
'seeders': tryInt(result['seeders']), 'seeders': tryInt(result['seeders']),
'leechers': tryInt(result['leechers']) 'leechers': tryInt(result['leechers'])
}) })

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

@ -2,7 +2,7 @@ import re
import traceback import traceback
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from couchpotato.core.helpers.variable import tryInt 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 TorrentMagnetProvider
@ -38,7 +38,7 @@ class Base(TorrentMagnetProvider):
def _search(self, media, quality, results): def _search(self, media, quality, results):
data = self.getHTMLData(self.urls['search'] % (self.getDomain(), 'm', media['identifier'].replace('tt', ''))) data = self.getHTMLData(self.urls['search'] % (self.getDomain(), 'm', getIdentifier(media).replace('tt', '')))
if data: if data:

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

@ -5,7 +5,7 @@ import time
import traceback import traceback
from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import getTitle, tryInt, mergeDicts from couchpotato.core.helpers.variable import getTitle, tryInt, mergeDicts, getIdentifier
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
from dateutil.parser import parse from dateutil.parser import parse
@ -36,7 +36,7 @@ class Base(TorrentProvider):
params = mergeDicts(self.quality_search_params[quality_id].copy(), { params = mergeDicts(self.quality_search_params[quality_id].copy(), {
'order_by': 'relevance', 'order_by': 'relevance',
'order_way': 'descending', 'order_way': 'descending',
'searchstr': media['identifier'] 'searchstr': getIdentifier(media)
}) })
url = '%s?json=noredirect&%s' % (self.urls['torrent'], tryUrlencode(params)) url = '%s?json=noredirect&%s' % (self.urls['torrent'], tryUrlencode(params))

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

@ -29,9 +29,9 @@ class Base(TorrentMagnetProvider):
'http://pirateproxy.ca', 'http://pirateproxy.ca',
'http://tpb.al', 'http://tpb.al',
'http://www.tpb.gr', 'http://www.tpb.gr',
'http://nl.tpb.li', 'http://bayproxy.me',
'http://proxybay.eu', 'http://proxybay.eu',
'https://www.getpirate.com', 'http://www.getpirate.com',
'http://piratebay.io', 'http://piratebay.io',
] ]

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

@ -1,6 +1,6 @@
import traceback import traceback
from couchpotato.core.helpers.variable import tryInt 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 TorrentProvider from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
@ -35,7 +35,7 @@ class Base(TorrentProvider):
def _search(self, movie, quality, results): def _search(self, movie, quality, results):
search_url = self.urls['search'] % (self.getDomain(), movie['identifier'], quality['identifier']) search_url = self.urls['search'] % (self.getDomain(), getIdentifier(movie), quality['identifier'])
data = self.getJsonData(search_url) data = self.getJsonData(search_url)

39
couchpotato/core/media/movie/_base/main.py

@ -6,7 +6,7 @@ from couchpotato import get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, fireEventAsync, addEvent from couchpotato.core.event import fireEvent, fireEventAsync, addEvent
from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import splitString, getTitle, getImdb from couchpotato.core.helpers.variable import splitString, getTitle, getImdb, getIdentifier
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.media.movie import MovieTypeBase from couchpotato.core.media.movie import MovieTypeBase
import six import six
@ -138,7 +138,7 @@ class MovieBase(MovieTypeBase):
elif force_readd: elif force_readd:
# Clean snatched history # Clean snatched history
for release in db.run('release', 'for_media', m['_id']): for release in fireEvent('release.for_media', m['_id'], single = True):
if release.get('status') in ['downloaded', 'snatched', 'done']: if release.get('status') in ['downloaded', 'snatched', 'done']:
if params.get('ignore_previous', False): if params.get('ignore_previous', False):
release['status'] = 'ignored' release['status'] = 'ignored'
@ -164,11 +164,11 @@ class MovieBase(MovieTypeBase):
fireEventAsync('movie.update_info', m['_id'], default_title = params.get('title'), on_complete = onComplete) fireEventAsync('movie.update_info', m['_id'], default_title = params.get('title'), on_complete = onComplete)
# Remove releases # Remove releases
for rel in db.run('release', 'for_media', m['_id']): for rel in fireEvent('release.for_media', m['_id'], single = True):
if rel['status'] is 'available': if rel['status'] is 'available':
db.delete(rel) db.delete(rel)
movie_dict = db.run('media', 'to_dict', m['_id']) movie_dict = fireEvent('media.get', m['_id'], single = True)
if do_search and search_after: if do_search and search_after:
onComplete = self.createOnComplete(m['_id']) onComplete = self.createOnComplete(m['_id'])
@ -215,7 +215,7 @@ class MovieBase(MovieTypeBase):
m['category_id'] = cat_id if len(cat_id) > 0 else None m['category_id'] = cat_id if len(cat_id) > 0 else None
# Remove releases # Remove releases
for rel in db.run('release', 'for_media', m['_id']): for rel in fireEvent('release.for_media', m['_id'], single = True):
if rel['status'] is 'available': if rel['status'] is 'available':
db.delete(rel) db.delete(rel)
@ -229,7 +229,7 @@ class MovieBase(MovieTypeBase):
m = db.get('id', media_id) m = db.get('id', media_id)
movie_dict = db.run('media', 'to_dict', m['_id']) movie_dict = fireEvent('media.get', m['_id'], single = True)
fireEventAsync('movie.searcher.single', movie_dict, on_complete = self.createNotifyFront(media_id)) fireEventAsync('movie.searcher.single', movie_dict, on_complete = self.createNotifyFront(media_id))
except: except:
@ -266,7 +266,7 @@ class MovieBase(MovieTypeBase):
else: else:
media = db.get('media', 'imdb-%s' % identifier, with_doc = True)['doc'] media = db.get('media', 'imdb-%s' % identifier, with_doc = True)['doc']
info = fireEvent('movie.info', merge = True, extended = extended, identifier = media.get('identifier')) info = fireEvent('movie.info', merge = True, extended = extended, identifier = getIdentifier(media))
# Don't need those here # Don't need those here
try: del info['in_wanted'] try: del info['in_wanted']
@ -275,7 +275,7 @@ class MovieBase(MovieTypeBase):
except: pass except: pass
if not info or len(info) == 0: if not info or len(info) == 0:
log.error('Could not update, no movie info to work with: %s', media.get('identifier')) log.error('Could not update, no movie info to work with: %s', identifier)
return False return False
# Update basic info # Update basic info
@ -285,19 +285,20 @@ class MovieBase(MovieTypeBase):
log.debug('Adding titles: %s', titles) log.debug('Adding titles: %s', titles)
# Define default title # Define default title
def_title = None
if default_title: if default_title:
counter = 0 def_title = None
for title in titles: if default_title:
if title.lower() == toUnicode(default_title.lower()) or (toUnicode(default_title) == six.u('') and toUnicode(titles[0]) == title): counter = 0
def_title = toUnicode(title) for title in titles:
break if title.lower() == toUnicode(default_title.lower()) or (toUnicode(default_title) == six.u('') and toUnicode(titles[0]) == title):
counter += 1 def_title = toUnicode(title)
break
counter += 1
if not def_title: if not def_title:
def_title = toUnicode(titles[0]) def_title = toUnicode(titles[0])
media['title'] = def_title media['title'] = def_title
# Files # Files
images = info.get('images', []) images = info.get('images', [])
@ -357,7 +358,7 @@ class MovieBase(MovieTypeBase):
dates = media.get('info').get('release_date') dates = media.get('info').get('release_date')
if dates and (dates.get('expires', 0) < time.time() or dates.get('expires', 0) > time.time() + (604800 * 4)) or not dates: if dates and (dates.get('expires', 0) < time.time() or dates.get('expires', 0) > time.time() + (604800 * 4)) or not dates:
dates = fireEvent('movie.info.release_date', identifier = media['identifier'], merge = True) dates = fireEvent('movie.info.release_date', identifier = getIdentifier(media), merge = True)
media['info'].update({'release_date': dates}) media['info'].update({'release_date': dates})
db.update(media) db.update(media)

2
couchpotato/core/media/movie/_base/static/movie.actions.js

@ -428,7 +428,7 @@ MA.Release = new Class({
Api.request('movie.searcher.try_next', { Api.request('movie.searcher.try_next', {
'data': { 'data': {
'id': self.movie.get('_id') 'media_id': self.movie.get('_id')
} }
}); });

2
couchpotato/core/media/movie/providers/automation/itunes.py

@ -26,7 +26,7 @@ class ITunes(Automation, RSS):
urls = splitString(self.conf('automation_urls')) urls = splitString(self.conf('automation_urls'))
namespace = 'http://www.w3.org/2005/Atom' namespace = 'http://www.w3.org/2005/Atom'
namespace_im = 'https://rss.itunes.apple.com' namespace_im = 'http://itunes.apple.com/rss'
index = -1 index = -1
for url in urls: for url in urls:

4
couchpotato/core/media/movie/providers/info/_modifier.py

@ -3,7 +3,7 @@ import traceback
from CodernityDB.database import RecordNotFound from CodernityDB.database import RecordNotFound
from couchpotato import get_db from couchpotato import get_db
from couchpotato.core.event import addEvent from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.variable import mergeDicts, randomString from couchpotato.core.helpers.variable import mergeDicts, randomString
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
@ -104,7 +104,7 @@ class MovieResultModifier(Plugin):
if media.get('status') == 'active': if media.get('status') == 'active':
temp['in_wanted'] = media temp['in_wanted'] = media
for release in db.run('release', 'for_media', media.get('_id')): for release in fireEvent('release.for_media', media['_id'], single = True):
if release.get('status') == 'done': if release.get('status') == 'done':
if not temp['in_library']: if not temp['in_library']:
temp['in_library'] = media temp['in_library'] = media

3
couchpotato/core/media/movie/providers/nzb/binsearch.py

@ -1,4 +1,5 @@
from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import getIdentifier
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.nzb.binsearch import Base from couchpotato.core.media._base.providers.nzb.binsearch import Base
from couchpotato.core.media.movie.providers.base import MovieProvider from couchpotato.core.media.movie.providers.base import MovieProvider
@ -13,7 +14,7 @@ class BinSearch(MovieProvider, Base):
def buildUrl(self, media, quality): def buildUrl(self, media, quality):
query = tryUrlencode({ query = tryUrlencode({
'q': media['identifier'], 'q': getIdentifier(media),
'm': 'n', 'm': 'n',
'max': 400, 'max': 400,
'adv_age': Env.setting('retention', 'nzb'), 'adv_age': Env.setting('retention', 'nzb'),

3
couchpotato/core/media/movie/providers/nzb/newznab.py

@ -1,4 +1,5 @@
from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import getIdentifier
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.nzb.newznab import Base from couchpotato.core.media._base.providers.nzb.newznab import Base
from couchpotato.core.media.movie.providers.base import MovieProvider from couchpotato.core.media.movie.providers.base import MovieProvider
@ -13,7 +14,7 @@ class Newznab(MovieProvider, Base):
def buildUrl(self, media, api_key): def buildUrl(self, media, api_key):
query = tryUrlencode({ query = tryUrlencode({
't': 'movie', 't': 'movie',
'imdbid': media['identifier'].replace('tt', ''), 'imdbid': getIdentifier(media).replace('tt', ''),
'apikey': api_key, 'apikey': api_key,
'extended': 1 'extended': 1
}) })

2
couchpotato/core/media/movie/providers/nzb/nzbindex.py

@ -14,7 +14,7 @@ class NzbIndex(MovieProvider, Base):
def buildUrl(self, media, quality): def buildUrl(self, media, quality):
title = fireEvent('library.query', media, include_year = False, single = True) title = fireEvent('library.query', media, include_year = False, single = True)
year = media['year'] year = media['info']['year']
query = tryUrlencode({ query = tryUrlencode({
'q': '"%s %s" | "%s (%s)"' % (title, year, title, year), 'q': '"%s %s" | "%s (%s)"' % (title, year, title, year),

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

@ -21,7 +21,7 @@ class Bitsoup(MovieProvider, Base):
query = tryUrlencode({ query = tryUrlencode({
'search': '"%s" %s' % ( 'search': '"%s" %s' % (
fireEvent('library.query', media, include_year = False, single = True), fireEvent('library.query', media, include_year = False, single = True),
media['year'] media['info']['year']
), ),
'cat': self.getCatId(quality['identifier'])[0], 'cat': self.getCatId(quality['identifier'])[0],
}) })

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

@ -17,6 +17,6 @@ class IPTorrents(MovieProvider, Base):
] ]
def buildUrl(self, title, media, quality): def buildUrl(self, title, media, quality):
query = '%s %s' % (title.replace(':', ''), media['year']) query = '%s %s' % (title.replace(':', ''), media['info']['year'])
return self._buildUrl(query, quality['identifier']) return self._buildUrl(query, quality['identifier'])

3
couchpotato/core/media/movie/providers/torrent/torrentpotato.py

@ -1,4 +1,5 @@
from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import getIdentifier
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.torrent.torrentpotato import Base from couchpotato.core.media._base.providers.torrent.torrentpotato import Base
from couchpotato.core.media.movie.providers.base import MovieProvider from couchpotato.core.media.movie.providers.base import MovieProvider
@ -14,6 +15,6 @@ class TorrentPotato(MovieProvider, Base):
arguments = tryUrlencode({ arguments = tryUrlencode({
'user': host['name'], 'user': host['name'],
'passkey': host['pass_key'], 'passkey': host['pass_key'],
'imdbid': media['identifier'] 'imdbid': getIdentifier(media),
}) })
return '%s?%s' % (host['host'], arguments) return '%s?%s' % (host['host'], arguments)

33
couchpotato/core/media/movie/searcher.py

@ -8,7 +8,7 @@ from couchpotato import get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent, fireEventAsync from couchpotato.core.event import addEvent, fireEvent, fireEventAsync
from couchpotato.core.helpers.encoding import simplifyString from couchpotato.core.helpers.encoding import simplifyString
from couchpotato.core.helpers.variable import getTitle, possibleTitles, getImdb from couchpotato.core.helpers.variable import getTitle, possibleTitles, getImdb, getIdentifier, tryInt
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.searcher.base import SearcherBase from couchpotato.core.media._base.searcher.base import SearcherBase
from couchpotato.core.media.movie import MovieTypeBase from couchpotato.core.media.movie import MovieTypeBase
@ -38,7 +38,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
addApiView('movie.searcher.try_next', self.tryNextReleaseView, docs = { addApiView('movie.searcher.try_next', self.tryNextReleaseView, docs = {
'desc': 'Marks the snatched results as ignored and try the next best release', 'desc': 'Marks the snatched results as ignored and try the next best release',
'params': { 'params': {
'id': {'desc': 'The id of the movie'}, 'media_id': {'desc': 'The id of the media'},
}, },
}) })
@ -74,9 +74,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
self.in_progress = True self.in_progress = True
fireEvent('notify.frontend', type = 'movie.searcher.started', data = True, message = 'Full search started') fireEvent('notify.frontend', type = 'movie.searcher.started', data = True, message = 'Full search started')
db = get_db() medias = [x['_id'] for x in fireEvent('media.with_status', 'active', with_doc = False, single = True)]
medias = [x['_id'] for x in db.run('media', 'with_status', 'active', with_doc = False)]
random.shuffle(medias) random.shuffle(medias)
total = len(medias) total = len(medias)
@ -90,15 +88,15 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
for media_id in medias: for media_id in medias:
media = db.run('media', 'to_dict', media_id) media = fireEvent('media.get', media_id, single = True)
try: try:
self.single(media, search_protocols) self.single(media, search_protocols)
except IndexError: except IndexError:
log.error('Forcing library update for %s, if you see this often, please report: %s', (media['identifier'], traceback.format_exc())) log.error('Forcing library update for %s, if you see this often, please report: %s', (getIdentifier(media), traceback.format_exc()))
fireEvent('movie.update_info', media_id) fireEvent('movie.update_info', media_id)
except: except:
log.error('Search failed for %s: %s', (media['identifier'], traceback.format_exc())) log.error('Search failed for %s: %s', (getIdentifier(media), traceback.format_exc()))
self.in_progress['to_go'] -= 1 self.in_progress['to_go'] -= 1
@ -142,7 +140,6 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
profile = db.get('id', movie['profile_id']) profile = db.get('id', movie['profile_id'])
quality_order = fireEvent('quality.order', single = True) quality_order = fireEvent('quality.order', single = True)
media_releases = db.run('release', 'for_media', movie['_id'])
ret = False ret = False
@ -161,7 +158,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
has_better_quality = 0 has_better_quality = 0
# See if better quality is available # See if better quality is available
for release in media_releases: for release in movie.get('releases', []):
if quality_order.index(release['quality']) <= quality_order.index(q_identifier) and release['status'] not in ['available', 'ignored', 'failed']: if quality_order.index(release['quality']) <= quality_order.index(q_identifier) and release['status'] not in ['available', 'ignored', 'failed']:
has_better_quality += 1 has_better_quality += 1
@ -187,7 +184,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
ret = True ret = True
# Remove releases that aren't found anymore # Remove releases that aren't found anymore
for release in db.run('release', 'for_media', movie['_id']): for release in movie.get('releases', []):
if release.get('status') == 'available' and release.get('identifier') not in found_releases: if release.get('status') == 'available' and release.get('identifier') not in found_releases:
fireEvent('release.delete', release.get('_id'), single = True) fireEvent('release.delete', release.get('_id'), single = True)
@ -233,12 +230,12 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
# File to small # File to small
if nzb['size'] and preferred_quality['size_min'] > nzb['size']: if nzb['size'] and tryInt(preferred_quality['size_min']) > tryInt(nzb['size']):
log.info2('Wrong: "%s" is too small to be %s. %sMB instead of the minimal of %sMB.', (nzb['name'], preferred_quality['label'], nzb['size'], preferred_quality['size_min'])) log.info2('Wrong: "%s" is too small to be %s. %sMB instead of the minimal of %sMB.', (nzb['name'], preferred_quality['label'], nzb['size'], preferred_quality['size_min']))
return False return False
# File to large # File to large
if nzb['size'] and preferred_quality.get('size_max') < nzb['size']: if nzb['size'] and tryInt(preferred_quality['size_max']) < tryInt(nzb['size']):
log.info2('Wrong: "%s" is too large to be %s. %sMB instead of the maximum of %sMB.', (nzb['name'], preferred_quality['label'], nzb['size'], preferred_quality['size_max'])) log.info2('Wrong: "%s" is too large to be %s. %sMB instead of the maximum of %sMB.', (nzb['name'], preferred_quality['label'], nzb['size'], preferred_quality['size_max']))
return False return False
@ -257,7 +254,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
return True return True
# Check if nzb contains imdb link # Check if nzb contains imdb link
if getImdb(nzb.get('description', '')) == media['identifier']: if getImdb(nzb.get('description', '')) == getIdentifier(media):
return True return True
for raw_title in media['info']['titles']: for raw_title in media['info']['titles']:
@ -317,9 +314,9 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
return False return False
def tryNextReleaseView(self, id = None, **kwargs): def tryNextReleaseView(self, media_id = None, **kwargs):
trynext = self.tryNextRelease(id, manual = True) trynext = self.tryNextRelease(media_id, manual = True)
return { return {
'success': trynext 'success': trynext
@ -329,13 +326,13 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
try: try:
db = get_db() db = get_db()
rels = db.run('media', 'with_status', media_id, status = ['snatched', 'done']) rels = fireEvent('media.with_status', ['snatched', 'done'], single = True)
for rel in rels: for rel in rels:
rel['status'] = 'ignored' rel['status'] = 'ignored'
db.update(rel) db.update(rel)
movie_dict = db.run('media', 'to_dict', media_id) movie_dict = fireEvent('media.get', media_id, single = True)
log.info('Trying next release for: %s', getTitle(movie_dict)) log.info('Trying next release for: %s', getTitle(movie_dict))
self.single(movie_dict, manual = manual) self.single(movie_dict, manual = manual)

11
couchpotato/core/media/movie/suggestion/main.py

@ -1,7 +1,7 @@
from couchpotato import get_db from couchpotato import get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent from couchpotato.core.event import fireEvent
from couchpotato.core.helpers.variable import splitString, removeDuplicate from couchpotato.core.helpers.variable import splitString, removeDuplicate, getIdentifier
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
from couchpotato.environment import Env from couchpotato.environment import Env
@ -28,9 +28,8 @@ class Suggestion(Plugin):
else: else:
if not movies or len(movies) == 0: if not movies or len(movies) == 0:
db = get_db() active_movies = fireEvent('media.with_status', ['active', 'done'], single = True)
active_movies = db.run('media', 'with_status', ['active', 'done']) movies = [getIdentifier(x) for x in active_movies]
movies = [x['identifier'] for x in active_movies]
if not ignored or len(ignored) == 0: if not ignored or len(ignored) == 0:
ignored = splitString(Env.prop('suggest_ignore', default = '')) ignored = splitString(Env.prop('suggest_ignore', default = ''))
@ -86,8 +85,8 @@ class Suggestion(Plugin):
# Get new results and add them # Get new results and add them
if len(new_suggestions) - 1 < limit: if len(new_suggestions) - 1 < limit:
db = get_db() db = get_db()
active_movies = db.run('media', 'with_status', ['active', 'done']) active_movies = fireEvent('media.with_status', ['active', 'done'], single = True)
movies = [x['identifier'] for x in active_movies] movies = [getIdentifier(x) for x in active_movies]
movies.extend(seen) movies.extend(seen)
ignored.extend([x.get('imdb') for x in cached_suggestion]) ignored.extend([x.get('imdb') for x in cached_suggestion])

2
couchpotato/core/notifications/boxcar.py

@ -7,6 +7,8 @@ from couchpotato.core.notifications.base import Notification
log = CPLog(__name__) log = CPLog(__name__)
autoload = 'Boxcar'
class Boxcar(Notification): class Boxcar(Notification):

2
couchpotato/core/notifications/boxcar2.py

@ -25,7 +25,7 @@ class Boxcar2(Notification):
data = { data = {
'user_credentials': self.conf('token'), 'user_credentials': self.conf('token'),
'notification[title]': toUnicode(message), 'notification[title]': toUnicode('%s - %s' % (self.default_title, message)),
'notification[long_message]': toUnicode(long_message), 'notification[long_message]': toUnicode(long_message),
} }

2
couchpotato/core/notifications/email_.py

@ -12,6 +12,8 @@ from couchpotato.environment import Env
log = CPLog(__name__) log = CPLog(__name__)
autoload = 'Email'
class Email(Notification): class Email(Notification):

2
couchpotato/core/notifications/growl.py

@ -9,6 +9,8 @@ from gntp import notifier
log = CPLog(__name__) log = CPLog(__name__)
autoload = 'Growl'
class Growl(Notification): class Growl(Notification):

2
couchpotato/core/notifications/nmj.py

@ -15,6 +15,8 @@ except ImportError:
log = CPLog(__name__) log = CPLog(__name__)
autoload = 'NMJ'
class NMJ(Notification): class NMJ(Notification):

2
couchpotato/core/notifications/notifymyandroid.py

@ -6,6 +6,8 @@ import six
log = CPLog(__name__) log = CPLog(__name__)
autoload = 'NotifyMyAndroid'
class NotifyMyAndroid(Notification): class NotifyMyAndroid(Notification):

2
couchpotato/core/notifications/notifymywp.py

@ -6,6 +6,8 @@ import six
log = CPLog(__name__) log = CPLog(__name__)
autoload = 'NotifyMyWP'
class NotifyMyWP(Notification): class NotifyMyWP(Notification):

2
couchpotato/core/notifications/prowl.py

@ -7,6 +7,8 @@ from couchpotato.core.notifications.base import Notification
log = CPLog(__name__) log = CPLog(__name__)
autoload = 'Prowl'
class Prowl(Notification): class Prowl(Notification):

2
couchpotato/core/notifications/pushalot.py

@ -7,6 +7,8 @@ from couchpotato.core.notifications.base import Notification
log = CPLog(__name__) log = CPLog(__name__)
autoload = 'Pushalot'
class Pushalot(Notification): class Pushalot(Notification):

2
couchpotato/core/notifications/pushbullet.py

@ -9,6 +9,8 @@ from couchpotato.core.notifications.base import Notification
log = CPLog(__name__) log = CPLog(__name__)
autoload = 'Pushbullet'
class Pushbullet(Notification): class Pushbullet(Notification):

10
couchpotato/core/plugins/base.py

@ -7,11 +7,10 @@ import time
import traceback import traceback
import urllib2 import urllib2
from couchpotato import get_db
from couchpotato.core.event import fireEvent, addEvent from couchpotato.core.event import fireEvent, addEvent
from couchpotato.core.helpers.encoding import ss, toSafeString, \ from couchpotato.core.helpers.encoding import ss, toSafeString, \
toUnicode, sp toUnicode, sp
from couchpotato.core.helpers.variable import getExt, md5, isLocalIP, scanForPassword, tryInt from couchpotato.core.helpers.variable import getExt, md5, isLocalIP, scanForPassword, tryInt, getIdentifier
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.environment import Env from couchpotato.environment import Env
import requests import requests
@ -327,19 +326,22 @@ class Plugin(object):
if name_password: if name_password:
release_name, password = name_password release_name, password = name_password
tag += '{{%s}}' % password tag += '{{%s}}' % password
elif data.get('password'):
tag += '{{%s}}' % data.get('password')
max_length = 127 - len(tag) # Some filesystems don't support 128+ long filenames max_length = 127 - len(tag) # Some filesystems don't support 128+ long filenames
return '%s%s' % (toSafeString(toUnicode(release_name)[:max_length]), tag) return '%s%s' % (toSafeString(toUnicode(release_name)[:max_length]), tag)
def createFileName(self, data, filedata, media): def createFileName(self, data, filedata, media):
name = sp(os.path.join(self.createNzbName(data, media))) name = self.createNzbName(data, media)
if data.get('protocol') == 'nzb' and 'DOCTYPE nzb' not in filedata and '</nzb>' not in filedata: if data.get('protocol') == 'nzb' and 'DOCTYPE nzb' not in filedata and '</nzb>' not in filedata:
return '%s.%s' % (name, 'rar') return '%s.%s' % (name, 'rar')
return '%s.%s' % (name, data.get('protocol')) return '%s.%s' % (name, data.get('protocol'))
def cpTag(self, media): def cpTag(self, media):
if Env.setting('enabled', 'renamer'): if Env.setting('enabled', 'renamer'):
return '.cp(' + media.get('identifier') + ')' if media.get('identifier') else '' identifier = getIdentifier(media)
return '.cp(' + identifier + ')' if identifier else ''
return '' return ''

2
couchpotato/core/plugins/dashboard.py

@ -45,7 +45,7 @@ class Dashboard(Plugin):
limit = tryInt(splt[0]) limit = tryInt(splt[0])
# Get all active medias # Get all active medias
active_ids = [x['_id'] for x in db.run('media', 'with_status', 'active', with_doc = False)] active_ids = [x['_id'] for x in fireEvent('media.with_status', 'active', with_doc = False, single = True)]
medias = [] medias = []
now_year = date.today().year now_year = date.today().year

5
couchpotato/core/plugins/file.py

@ -4,7 +4,7 @@ import traceback
from couchpotato import get_db from couchpotato import get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import addEvent from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import md5, getExt from couchpotato.core.helpers.variable import md5, getExt
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
@ -32,12 +32,11 @@ class FileManager(Plugin):
'return': {'type': 'file'} 'return': {'type': 'file'}
}) })
addEvent('app.load', self.cleanup) fireEvent('schedule.interval', 'file.cleanup', self.cleanup, hours = 24)
def cleanup(self): def cleanup(self):
# Wait a bit after starting before cleanup # Wait a bit after starting before cleanup
time.sleep(2)
log.debug('Cleaning up unused files') log.debug('Cleaning up unused files')
try: try:

7
couchpotato/core/plugins/manage.py

@ -8,7 +8,7 @@ from couchpotato import get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, addEvent, fireEventAsync from couchpotato.core.event import fireEvent, addEvent, fireEventAsync
from couchpotato.core.helpers.encoding import sp from couchpotato.core.helpers.encoding import sp
from couchpotato.core.helpers.variable import splitString, getTitle, tryInt from couchpotato.core.helpers.variable import splitString, getTitle, tryInt, getIdentifier
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
from couchpotato.environment import Env from couchpotato.environment import Env
@ -123,12 +123,11 @@ class Manage(Plugin):
total_movies, done_movies = fireEvent('media.list', types = 'movie', status = 'done', single = True) total_movies, done_movies = fireEvent('media.list', types = 'movie', status = 'done', single = True)
for done_movie in done_movies: for done_movie in done_movies:
if done_movie['identifier'] not in added_identifiers: if getIdentifier(done_movie) not in added_identifiers:
fireEvent('media.delete', media_id = done_movie['_id'], delete_from = 'all') fireEvent('media.delete', media_id = done_movie['_id'], delete_from = 'all')
else: else:
db = get_db() releases = done_movie.get('releases', [])
releases = list(db.run('release', 'for_media', done_movie.get('_id')))
for release in releases: for release in releases:
if release.get('files'): if release.get('files'):

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

@ -2,7 +2,7 @@ import traceback
from couchpotato import get_db, tryInt from couchpotato import get_db, tryInt
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import addEvent from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
@ -41,7 +41,7 @@ class ProfilePlugin(Plugin):
# Get all active movies without profile # Get all active movies without profile
try: try:
db = get_db() db = get_db()
medias = db.run('media', 'with_status', ['active']) medias = fireEvent('media.with_status', 'active', single = True)
profile_ids = [x.get('_id') for x in self.all()] profile_ids = [x.get('_id') for x in self.all()]
default_id = profile_ids[0] default_id = profile_ids[0]

8
couchpotato/core/plugins/quality/main.py

@ -5,7 +5,7 @@ from couchpotato import get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import addEvent from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import toUnicode, ss from couchpotato.core.helpers.encoding import toUnicode, ss
from couchpotato.core.helpers.variable import mergeDicts, getExt from couchpotato.core.helpers.variable import mergeDicts, getExt, tryInt
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
from couchpotato.core.plugins.quality.index import QualityIndex from couchpotato.core.plugins.quality.index import QualityIndex
@ -121,7 +121,7 @@ class QualityPlugin(Plugin):
quality = db.get('quality', kwargs.get('identifier'), with_doc = True) quality = db.get('quality', kwargs.get('identifier'), with_doc = True)
if quality: if quality:
quality['doc'][kwargs.get('value_type')] = kwargs.get('value') quality['doc'][kwargs.get('value_type')] = tryInt(kwargs.get('value'))
db.update(quality['doc']) db.update(quality['doc'])
self.cached_qualities = None self.cached_qualities = None
@ -148,8 +148,8 @@ class QualityPlugin(Plugin):
'_t': 'quality', '_t': 'quality',
'order': order, 'order': order,
'identifier': q.get('identifier'), 'identifier': q.get('identifier'),
'size_min': q.get('size')[0], 'size_min': tryInt(q.get('size')[0]),
'size_max': q.get('size')[1] 'size_max': tryInt(q.get('size')[1]),
}) })
log.info('Creating profile: %s', q.get('label')) log.info('Creating profile: %s', q.get('label'))

18
couchpotato/core/plugins/release/index.py

@ -18,18 +18,6 @@ class ReleaseIndex(TreeBasedIndex):
if data.get('_t') == 'release' and data.get('media_id'): if data.get('_t') == 'release' and data.get('media_id'):
return data['media_id'], None return data['media_id'], None
def run_for_media(self, db, media_id):
for release in db.get_many('release', media_id, with_doc = True):
yield release['doc']
def run_with_status(self, db, status = [], with_doc = True):
status = list(status if isinstance(status, (list, tuple)) else [status])
for s in status:
for ms in db.get_many('release_status', s, with_doc = with_doc):
yield ms['doc'] if with_doc else ms
class ReleaseStatusIndex(TreeBasedIndex): class ReleaseStatusIndex(TreeBasedIndex):
_version = 1 _version = 1
@ -62,15 +50,15 @@ class ReleaseIDIndex(HashIndex):
class ReleaseDownloadIndex(HashIndex): class ReleaseDownloadIndex(HashIndex):
_version = 1 _version = 2
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs['key_format'] = '32s' kwargs['key_format'] = '32s'
super(ReleaseDownloadIndex, self).__init__(*args, **kwargs) super(ReleaseDownloadIndex, self).__init__(*args, **kwargs)
def make_key(self, key): def make_key(self, key):
return md5(key).hexdigest() return md5(key.lower()).hexdigest()
def make_key_value(self, data): def make_key_value(self, data):
if data.get('_t') == 'release' and data.get('download_info') and data['download_info']['id'] and data['download_info']['downloader']: if data.get('_t') == 'release' and data.get('download_info') and data['download_info']['id'] and data['download_info']['downloader']:
return md5('%s-%s' % (data['download_info']['downloader'], data['download_info']['id'])).hexdigest(), None return md5(('%s-%s' % (data['download_info']['downloader'], data['download_info']['id'])).lower()).hexdigest(), None

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

@ -53,6 +53,8 @@ class Release(Plugin):
addEvent('release.delete', self.delete) addEvent('release.delete', self.delete)
addEvent('release.clean', self.clean) addEvent('release.clean', self.clean)
addEvent('release.update_status', self.updateStatus) addEvent('release.update_status', self.updateStatus)
addEvent('release.with_status', self.withStatus)
addEvent('release.for_media', self.forMedia)
# Clean releases that didn't have activity in the last week # Clean releases that didn't have activity in the last week
addEvent('app.load', self.cleanDone) addEvent('app.load', self.cleanDone)
@ -67,13 +69,13 @@ class Release(Plugin):
db = get_db() db = get_db()
# get movies last_edit more than a week ago # get movies last_edit more than a week ago
medias = db.run('media', 'with_status', ['done']) medias = fireEvent('media.with_status', 'done', single = True)
for media in medias: for media in medias:
if media.get('last_edit', 0) > (now - week): if media.get('last_edit', 0) > (now - week):
continue continue
for rel in db.run('release', 'for_media', media['_id']): for rel in fireEvent('release.for_media', media['_id'], single = True):
# Remove all available releases # Remove all available releases
if rel['status'] in ['available']: if rel['status'] in ['available']:
@ -422,3 +424,20 @@ class Release(Plugin):
log.error('Failed: %s', traceback.format_exc()) log.error('Failed: %s', traceback.format_exc())
return False return False
def withStatus(self, status, with_doc = True):
db = get_db()
status = list(status if isinstance(status, (list, tuple)) else [status])
for s in status:
for ms in db.get_many('release_status', s, with_doc = with_doc):
yield ms['doc'] if with_doc else ms
def forMedia(self, media_id):
db = get_db()
for release in db.get_many('release', media_id, with_doc = True):
yield release['doc']

47
couchpotato/core/plugins/renamer.py

@ -10,7 +10,7 @@ from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent, fireEventAsync from couchpotato.core.event import addEvent, fireEvent, fireEventAsync
from couchpotato.core.helpers.encoding import toUnicode, ss, sp from couchpotato.core.helpers.encoding import toUnicode, ss, sp
from couchpotato.core.helpers.variable import getExt, mergeDicts, getTitle, \ from couchpotato.core.helpers.variable import getExt, mergeDicts, getTitle, \
getImdb, link, symlink, tryInt, splitString, fnEscape, isSubFolder getImdb, link, symlink, tryInt, splitString, fnEscape, isSubFolder, getIdentifier
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
from couchpotato.environment import Env from couchpotato.environment import Env
@ -79,16 +79,22 @@ class Renamer(Plugin):
downloader = kwargs.get('downloader') downloader = kwargs.get('downloader')
download_id = kwargs.get('download_id') download_id = kwargs.get('download_id')
files = '|'.join([sp(filename) for filename in splitString(kwargs.get('files'), '|')]) files = [sp(filename) for filename in splitString(kwargs.get('files'), '|')]
status = kwargs.get('status', 'completed') status = kwargs.get('status', 'completed')
release_download = None release_download = None
if not base_folder and media_folder: if not base_folder and media_folder:
release_download = {'folder': media_folder} release_download = {'folder': media_folder}
release_download.update({'id': download_id, 'downloader': downloader, 'status': status, 'files': files} if download_id else {})
fire_handle = fireEvent if not async else fireEventAsync if download_id:
release_download.update({
'id': download_id,
'downloader': downloader,
'status': status,
'files': files
})
fire_handle = fireEvent if not async else fireEventAsync
fire_handle('renamer.scan', base_folder = base_folder, release_download = release_download) fire_handle('renamer.scan', base_folder = base_folder, release_download = release_download)
return { return {
@ -142,7 +148,7 @@ class Renamer(Plugin):
log.debug('The provided media folder %s does not exist. Trying to find it in the \'from\' folder.', media_folder) log.debug('The provided media folder %s does not exist. Trying to find it in the \'from\' folder.', media_folder)
# Update to the from folder # Update to the from folder
if len(splitString(release_download.get('files'), '|')) == 1: if len(release_download.get('files'), []) == 1:
new_media_folder = from_folder new_media_folder = from_folder
else: else:
new_media_folder = os.path.join(from_folder, os.path.basename(media_folder)) new_media_folder = os.path.join(from_folder, os.path.basename(media_folder))
@ -152,7 +158,7 @@ class Renamer(Plugin):
return return
# Update the files # Update the files
new_files = [os.path.join(new_media_folder, os.path.relpath(filename, media_folder)) for filename in splitString(release_download.get('files'), '|')] new_files = [os.path.join(new_media_folder, os.path.relpath(filename, media_folder)) for filename in release_download.get('files', [])]
if new_files and not os.path.isfile(new_files[0]): if new_files and not os.path.isfile(new_files[0]):
log.error('The provided media folder %s does not exist and its files could also not be found in the \'from\' folder.', media_folder) log.error('The provided media folder %s does not exist and its files could also not be found in the \'from\' folder.', media_folder)
return return
@ -160,7 +166,7 @@ class Renamer(Plugin):
# Update release_download info to the from folder # Update release_download info to the from folder
log.debug('Release %s found in the \'from\' folder.', media_folder) log.debug('Release %s found in the \'from\' folder.', media_folder)
release_download['folder'] = new_media_folder release_download['folder'] = new_media_folder
release_download['files'] = '|'.join(new_files) release_download['files'] = new_files
media_folder = new_media_folder media_folder = new_media_folder
if media_folder: if media_folder:
@ -182,11 +188,10 @@ class Renamer(Plugin):
log.info('Scanning media folder %s...', media_folder) log.info('Scanning media folder %s...', media_folder)
folder = os.path.dirname(media_folder) folder = os.path.dirname(media_folder)
if release_download.get('files', ''): release_files = release_download.get('files', [])
files = splitString(release_download['files'], '|') if release_files:
# If there is only one file in the torrent, the downloader did not create a subfolder # If there is only one file in the torrent, the downloader did not create a subfolder
if len(files) == 1: if len(release_files) == 1:
folder = media_folder folder = media_folder
else: else:
# Get all files from the specified folder # Get all files from the specified folder
@ -446,7 +451,7 @@ class Renamer(Plugin):
log.error('Failed marking movie finished: %s', (traceback.format_exc())) log.error('Failed marking movie finished: %s', (traceback.format_exc()))
# Go over current movie releases # Go over current movie releases
for release in db.run('release', 'for_media', media['_id']): for release in fireEvent('release.for_media', media['_id'], single = True):
# When a release already exists # When a release already exists
if release.get('status') == 'done': if release.get('status') == 'done':
@ -643,8 +648,8 @@ Remove it if you want it to be renamed (again, or at least let it try again)
elif isinstance(release_download, dict): elif isinstance(release_download, dict):
# Tag download_files if they are known # Tag download_files if they are known
if release_download['files']: if release_download.get('files', []):
tag_files = splitString(release_download['files'], '|') tag_files = release_download.get('files', [])
# Tag all files in release folder # Tag all files in release folder
else: else:
@ -678,8 +683,8 @@ Remove it if you want it to be renamed (again, or at least let it try again)
elif isinstance(release_download, dict): elif isinstance(release_download, dict):
# Untag download_files if they are known # Untag download_files if they are known
if release_download['files']: if release_download.get('files'):
tag_files = splitString(release_download['files'], '|') tag_files = release_download.get('files', [])
# Untag all files in release folder # Untag all files in release folder
else: else:
@ -719,8 +724,8 @@ Remove it if you want it to be renamed (again, or at least let it try again)
ignore_files = [] ignore_files = []
# Find tag on download_files if they are known # Find tag on download_files if they are known
if release_download['files']: if release_download.get('files'):
tag_files = splitString(release_download['files'], '|') tag_files = release_download.get('files', [])
# Find tag on all files in release folder # Find tag on all files in release folder
else: else:
@ -834,7 +839,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
try: try:
db = get_db() db = get_db()
rels = list(db.run('release', 'with_status', ['snatched', 'seeding', 'missing'])) rels = list(fireEvent('release.with_status', ['snatched', 'seeding', 'missing'], single = True))
if not rels: if not rels:
#No releases found that need status checking #No releases found that need status checking
@ -906,7 +911,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
found_release = True found_release = True
break break
else: else:
if release_download['name'] == nzbname or rel['info']['name'] in release_download['name'] or getImdb(release_download['name']) == movie_dict['identifier']: if release_download['name'] == nzbname or rel['info']['name'] in release_download['name'] or getImdb(release_download['name']) == getIdentifier(movie_dict):
log.debug('Found release by release name or imdb ID: %s', release_download['name']) log.debug('Found release by release name or imdb ID: %s', release_download['name'])
found_release = True found_release = True
break break
@ -1043,7 +1048,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
if rls: if rls:
media = db.get('id', rls['media_id']) media = db.get('id', rls['media_id'])
release_download.update({ release_download.update({
'imdb_id': media['identifier'], 'imdb_id': getIdentifier(media),
'quality': rls['quality'], 'quality': rls['quality'],
'protocol': rls.get('info', {}).get('protocol') or rls.get('info', {}).get('type'), 'protocol': rls.get('info', {}).get('protocol') or rls.get('info', {}).get('type'),
'release_id': rls['_id'], 'release_id': rls['_id'],

4
couchpotato/core/plugins/scanner.py

@ -8,7 +8,7 @@ from couchpotato import get_db
from couchpotato.core.event import fireEvent, addEvent from couchpotato.core.event import fireEvent, addEvent
from couchpotato.core.helpers.encoding import toUnicode, simplifyString, sp from couchpotato.core.helpers.encoding import toUnicode, simplifyString, sp
from couchpotato.core.helpers.variable import getExt, getImdb, tryInt, \ from couchpotato.core.helpers.variable import getExt, getImdb, tryInt, \
splitString splitString, getIdentifier
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
from enzyme.exceptions import NoParserError, ParseError from enzyme.exceptions import NoParserError, ParseError
@ -403,7 +403,7 @@ class Scanner(Plugin):
if not group['media']: if not group['media']:
log.error('Unable to determine media: %s', group['identifiers']) log.error('Unable to determine media: %s', group['identifiers'])
else: else:
group['identifier'] = group['media'].get('identifier') or group['media']['info'].get('imdb') group['identifier'] = getIdentifier(group['media']) or group['media']['info'].get('imdb')
processed_movies[identifier] = group processed_movies[identifier] = group

7
libs/rtorrent/__init__.py

@ -89,13 +89,16 @@ class RTorrent:
def _get_conn(self): def _get_conn(self):
"""Get ServerProxy instance""" """Get ServerProxy instance"""
if self.username is not None and self.password is not None:
if self.username and self.password:
if self.scheme == 'scgi': if self.scheme == 'scgi':
raise NotImplementedError() raise NotImplementedError()
secure = self.scheme == 'https'
return self.sp( return self.sp(
self.uri, self.uri,
transport=BasicAuthTransport(self.username, self.password), transport=BasicAuthTransport(secure, self.username, self.password),
**self.sp_kwargs **self.sp_kwargs
) )

38
libs/rtorrent/lib/xmlrpc/basic_auth.py

@ -20,24 +20,46 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from base64 import encodestring from base64 import b64encode
import string import httplib
import xmlrpclib import xmlrpclib
class BasicAuthTransport(xmlrpclib.Transport): class BasicAuthTransport(xmlrpclib.Transport):
def __init__(self, username=None, password=None): def __init__(self, secure=False, username=None, password=None):
xmlrpclib.Transport.__init__(self) xmlrpclib.Transport.__init__(self)
self.secure = secure
self.username = username self.username = username
self.password = password self.password = password
def send_auth(self, h): def send_auth(self, h):
if self.username is not None and self.password is not None: if not self.username or not self.password:
h.putheader('AUTHORIZATION', "Basic %s" % string.replace( return
encodestring("%s:%s" % (self.username, self.password)),
"\012", "" auth = b64encode("%s:%s" % (self.username, self.password))
))
h.putheader('Authorization', "Basic %s" % auth)
def make_connection(self, host):
if self._connection and host == self._connection[0]:
return self._connection[1]
chost, self._extra_headers, x509 = self.get_host_info(host)
if self.secure:
try:
self._connection = host, httplib.HTTPSConnection(chost, None, **(x509 or {}))
except AttributeError:
raise NotImplementedError(
"your version of httplib doesn't support HTTPS"
)
else:
self._connection = host, httplib.HTTPConnection(chost)
return self._connection[1]
def single_request(self, host, handler, request_body, verbose=0): def single_request(self, host, handler, request_body, verbose=0):
# issue XML-RPC request # issue XML-RPC request

Loading…
Cancel
Save