diff --git a/contributing.md b/contributing.md
index d5db0b4..0d82d71 100644
--- a/contributing.md
+++ b/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
- * Search through the existing (and closed) issues first, see if you can get your answer there.
- * Double check the result manually, because it could be an external issue.
- * Post logs! Without seeing what is going on, I can't reproduce the error.
- * Also check the logs before submitting, obvious errors like permission or http errors are often not related to CP.
- * What is the movie + quality you are searching for?
- * What are you're settings for the specific problem?
- * What providers are you using? (While you're logs include these, scanning through hundred of lines of log isn't our hobby)
- * Post the logs from config directory, please do not copy paste the UI. Use pastebin to store these logs!
+## Contributing
+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.
+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!
+If you want to contribute your own work, please read the [guidelines](#pull-requests) for submitting a pull request.
+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.
+
+## Issues
+Issues are intended for reporting bugs and weird behaviour or suggesting improvements to CouchPotatoServer.
+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.
- * 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.
- * 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 ;)
- * 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!!
+ * 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.
+ * 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 set up to use our source repository (RuudBurger/CouchPotatoServer) and nothing else!!
+
+The more relevant information you can provide, the more likely it is the issue will be resolved rather than closed.
-## Pull Request
- * Make sure you're pull request is made for develop branch (or relevant feature branch)
+## 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?
- * 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 ;)**
+ * 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?
diff --git a/couchpotato/__init__.py b/couchpotato/__init__.py
index ce034db..1946963 100644
--- a/couchpotato/__init__.py
+++ b/couchpotato/__init__.py
@@ -48,10 +48,6 @@ def addView(route, func, static = False):
views[route] = func
-def get_session():
- return None
-
-
def get_db():
return Env.get('db')
diff --git a/couchpotato/core/database.py b/couchpotato/core/database.py
index 3aa1bb7..19fde90 100644
--- a/couchpotato/core/database.py
+++ b/couchpotato/core/database.py
@@ -279,8 +279,8 @@ class Database(object):
quality = db.get('id', q_id)
quality['order'] = q.get('order')
- quality['size_min'] = q.get('size_min')
- quality['size_max'] = q.get('size_max')
+ quality['size_min'] = tryInt(q.get('size_min'))
+ quality['size_max'] = tryInt(q.get('size_max'))
db.update(quality)
quality_link[x] = quality
diff --git a/couchpotato/core/downloaders/base.py b/couchpotato/core/downloaders/base.py
index 269bdc6..8042c4a 100644
--- a/couchpotato/core/downloaders/base.py
+++ b/couchpotato/core/downloaders/base.py
@@ -210,7 +210,7 @@ class ReleaseDownloadList(list):
'status': 'busy',
'downloader': self.provider.getName(),
'folder': '',
- 'files': '',
+ 'files': [],
}
return mergeDicts(defaults, result)
diff --git a/couchpotato/core/downloaders/deluge.py b/couchpotato/core/downloaders/deluge.py
index 2a386ad..26592ca 100644
--- a/couchpotato/core/downloaders/deluge.py
+++ b/couchpotato/core/downloaders/deluge.py
@@ -147,7 +147,7 @@ class Deluge(Downloader):
'seed_ratio': torrent['ratio'],
'timeleft': str(timedelta(seconds = torrent['eta'])),
'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
diff --git a/couchpotato/core/downloaders/qbittorrent_.py b/couchpotato/core/downloaders/qbittorrent_.py
index 349af17..558222d 100644
--- a/couchpotato/core/downloaders/qbittorrent_.py
+++ b/couchpotato/core/downloaders/qbittorrent_.py
@@ -135,7 +135,7 @@ class qBittorrent(Downloader):
'original_status': torrent.state,
'timeleft': torrent.progress * 100 if torrent.progress else -1, # percentage
'folder': sp(torrent.save_path),
- 'files': '|'.join(torrent_files)
+ 'files': torrent_files
})
return release_downloads
diff --git a/couchpotato/core/downloaders/rtorrent_.py b/couchpotato/core/downloaders/rtorrent_.py
index fb8948c..98946b2 100644
--- a/couchpotato/core/downloaders/rtorrent_.py
+++ b/couchpotato/core/downloaders/rtorrent_.py
@@ -59,20 +59,22 @@ class rTorrent(Downloader):
return self.rt
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)
# rpc_url is only used on http/https scgi pass-through
if parsed.scheme in ['http', 'https']:
url += self.conf('rpc_url')
- if self.conf('username') and self.conf('password'):
- self.rt = RTorrent(
- url,
- self.conf('username'),
- self.conf('password')
- )
- else:
- self.rt = RTorrent(url)
+ self.rt = RTorrent(
+ url,
+ self.conf('username'),
+ self.conf('password')
+ )
self.error_msg = ''
try:
@@ -243,7 +245,7 @@ class rTorrent(Downloader):
'original_status': torrent.state,
'timeleft': str(timedelta(seconds = float(torrent.left_bytes) / torrent.down_rate)) if torrent.down_rate > 0 else -1,
'folder': sp(torrent.directory),
- 'files': '|'.join(torrent_files)
+ 'files': torrent_files
})
return release_downloads
diff --git a/couchpotato/core/downloaders/synology.py b/couchpotato/core/downloaders/synology.py
index 46d889f..f7145de 100644
--- a/couchpotato/core/downloaders/synology.py
+++ b/couchpotato/core/downloaders/synology.py
@@ -33,7 +33,7 @@ class Synology(Downloader):
try:
# 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':
log.info('Adding torrent URL %s', data['url'])
response = srpc.create_task(url = data['url'])
@@ -84,7 +84,7 @@ class SynologyRPC(object):
"""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__()
@@ -92,6 +92,7 @@ class SynologyRPC(object):
self.auth_url = 'http://%s:%s/webapi/auth.cgi' % (host, port)
self.username = username
self.password = password
+ self.destination = destination
self.session_name = 'DownloadStation'
def _login(self):
@@ -144,6 +145,10 @@ class SynologyRPC(object):
'version': '1',
'method': 'create',
'_sid': self.sid}
+
+ if self.destination and len(self.destination) > 0:
+ args['destination'] = self.destination
+
if url:
log.info('Login success, adding torrent URI')
args['uri'] = url
@@ -196,6 +201,11 @@ config = [{
'type': 'password',
},
{
+ 'name': 'destination',
+ 'description': 'Specify existing destination share to where your files will be downloaded, usually Downloads',
+ 'advanced': True,
+ },
+ {
'name': 'use_for',
'label': 'Use for',
'default': 'both',
diff --git a/couchpotato/core/downloaders/transmission.py b/couchpotato/core/downloaders/transmission.py
index f49cb9d..dd11166 100644
--- a/couchpotato/core/downloaders/transmission.py
+++ b/couchpotato/core/downloaders/transmission.py
@@ -141,7 +141,7 @@ class Transmission(Downloader):
'seed_ratio': torrent['uploadRatio'],
'timeleft': str(timedelta(seconds = torrent['eta'])),
'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
diff --git a/couchpotato/core/downloaders/utorrent.py b/couchpotato/core/downloaders/utorrent.py
index dae8950..671dd9e 100644
--- a/couchpotato/core/downloaders/utorrent.py
+++ b/couchpotato/core/downloaders/utorrent.py
@@ -184,7 +184,7 @@ class uTorrent(Downloader):
'original_status': torrent[1],
'timeleft': str(timedelta(seconds = torrent[10])),
'folder': sp(torrent[26]),
- 'files': '|'.join(torrent_files)
+ 'files': torrent_files
})
return release_downloads
diff --git a/couchpotato/core/helpers/variable.py b/couchpotato/core/helpers/variable.py
index 5eab960..34e66e9 100644
--- a/couchpotato/core/helpers/variable.py
+++ b/couchpotato/core/helpers/variable.py
@@ -227,6 +227,10 @@ def toIterable(value):
return [value]
+def getIdentifier(media):
+ return media.get('identifier') or media.get('identifiers', {}).get('imdb')
+
+
def getTitle(media_dict):
try:
try:
@@ -241,10 +245,10 @@ def getTitle(media_dict):
try:
return media_dict['media']['info']['titles'][0]
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
- log.error('Could not get title for %s', media_dict['identifier'])
+ log.error('Could not get title for %s', getIdentifier(media_dict))
return None
except:
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)
# 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):
m = None
for reg in re_password:
diff --git a/couchpotato/core/media/__init__.py b/couchpotato/core/media/__init__.py
index f9b3b46..8e704de 100644
--- a/couchpotato/core/media/__init__.py
+++ b/couchpotato/core/media/__init__.py
@@ -25,7 +25,7 @@ class MediaBase(Plugin):
def onComplete():
try:
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')
fireEventAsync(event_name, media, on_complete = self.createNotifyFront(media_id))
@@ -38,8 +38,7 @@ class MediaBase(Plugin):
def notifyFront():
try:
- db = get_db()
- media = db.get('id', media_id)
+ media = fireEvent('media.get', media_id, single = True)
event_name = '%s.update' % media.get('type')
fireEvent('notify.frontend', type = event_name, data = media)
diff --git a/couchpotato/core/media/_base/media/index.py b/couchpotato/core/media/_base/media/index.py
index 5065871..42e6990 100644
--- a/couchpotato/core/media/_base/media/index.py
+++ b/couchpotato/core/media/_base/media/index.py
@@ -6,7 +6,7 @@ from couchpotato.core.helpers.encoding import toUnicode, simplifyString
class MediaIndex(MultiTreeBasedIndex):
- _version = 2
+ _version = 3
custom_header = """from CodernityDB.tree_index import MultiTreeBasedIndex"""
@@ -26,31 +26,10 @@ class MediaIndex(MultiTreeBasedIndex):
ids = []
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
- 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):
_version = 1
diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py
index 85047e9..f6bcd71 100644
--- a/couchpotato/core/media/_base/media/main.py
+++ b/couchpotato/core/media/_base/media/main.py
@@ -74,6 +74,8 @@ class MediaPlugin(MediaBase):
addEvent('app.load', self.addSingleDeleteView, priority = 100)
addEvent('media.get', self.get)
+ addEvent('media.with_status', self.withStatus)
+ addEvent('media.with_identifiers', self.withIdentifiers)
addEvent('media.list', self.list)
addEvent('media.delete', self.delete)
addEvent('media.restatus', self.restatus)
@@ -99,13 +101,10 @@ class MediaPlugin(MediaBase):
try:
media = get_db().get('id', media_id)
-
-
- default_title = getTitle(media)
event = '%s.update_info' % media.get('type')
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:
return handler
@@ -124,16 +123,21 @@ class MediaPlugin(MediaBase):
imdb_id = getImdb(str(media_id))
+ media = None
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:
- m = db.get('id', media_id)
+ media = db.get('id', media_id)
+
+ if media:
- results = None
- if m:
- results = db.run('media', 'to_dict', m['_id'])
+ # Attach category
+ if media.get('category_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):
@@ -144,6 +148,29 @@ class MediaPlugin(MediaBase):
'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):
db = get_db()
@@ -170,13 +197,13 @@ class MediaPlugin(MediaBase):
# Filter on movie status
if status and len(status) > 0:
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 on release status
if release_status and len(release_status) > 0:
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'))
# Add search filters
@@ -220,9 +247,7 @@ class MediaPlugin(MediaBase):
offset -= 1
continue
- media = db.run('media', 'to_dict', media_id)
-
- media['releases'] = list(db.run('release', 'for_media', media_id))
+ media = fireEvent('media.get', media_id, single = True)
# Merge releases with movie dict
medias.append(media)
@@ -285,13 +310,13 @@ class MediaPlugin(MediaBase):
# Filter on movie status
if status and len(status) > 0:
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 on release status
if release_status and len(release_status) > 0:
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 combining ids
@@ -341,7 +366,7 @@ class MediaPlugin(MediaBase):
deleted = True
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_deleted = 0
@@ -407,7 +432,7 @@ class MediaPlugin(MediaBase):
move_to_wanted = True
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']:
index = profile['qualities'].index(q_identifier)
diff --git a/couchpotato/core/media/_base/providers/torrent/awesomehd.py b/couchpotato/core/media/_base/providers/torrent/awesomehd.py
index bf10456..1372f6c 100644
--- a/couchpotato/core/media/_base/providers/torrent/awesomehd.py
+++ b/couchpotato/core/media/_base/providers/torrent/awesomehd.py
@@ -2,7 +2,7 @@ import re
import traceback
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.media._base.providers.torrent.base import TorrentProvider
@@ -22,7 +22,7 @@ class Base(TorrentProvider):
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:
try:
diff --git a/couchpotato/core/media/_base/providers/torrent/hdbits.py b/couchpotato/core/media/_base/providers/torrent/hdbits.py
index 73bfc16..c2e85ac 100644
--- a/couchpotato/core/media/_base/providers/torrent/hdbits.py
+++ b/couchpotato/core/media/_base/providers/torrent/hdbits.py
@@ -2,7 +2,7 @@ import re
import json
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.media._base.providers.torrent.base import TorrentProvider
@@ -44,7 +44,7 @@ class Base(TorrentProvider):
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)})
@@ -56,7 +56,7 @@ class Base(TorrentProvider):
'name': result['name'],
'url': self.urls['download'] % (result['id'], self.conf('passkey')),
'detail_url': self.urls['detail'] % result['id'],
- 'size': self.parseSize(result['size']),
+ 'size': tryInt(result['size'])/1024/1024,
'seeders': tryInt(result['seeders']),
'leechers': tryInt(result['leechers'])
})
diff --git a/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py b/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py
index 03f0a99..b347ccb 100644
--- a/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py
+++ b/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py
@@ -2,7 +2,7 @@ import re
import traceback
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.media._base.providers.torrent.base import TorrentMagnetProvider
@@ -38,7 +38,7 @@ class Base(TorrentMagnetProvider):
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:
diff --git a/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py b/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py
index 56550d2..5368ad3 100644
--- a/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py
+++ b/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py
@@ -5,7 +5,7 @@ import time
import traceback
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.media._base.providers.torrent.base import TorrentProvider
from dateutil.parser import parse
@@ -36,7 +36,7 @@ class Base(TorrentProvider):
params = mergeDicts(self.quality_search_params[quality_id].copy(), {
'order_by': 'relevance',
'order_way': 'descending',
- 'searchstr': media['identifier']
+ 'searchstr': getIdentifier(media)
})
url = '%s?json=noredirect&%s' % (self.urls['torrent'], tryUrlencode(params))
diff --git a/couchpotato/core/media/_base/providers/torrent/thepiratebay.py b/couchpotato/core/media/_base/providers/torrent/thepiratebay.py
index 42006d1..4d81961 100644
--- a/couchpotato/core/media/_base/providers/torrent/thepiratebay.py
+++ b/couchpotato/core/media/_base/providers/torrent/thepiratebay.py
@@ -29,9 +29,9 @@ class Base(TorrentMagnetProvider):
'http://pirateproxy.ca',
'http://tpb.al',
'http://www.tpb.gr',
- 'http://nl.tpb.li',
+ 'http://bayproxy.me',
'http://proxybay.eu',
- 'https://www.getpirate.com',
+ 'http://www.getpirate.com',
'http://piratebay.io',
]
diff --git a/couchpotato/core/media/_base/providers/torrent/yify.py b/couchpotato/core/media/_base/providers/torrent/yify.py
index 9380e65..fe7a9b4 100644
--- a/couchpotato/core/media/_base/providers/torrent/yify.py
+++ b/couchpotato/core/media/_base/providers/torrent/yify.py
@@ -1,6 +1,6 @@
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.media._base.providers.torrent.base import TorrentProvider
@@ -35,7 +35,7 @@ class Base(TorrentProvider):
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)
diff --git a/couchpotato/core/media/movie/_base/main.py b/couchpotato/core/media/movie/_base/main.py
index d8060d7..a783cd1 100644
--- a/couchpotato/core/media/movie/_base/main.py
+++ b/couchpotato/core/media/movie/_base/main.py
@@ -6,7 +6,7 @@ from couchpotato import get_db
from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, fireEventAsync, addEvent
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.media.movie import MovieTypeBase
import six
@@ -138,7 +138,7 @@ class MovieBase(MovieTypeBase):
elif force_readd:
# 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 params.get('ignore_previous', False):
release['status'] = 'ignored'
@@ -164,11 +164,11 @@ class MovieBase(MovieTypeBase):
fireEventAsync('movie.update_info', m['_id'], default_title = params.get('title'), on_complete = onComplete)
# 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':
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:
onComplete = self.createOnComplete(m['_id'])
@@ -215,7 +215,7 @@ class MovieBase(MovieTypeBase):
m['category_id'] = cat_id if len(cat_id) > 0 else None
# 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':
db.delete(rel)
@@ -229,7 +229,7 @@ class MovieBase(MovieTypeBase):
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))
except:
@@ -266,7 +266,7 @@ class MovieBase(MovieTypeBase):
else:
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
try: del info['in_wanted']
@@ -275,7 +275,7 @@ class MovieBase(MovieTypeBase):
except: pass
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
# Update basic info
@@ -285,19 +285,20 @@ class MovieBase(MovieTypeBase):
log.debug('Adding titles: %s', titles)
# Define default title
- def_title = None
if default_title:
- counter = 0
- for title in titles:
- if title.lower() == toUnicode(default_title.lower()) or (toUnicode(default_title) == six.u('') and toUnicode(titles[0]) == title):
- def_title = toUnicode(title)
- break
- counter += 1
+ def_title = None
+ if default_title:
+ counter = 0
+ for title in titles:
+ if title.lower() == toUnicode(default_title.lower()) or (toUnicode(default_title) == six.u('') and toUnicode(titles[0]) == title):
+ def_title = toUnicode(title)
+ break
+ counter += 1
- if not def_title:
- def_title = toUnicode(titles[0])
+ if not def_title:
+ def_title = toUnicode(titles[0])
- media['title'] = def_title
+ media['title'] = def_title
# Files
images = info.get('images', [])
@@ -357,7 +358,7 @@ class MovieBase(MovieTypeBase):
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:
- 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})
db.update(media)
diff --git a/couchpotato/core/media/movie/_base/static/movie.actions.js b/couchpotato/core/media/movie/_base/static/movie.actions.js
index cb4be00..5dcaed7 100644
--- a/couchpotato/core/media/movie/_base/static/movie.actions.js
+++ b/couchpotato/core/media/movie/_base/static/movie.actions.js
@@ -428,7 +428,7 @@ MA.Release = new Class({
Api.request('movie.searcher.try_next', {
'data': {
- 'id': self.movie.get('_id')
+ 'media_id': self.movie.get('_id')
}
});
diff --git a/couchpotato/core/media/movie/providers/automation/itunes.py b/couchpotato/core/media/movie/providers/automation/itunes.py
index bb6eef2..fcb20b1 100644
--- a/couchpotato/core/media/movie/providers/automation/itunes.py
+++ b/couchpotato/core/media/movie/providers/automation/itunes.py
@@ -26,7 +26,7 @@ class ITunes(Automation, RSS):
urls = splitString(self.conf('automation_urls'))
namespace = 'http://www.w3.org/2005/Atom'
- namespace_im = 'https://rss.itunes.apple.com'
+ namespace_im = 'http://itunes.apple.com/rss'
index = -1
for url in urls:
diff --git a/couchpotato/core/media/movie/providers/info/_modifier.py b/couchpotato/core/media/movie/providers/info/_modifier.py
index 131cc05..cea0f49 100644
--- a/couchpotato/core/media/movie/providers/info/_modifier.py
+++ b/couchpotato/core/media/movie/providers/info/_modifier.py
@@ -3,7 +3,7 @@ import traceback
from CodernityDB.database import RecordNotFound
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.logger import CPLog
from couchpotato.core.plugins.base import Plugin
@@ -104,7 +104,7 @@ class MovieResultModifier(Plugin):
if media.get('status') == 'active':
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 not temp['in_library']:
temp['in_library'] = media
diff --git a/couchpotato/core/media/movie/providers/nzb/binsearch.py b/couchpotato/core/media/movie/providers/nzb/binsearch.py
index f4c16c4..d6f4852 100644
--- a/couchpotato/core/media/movie/providers/nzb/binsearch.py
+++ b/couchpotato/core/media/movie/providers/nzb/binsearch.py
@@ -1,4 +1,5 @@
from couchpotato.core.helpers.encoding import tryUrlencode
+from couchpotato.core.helpers.variable import getIdentifier
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.nzb.binsearch import Base
from couchpotato.core.media.movie.providers.base import MovieProvider
@@ -13,7 +14,7 @@ class BinSearch(MovieProvider, Base):
def buildUrl(self, media, quality):
query = tryUrlencode({
- 'q': media['identifier'],
+ 'q': getIdentifier(media),
'm': 'n',
'max': 400,
'adv_age': Env.setting('retention', 'nzb'),
diff --git a/couchpotato/core/media/movie/providers/nzb/newznab.py b/couchpotato/core/media/movie/providers/nzb/newznab.py
index dd4d94c..9783f8d 100644
--- a/couchpotato/core/media/movie/providers/nzb/newznab.py
+++ b/couchpotato/core/media/movie/providers/nzb/newznab.py
@@ -1,4 +1,5 @@
from couchpotato.core.helpers.encoding import tryUrlencode
+from couchpotato.core.helpers.variable import getIdentifier
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.nzb.newznab import Base
from couchpotato.core.media.movie.providers.base import MovieProvider
@@ -13,7 +14,7 @@ class Newznab(MovieProvider, Base):
def buildUrl(self, media, api_key):
query = tryUrlencode({
't': 'movie',
- 'imdbid': media['identifier'].replace('tt', ''),
+ 'imdbid': getIdentifier(media).replace('tt', ''),
'apikey': api_key,
'extended': 1
})
diff --git a/couchpotato/core/media/movie/providers/nzb/nzbindex.py b/couchpotato/core/media/movie/providers/nzb/nzbindex.py
index 0b5b2b4..70e939d 100644
--- a/couchpotato/core/media/movie/providers/nzb/nzbindex.py
+++ b/couchpotato/core/media/movie/providers/nzb/nzbindex.py
@@ -14,7 +14,7 @@ class NzbIndex(MovieProvider, Base):
def buildUrl(self, media, quality):
title = fireEvent('library.query', media, include_year = False, single = True)
- year = media['year']
+ year = media['info']['year']
query = tryUrlencode({
'q': '"%s %s" | "%s (%s)"' % (title, year, title, year),
diff --git a/couchpotato/core/media/movie/providers/torrent/bitsoup.py b/couchpotato/core/media/movie/providers/torrent/bitsoup.py
index 578de69..b3ecf2e 100644
--- a/couchpotato/core/media/movie/providers/torrent/bitsoup.py
+++ b/couchpotato/core/media/movie/providers/torrent/bitsoup.py
@@ -21,7 +21,7 @@ class Bitsoup(MovieProvider, Base):
query = tryUrlencode({
'search': '"%s" %s' % (
fireEvent('library.query', media, include_year = False, single = True),
- media['year']
+ media['info']['year']
),
'cat': self.getCatId(quality['identifier'])[0],
})
diff --git a/couchpotato/core/media/movie/providers/torrent/iptorrents.py b/couchpotato/core/media/movie/providers/torrent/iptorrents.py
index a1ad4aa..4f9d651 100644
--- a/couchpotato/core/media/movie/providers/torrent/iptorrents.py
+++ b/couchpotato/core/media/movie/providers/torrent/iptorrents.py
@@ -17,6 +17,6 @@ class IPTorrents(MovieProvider, Base):
]
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'])
diff --git a/couchpotato/core/media/movie/providers/torrent/torrentpotato.py b/couchpotato/core/media/movie/providers/torrent/torrentpotato.py
index 9c99207..6757353 100644
--- a/couchpotato/core/media/movie/providers/torrent/torrentpotato.py
+++ b/couchpotato/core/media/movie/providers/torrent/torrentpotato.py
@@ -1,4 +1,5 @@
from couchpotato.core.helpers.encoding import tryUrlencode
+from couchpotato.core.helpers.variable import getIdentifier
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.torrent.torrentpotato import Base
from couchpotato.core.media.movie.providers.base import MovieProvider
@@ -14,6 +15,6 @@ class TorrentPotato(MovieProvider, Base):
arguments = tryUrlencode({
'user': host['name'],
'passkey': host['pass_key'],
- 'imdbid': media['identifier']
+ 'imdbid': getIdentifier(media),
})
return '%s?%s' % (host['host'], arguments)
diff --git a/couchpotato/core/media/movie/searcher.py b/couchpotato/core/media/movie/searcher.py
index 515f5f9..682fa69 100644
--- a/couchpotato/core/media/movie/searcher.py
+++ b/couchpotato/core/media/movie/searcher.py
@@ -8,7 +8,7 @@ from couchpotato import get_db
from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent, fireEventAsync
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.media._base.searcher.base import SearcherBase
from couchpotato.core.media.movie import MovieTypeBase
@@ -38,7 +38,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
addApiView('movie.searcher.try_next', self.tryNextReleaseView, docs = {
'desc': 'Marks the snatched results as ignored and try the next best release',
'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
fireEvent('notify.frontend', type = 'movie.searcher.started', data = True, message = 'Full search started')
- db = get_db()
-
- medias = [x['_id'] for x in db.run('media', 'with_status', 'active', with_doc = False)]
+ medias = [x['_id'] for x in fireEvent('media.with_status', 'active', with_doc = False, single = True)]
random.shuffle(medias)
total = len(medias)
@@ -90,15 +88,15 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
for media_id in medias:
- media = db.run('media', 'to_dict', media_id)
+ media = fireEvent('media.get', media_id, single = True)
try:
self.single(media, search_protocols)
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)
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
@@ -142,7 +140,6 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
profile = db.get('id', movie['profile_id'])
quality_order = fireEvent('quality.order', single = True)
- media_releases = db.run('release', 'for_media', movie['_id'])
ret = False
@@ -161,7 +158,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
has_better_quality = 0
# 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']:
has_better_quality += 1
@@ -187,7 +184,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
ret = True
# 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:
fireEvent('release.delete', release.get('_id'), single = True)
@@ -233,12 +230,12 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
# 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']))
return False
# 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']))
return False
@@ -257,7 +254,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
return True
# Check if nzb contains imdb link
- if getImdb(nzb.get('description', '')) == media['identifier']:
+ if getImdb(nzb.get('description', '')) == getIdentifier(media):
return True
for raw_title in media['info']['titles']:
@@ -317,9 +314,9 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
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 {
'success': trynext
@@ -329,13 +326,13 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
try:
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:
rel['status'] = 'ignored'
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))
self.single(movie_dict, manual = manual)
diff --git a/couchpotato/core/media/movie/suggestion/main.py b/couchpotato/core/media/movie/suggestion/main.py
index 62b9f57..5db403f 100644
--- a/couchpotato/core/media/movie/suggestion/main.py
+++ b/couchpotato/core/media/movie/suggestion/main.py
@@ -1,7 +1,7 @@
from couchpotato import get_db
from couchpotato.api import addApiView
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.environment import Env
@@ -28,9 +28,8 @@ class Suggestion(Plugin):
else:
if not movies or len(movies) == 0:
- db = get_db()
- active_movies = db.run('media', 'with_status', ['active', 'done'])
- movies = [x['identifier'] for x in active_movies]
+ active_movies = fireEvent('media.with_status', ['active', 'done'], single = True)
+ movies = [getIdentifier(x) for x in active_movies]
if not ignored or len(ignored) == 0:
ignored = splitString(Env.prop('suggest_ignore', default = ''))
@@ -86,8 +85,8 @@ class Suggestion(Plugin):
# Get new results and add them
if len(new_suggestions) - 1 < limit:
db = get_db()
- active_movies = db.run('media', 'with_status', ['active', 'done'])
- movies = [x['identifier'] for x in active_movies]
+ active_movies = fireEvent('media.with_status', ['active', 'done'], single = True)
+ movies = [getIdentifier(x) for x in active_movies]
movies.extend(seen)
ignored.extend([x.get('imdb') for x in cached_suggestion])
diff --git a/couchpotato/core/notifications/boxcar.py b/couchpotato/core/notifications/boxcar.py
index 3777a42..a7acc88 100644
--- a/couchpotato/core/notifications/boxcar.py
+++ b/couchpotato/core/notifications/boxcar.py
@@ -7,6 +7,8 @@ from couchpotato.core.notifications.base import Notification
log = CPLog(__name__)
+autoload = 'Boxcar'
+
class Boxcar(Notification):
diff --git a/couchpotato/core/notifications/boxcar2.py b/couchpotato/core/notifications/boxcar2.py
index 3e19c19..04ce4f3 100644
--- a/couchpotato/core/notifications/boxcar2.py
+++ b/couchpotato/core/notifications/boxcar2.py
@@ -25,7 +25,7 @@ class Boxcar2(Notification):
data = {
'user_credentials': self.conf('token'),
- 'notification[title]': toUnicode(message),
+ 'notification[title]': toUnicode('%s - %s' % (self.default_title, message)),
'notification[long_message]': toUnicode(long_message),
}
diff --git a/couchpotato/core/notifications/email_.py b/couchpotato/core/notifications/email_.py
index b42650b..938a361 100644
--- a/couchpotato/core/notifications/email_.py
+++ b/couchpotato/core/notifications/email_.py
@@ -12,6 +12,8 @@ from couchpotato.environment import Env
log = CPLog(__name__)
+autoload = 'Email'
+
class Email(Notification):
diff --git a/couchpotato/core/notifications/growl.py b/couchpotato/core/notifications/growl.py
index c7847da..160e383 100644
--- a/couchpotato/core/notifications/growl.py
+++ b/couchpotato/core/notifications/growl.py
@@ -9,6 +9,8 @@ from gntp import notifier
log = CPLog(__name__)
+autoload = 'Growl'
+
class Growl(Notification):
diff --git a/couchpotato/core/notifications/nmj.py b/couchpotato/core/notifications/nmj.py
index 6ef70d4..4b9b92b 100644
--- a/couchpotato/core/notifications/nmj.py
+++ b/couchpotato/core/notifications/nmj.py
@@ -15,6 +15,8 @@ except ImportError:
log = CPLog(__name__)
+autoload = 'NMJ'
+
class NMJ(Notification):
diff --git a/couchpotato/core/notifications/notifymyandroid.py b/couchpotato/core/notifications/notifymyandroid.py
index 8b08360..ed7a24c 100644
--- a/couchpotato/core/notifications/notifymyandroid.py
+++ b/couchpotato/core/notifications/notifymyandroid.py
@@ -6,6 +6,8 @@ import six
log = CPLog(__name__)
+autoload = 'NotifyMyAndroid'
+
class NotifyMyAndroid(Notification):
diff --git a/couchpotato/core/notifications/notifymywp.py b/couchpotato/core/notifications/notifymywp.py
index 914897f..262fd8d 100644
--- a/couchpotato/core/notifications/notifymywp.py
+++ b/couchpotato/core/notifications/notifymywp.py
@@ -6,6 +6,8 @@ import six
log = CPLog(__name__)
+autoload = 'NotifyMyWP'
+
class NotifyMyWP(Notification):
diff --git a/couchpotato/core/notifications/prowl.py b/couchpotato/core/notifications/prowl.py
index b276d7f..fdece32 100644
--- a/couchpotato/core/notifications/prowl.py
+++ b/couchpotato/core/notifications/prowl.py
@@ -7,6 +7,8 @@ from couchpotato.core.notifications.base import Notification
log = CPLog(__name__)
+autoload = 'Prowl'
+
class Prowl(Notification):
diff --git a/couchpotato/core/notifications/pushalot.py b/couchpotato/core/notifications/pushalot.py
index 0ce9027..f8fa187 100644
--- a/couchpotato/core/notifications/pushalot.py
+++ b/couchpotato/core/notifications/pushalot.py
@@ -7,6 +7,8 @@ from couchpotato.core.notifications.base import Notification
log = CPLog(__name__)
+autoload = 'Pushalot'
+
class Pushalot(Notification):
diff --git a/couchpotato/core/notifications/pushbullet.py b/couchpotato/core/notifications/pushbullet.py
index fd1a376..56cf228 100644
--- a/couchpotato/core/notifications/pushbullet.py
+++ b/couchpotato/core/notifications/pushbullet.py
@@ -9,6 +9,8 @@ from couchpotato.core.notifications.base import Notification
log = CPLog(__name__)
+autoload = 'Pushbullet'
+
class Pushbullet(Notification):
diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py
index 7d52e1e..c5892f5 100644
--- a/couchpotato/core/plugins/base.py
+++ b/couchpotato/core/plugins/base.py
@@ -7,11 +7,10 @@ import time
import traceback
import urllib2
-from couchpotato import get_db
from couchpotato.core.event import fireEvent, addEvent
from couchpotato.core.helpers.encoding import ss, toSafeString, \
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.environment import Env
import requests
@@ -327,19 +326,22 @@ class Plugin(object):
if name_password:
release_name, password = name_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
return '%s%s' % (toSafeString(toUnicode(release_name)[:max_length]), tag)
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 '' not in filedata:
return '%s.%s' % (name, 'rar')
return '%s.%s' % (name, data.get('protocol'))
def cpTag(self, media):
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 ''
diff --git a/couchpotato/core/plugins/dashboard.py b/couchpotato/core/plugins/dashboard.py
index 57cd7af..fad68b0 100644
--- a/couchpotato/core/plugins/dashboard.py
+++ b/couchpotato/core/plugins/dashboard.py
@@ -45,7 +45,7 @@ class Dashboard(Plugin):
limit = tryInt(splt[0])
# 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 = []
now_year = date.today().year
diff --git a/couchpotato/core/plugins/file.py b/couchpotato/core/plugins/file.py
index 77b3ba8..b2533c0 100644
--- a/couchpotato/core/plugins/file.py
+++ b/couchpotato/core/plugins/file.py
@@ -4,7 +4,7 @@ import traceback
from couchpotato import get_db
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.variable import md5, getExt
from couchpotato.core.logger import CPLog
@@ -32,12 +32,11 @@ class FileManager(Plugin):
'return': {'type': 'file'}
})
- addEvent('app.load', self.cleanup)
+ fireEvent('schedule.interval', 'file.cleanup', self.cleanup, hours = 24)
def cleanup(self):
# Wait a bit after starting before cleanup
- time.sleep(2)
log.debug('Cleaning up unused files')
try:
diff --git a/couchpotato/core/plugins/manage.py b/couchpotato/core/plugins/manage.py
index e1e084f..623ce6f 100644
--- a/couchpotato/core/plugins/manage.py
+++ b/couchpotato/core/plugins/manage.py
@@ -8,7 +8,7 @@ from couchpotato import get_db
from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, addEvent, fireEventAsync
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.plugins.base import Plugin
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)
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')
else:
- db = get_db()
- releases = list(db.run('release', 'for_media', done_movie.get('_id')))
+ releases = done_movie.get('releases', [])
for release in releases:
if release.get('files'):
diff --git a/couchpotato/core/plugins/profile/main.py b/couchpotato/core/plugins/profile/main.py
index 8f838f4..5d15c11 100644
--- a/couchpotato/core/plugins/profile/main.py
+++ b/couchpotato/core/plugins/profile/main.py
@@ -2,7 +2,7 @@ import traceback
from couchpotato import get_db, tryInt
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.logger import CPLog
from couchpotato.core.plugins.base import Plugin
@@ -41,7 +41,7 @@ class ProfilePlugin(Plugin):
# Get all active movies without profile
try:
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()]
default_id = profile_ids[0]
diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py
index ee06d4c..e64b503 100644
--- a/couchpotato/core/plugins/quality/main.py
+++ b/couchpotato/core/plugins/quality/main.py
@@ -5,7 +5,7 @@ from couchpotato import get_db
from couchpotato.api import addApiView
from couchpotato.core.event import addEvent
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.plugins.base import Plugin
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)
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'])
self.cached_qualities = None
@@ -148,8 +148,8 @@ class QualityPlugin(Plugin):
'_t': 'quality',
'order': order,
'identifier': q.get('identifier'),
- 'size_min': q.get('size')[0],
- 'size_max': q.get('size')[1]
+ 'size_min': tryInt(q.get('size')[0]),
+ 'size_max': tryInt(q.get('size')[1]),
})
log.info('Creating profile: %s', q.get('label'))
diff --git a/couchpotato/core/plugins/release/index.py b/couchpotato/core/plugins/release/index.py
index ee76253..8265fe3 100644
--- a/couchpotato/core/plugins/release/index.py
+++ b/couchpotato/core/plugins/release/index.py
@@ -18,18 +18,6 @@ class ReleaseIndex(TreeBasedIndex):
if data.get('_t') == 'release' and data.get('media_id'):
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):
_version = 1
@@ -62,15 +50,15 @@ class ReleaseIDIndex(HashIndex):
class ReleaseDownloadIndex(HashIndex):
- _version = 1
+ _version = 2
def __init__(self, *args, **kwargs):
kwargs['key_format'] = '32s'
super(ReleaseDownloadIndex, self).__init__(*args, **kwargs)
def make_key(self, key):
- return md5(key).hexdigest()
+ return md5(key.lower()).hexdigest()
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']:
- 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
diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py
index 40475a4..a80dfc0 100644
--- a/couchpotato/core/plugins/release/main.py
+++ b/couchpotato/core/plugins/release/main.py
@@ -53,6 +53,8 @@ class Release(Plugin):
addEvent('release.delete', self.delete)
addEvent('release.clean', self.clean)
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
addEvent('app.load', self.cleanDone)
@@ -67,13 +69,13 @@ class Release(Plugin):
db = get_db()
# 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:
if media.get('last_edit', 0) > (now - week):
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
if rel['status'] in ['available']:
@@ -422,3 +424,20 @@ class Release(Plugin):
log.error('Failed: %s', traceback.format_exc())
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']
diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py
index 0f531bc..f3b22c9 100644
--- a/couchpotato/core/plugins/renamer.py
+++ b/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.helpers.encoding import toUnicode, ss, sp
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.plugins.base import Plugin
from couchpotato.environment import Env
@@ -79,16 +79,22 @@ class Renamer(Plugin):
downloader = kwargs.get('downloader')
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')
release_download = None
if not base_folder and 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)
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)
# 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
else:
new_media_folder = os.path.join(from_folder, os.path.basename(media_folder))
@@ -152,7 +158,7 @@ class Renamer(Plugin):
return
# 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]):
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
@@ -160,7 +166,7 @@ class Renamer(Plugin):
# Update release_download info to the from folder
log.debug('Release %s found in the \'from\' folder.', media_folder)
release_download['folder'] = new_media_folder
- release_download['files'] = '|'.join(new_files)
+ release_download['files'] = new_files
media_folder = new_media_folder
if media_folder:
@@ -182,11 +188,10 @@ class Renamer(Plugin):
log.info('Scanning media folder %s...', media_folder)
folder = os.path.dirname(media_folder)
- if release_download.get('files', ''):
- files = splitString(release_download['files'], '|')
-
+ release_files = release_download.get('files', [])
+ if release_files:
# 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
else:
# Get all files from the specified folder
@@ -446,7 +451,7 @@ class Renamer(Plugin):
log.error('Failed marking movie finished: %s', (traceback.format_exc()))
# 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
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):
# Tag download_files if they are known
- if release_download['files']:
- tag_files = splitString(release_download['files'], '|')
+ if release_download.get('files', []):
+ tag_files = release_download.get('files', [])
# Tag all files in release folder
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):
# Untag download_files if they are known
- if release_download['files']:
- tag_files = splitString(release_download['files'], '|')
+ if release_download.get('files'):
+ tag_files = release_download.get('files', [])
# Untag all files in release folder
else:
@@ -719,8 +724,8 @@ Remove it if you want it to be renamed (again, or at least let it try again)
ignore_files = []
# Find tag on download_files if they are known
- if release_download['files']:
- tag_files = splitString(release_download['files'], '|')
+ if release_download.get('files'):
+ tag_files = release_download.get('files', [])
# Find tag on all files in release folder
else:
@@ -834,7 +839,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
try:
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:
#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
break
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'])
found_release = True
break
@@ -1043,7 +1048,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
if rls:
media = db.get('id', rls['media_id'])
release_download.update({
- 'imdb_id': media['identifier'],
+ 'imdb_id': getIdentifier(media),
'quality': rls['quality'],
'protocol': rls.get('info', {}).get('protocol') or rls.get('info', {}).get('type'),
'release_id': rls['_id'],
diff --git a/couchpotato/core/plugins/scanner.py b/couchpotato/core/plugins/scanner.py
index 0066c36..65ae257 100644
--- a/couchpotato/core/plugins/scanner.py
+++ b/couchpotato/core/plugins/scanner.py
@@ -8,7 +8,7 @@ from couchpotato import get_db
from couchpotato.core.event import fireEvent, addEvent
from couchpotato.core.helpers.encoding import toUnicode, simplifyString, sp
from couchpotato.core.helpers.variable import getExt, getImdb, tryInt, \
- splitString
+ splitString, getIdentifier
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from enzyme.exceptions import NoParserError, ParseError
@@ -403,7 +403,7 @@ class Scanner(Plugin):
if not group['media']:
log.error('Unable to determine media: %s', group['identifiers'])
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
diff --git a/libs/rtorrent/__init__.py b/libs/rtorrent/__init__.py
index d70e6e1..a3f1607 100755
--- a/libs/rtorrent/__init__.py
+++ b/libs/rtorrent/__init__.py
@@ -89,13 +89,16 @@ class RTorrent:
def _get_conn(self):
"""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':
raise NotImplementedError()
+ secure = self.scheme == 'https'
+
return self.sp(
self.uri,
- transport=BasicAuthTransport(self.username, self.password),
+ transport=BasicAuthTransport(secure, self.username, self.password),
**self.sp_kwargs
)
diff --git a/libs/rtorrent/lib/xmlrpc/basic_auth.py b/libs/rtorrent/lib/xmlrpc/basic_auth.py
index 20c02d9..c5654a2 100644
--- a/libs/rtorrent/lib/xmlrpc/basic_auth.py
+++ b/libs/rtorrent/lib/xmlrpc/basic_auth.py
@@ -20,24 +20,46 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-from base64 import encodestring
-import string
+from base64 import b64encode
+import httplib
import xmlrpclib
class BasicAuthTransport(xmlrpclib.Transport):
- def __init__(self, username=None, password=None):
+ def __init__(self, secure=False, username=None, password=None):
xmlrpclib.Transport.__init__(self)
+ self.secure = secure
+
self.username = username
self.password = password
def send_auth(self, h):
- if self.username is not None and self.password is not None:
- h.putheader('AUTHORIZATION', "Basic %s" % string.replace(
- encodestring("%s:%s" % (self.username, self.password)),
- "\012", ""
- ))
+ if not self.username or not self.password:
+ return
+
+ 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):
# issue XML-RPC request