Merge branch 'master' into desktop
This commit is contained in:
commit
32163b3951
39 files changed
+722
-535
No files matched your search
@@ -621,6 +621,8 @@ class Database(object):
|
||||
|
||||
except OperationalError:
|
||||
log.error('Migrating from faulty database, probably a (too) old version: %s', traceback.format_exc())
|
||||
|
||||
rename_old = True
|
||||
except:
|
||||
log.error('Migration failed: %s', traceback.format_exc())
|
||||
|
||||
|
||||
@@ -27,6 +27,11 @@ class Deluge(DownloaderBase):
|
||||
def connect(self, reconnect = False):
|
||||
# Load host from config and split out port.
|
||||
host = cleanHost(self.conf('host'), protocol = False).split(':')
|
||||
|
||||
# Force host assignment
|
||||
if len(host) == 1:
|
||||
host.append(80)
|
||||
|
||||
if not isInt(host[1]):
|
||||
log.error('Config properties are not filled in correctly, port is missing.')
|
||||
return False
|
||||
|
||||
@@ -62,7 +62,7 @@ class CPLog(object):
|
||||
if isinstance(replace_tuple, tuple):
|
||||
msg = msg % tuple([ss(x) if not isinstance(x, (int, float)) else x for x in list(replace_tuple)])
|
||||
elif isinstance(replace_tuple, dict):
|
||||
msg = msg % dict((k, ss(v)) for k, v in replace_tuple.iteritems())
|
||||
msg = msg % dict((k, ss(v) if not isinstance(v, (int, float)) else v) for k, v in replace_tuple.iteritems())
|
||||
else:
|
||||
msg = msg % ss(replace_tuple)
|
||||
except Exception as e:
|
||||
|
||||
@@ -13,11 +13,11 @@ log = CPLog(__name__)
|
||||
class Base(TorrentProvider):
|
||||
|
||||
urls = {
|
||||
'test': 'http://www.bit-hdtv.com/',
|
||||
'login': 'http://www.bit-hdtv.com/takelogin.php',
|
||||
'login_check': 'http://www.bit-hdtv.com/messages.php',
|
||||
'detail': 'http://www.bit-hdtv.com/details.php?id=%s',
|
||||
'search': 'http://www.bit-hdtv.com/torrents.php?',
|
||||
'test': 'https://www.bit-hdtv.com/',
|
||||
'login': 'https://www.bit-hdtv.com/takelogin.php',
|
||||
'login_check': 'https://www.bit-hdtv.com/messages.php',
|
||||
'detail': 'https://www.bit-hdtv.com/details.php?id=%s',
|
||||
'search': 'https://www.bit-hdtv.com/torrents.php?',
|
||||
}
|
||||
|
||||
# Searches for movies only - BiT-HDTV's subcategory and resolution search filters appear to be broken
|
||||
@@ -93,7 +93,7 @@ config = [{
|
||||
'tab': 'searcher',
|
||||
'list': 'torrent_providers',
|
||||
'name': 'BiT-HDTV',
|
||||
'description': '<a href="http://bit-hdtv.com">BiT-HDTV</a>',
|
||||
'description': '<a href="https://bit-hdtv.com">BiT-HDTV</a>',
|
||||
'wizard': True,
|
||||
'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABMklEQVR4AZ3Qu0ojcQCF8W9MJcQbJNgEEQUbQVIqWgnaWfkIvoCgggixEAmIhRtY2GV3w7KwU61B0EYIxmiw0YCik84ipaCuc0nmP5dcjIUgOjqDvxf4OAdf9mnMLcUJyPyGSCP+YRdC+Kp8iagJKhuS+InYRhTGgDbeV2uEMand4ZRxizjXHQEimxhraAnUr73BNqQxMiNeV2SwcjTLEVtb4Zl10mXutvOWm2otw5Sxz6TGTbdd6ncuYvVLXAXrvM+ruyBpy1S3JLGDfUQ1O6jn5vTsrJXvqSt4UNfj6vxTRPxBHER5QeSirhLGk/5rWN+ffB1XZuxjnDy1q87m7TS+xOGA+Iv4gfkbaw+nOMXHDHnITGEk0VfRFnn4Po4vNYm6RGukmggR0L08+l+e4HMeASo/i6AJUjLgAAAAAElFTkSuQmCC',
|
||||
'options': [
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
import traceback
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from couchpotato.core.helpers.variable import tryInt
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
|
||||
import six
|
||||
|
||||
|
||||
log = CPLog(__name__)
|
||||
|
||||
|
||||
class Base(TorrentProvider):
|
||||
|
||||
urls = {
|
||||
'test': 'https://www.torrentleech.org/',
|
||||
'login': 'https://www.torrentleech.org/user/account/login/',
|
||||
'login_check': 'https://torrentleech.org/user/messages',
|
||||
'detail': 'https://www.torrentleech.org/torrent/%s',
|
||||
'search': 'https://www.torrentleech.org/torrents/browse/index/query/%s/categories/%d',
|
||||
'download': 'https://www.torrentleech.org%s',
|
||||
}
|
||||
|
||||
http_time_between_calls = 1 # Seconds
|
||||
cat_backup_id = None
|
||||
|
||||
def _searchOnTitle(self, title, media, quality, results):
|
||||
|
||||
url = self.urls['search'] % self.buildUrl(title, media, quality)
|
||||
|
||||
data = self.getHTMLData(url)
|
||||
|
||||
if data:
|
||||
html = BeautifulSoup(data)
|
||||
|
||||
try:
|
||||
result_table = html.find('table', attrs = {'id': 'torrenttable'})
|
||||
if not result_table:
|
||||
return
|
||||
|
||||
entries = result_table.find_all('tr')
|
||||
|
||||
for result in entries[1:]:
|
||||
|
||||
link = result.find('td', attrs = {'class': 'name'}).find('a')
|
||||
url = result.find('td', attrs = {'class': 'quickdownload'}).find('a')
|
||||
details = result.find('td', attrs = {'class': 'name'}).find('a')
|
||||
|
||||
results.append({
|
||||
'id': link['href'].replace('/torrent/', ''),
|
||||
'name': six.text_type(link.string),
|
||||
'url': self.urls['download'] % url['href'],
|
||||
'detail_url': self.urls['download'] % details['href'],
|
||||
'size': self.parseSize(result.find_all('td')[4].string),
|
||||
'seeders': tryInt(result.find('td', attrs = {'class': 'seeders'}).string),
|
||||
'leechers': tryInt(result.find('td', attrs = {'class': 'leechers'}).string),
|
||||
})
|
||||
|
||||
except:
|
||||
log.error('Failed to parsing %s: %s', (self.getName(), traceback.format_exc()))
|
||||
|
||||
def getLoginParams(self):
|
||||
return {
|
||||
'username': self.conf('username'),
|
||||
'password': self.conf('password'),
|
||||
'remember_me': 'on',
|
||||
'login': 'submit',
|
||||
}
|
||||
|
||||
def loginSuccess(self, output):
|
||||
return '/user/account/logout' in output.lower() or 'welcome back' in output.lower()
|
||||
|
||||
loginCheckSuccess = loginSuccess
|
||||
|
||||
|
||||
config = [{
|
||||
'name': 'torrentleech',
|
||||
'groups': [
|
||||
{
|
||||
'tab': 'searcher',
|
||||
'list': 'torrent_providers',
|
||||
'name': 'TorrentLeech',
|
||||
'description': '<a href="http://torrentleech.org">TorrentLeech</a>',
|
||||
'wizard': True,
|
||||
'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAACHUlEQVR4AZVSO48SYRSdGTCBEMKzILLAWiybkKAGMZRUUJEoDZX7B9zsbuQPYEEjNLTQkYgJDwsoSaxspEBsCITXjjNAIKi8AkzceXgmbHQ1NJ5iMufmO9/9zrmXlCSJ+B8o75J8Pp/NZj0eTzweBy0Wi4PBYD6f12o1r9ebTCZx+22HcrnMsuxms7m6urTZ7LPZDMVYLBZ8ZV3yo8aq9Pq0wzCMTqe77dDv9y8uLyAWBH6xWOyL0K/56fcb+rrPgPZ6PZfLRe1fsl6vCUmGKIqoqNXqdDr9Dbjps9znUV0uTqdTjuPkDoVCIfcuJ4gizjMMm8u9vW+1nr04czqdK56c37CbKY9j2+1WEARZ0Gq1RFHAz2q1qlQqXxoN69HRcDjUarW8ZD6QUigUOnY8uKYH8N1sNkul9yiGw+F6vS4Rxn8EsodEIqHRaOSnq9T7ajQazWQycEIR1AEBYDabSZJyHDucJyegwWBQr9ebTCaKvHd4cCQANUU9evwQ1Ofz4YvUKUI43GE8HouSiFiNRhOowWBIpVLyHITJkuW3PwgAEf3pgIwxF5r+OplMEsk3CPT5szCMnY7EwUdhwUh/CXiej0Qi3idPz89fdrpdbsfBzH7S3Q9K5pP4c0sAKpVKoVAQGO1ut+t0OoFAQHkH2Da/3/+but3uarWK0ZMQoNdyucRutdttmqZxMTzY7XaYxsrgtUjEZrNhkSwWyy/0NCatZumrNQAAAABJRU5ErkJggg==',
|
||||
'options': [
|
||||
{
|
||||
'name': 'enabled',
|
||||
'type': 'enabler',
|
||||
'default': False,
|
||||
},
|
||||
{
|
||||
'name': 'username',
|
||||
'default': '',
|
||||
},
|
||||
{
|
||||
'name': 'password',
|
||||
'default': '',
|
||||
'type': 'password',
|
||||
},
|
||||
{
|
||||
'name': 'seed_ratio',
|
||||
'label': 'Seed ratio',
|
||||
'type': 'float',
|
||||
'default': 1,
|
||||
'description': 'Will not be (re)moved until this seed ratio is met.',
|
||||
},
|
||||
{
|
||||
'name': 'seed_time',
|
||||
'label': 'Seed time',
|
||||
'type': 'int',
|
||||
'default': 40,
|
||||
'description': 'Will not be (re)moved until this seed time (in hours) is met.',
|
||||
},
|
||||
{
|
||||
'name': 'extra_score',
|
||||
'advanced': True,
|
||||
'label': 'Extra Score',
|
||||
'type': 'int',
|
||||
'default': 20,
|
||||
'description': 'Starting score for each release found via this provider.',
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
}]
|
||||
@@ -264,3 +264,11 @@
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
@media all and (max-width: 480px) {
|
||||
.toggle_menu h2 {
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ from couchpotato import tryInt
|
||||
from couchpotato.core.event import addEvent
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.media.movie.providers.base import MovieProvider
|
||||
from requests import HTTPError
|
||||
|
||||
|
||||
log = CPLog(__name__)
|
||||
@@ -32,12 +33,14 @@ class FanartTV(MovieProvider):
|
||||
|
||||
try:
|
||||
url = self.urls['api'] % identifier
|
||||
fanart_data = self.getJsonData(url)
|
||||
fanart_data = self.getJsonData(url, show_error = False)
|
||||
|
||||
if fanart_data:
|
||||
log.debug('Found images for %s', fanart_data.get('name'))
|
||||
images = self._parseMovie(fanart_data)
|
||||
|
||||
except HTTPError as e:
|
||||
log.debug('Failed getting extra art for %s: %s',
|
||||
(identifier, e))
|
||||
except:
|
||||
log.error('Failed getting extra art for %s: %s',
|
||||
(identifier, traceback.format_exc()))
|
||||
|
||||
@@ -59,7 +59,8 @@ class TheMovieDb(MovieProvider):
|
||||
|
||||
for movie in raw:
|
||||
parsed_movie = self.parseMovie(movie, extended = False)
|
||||
results.append(parsed_movie)
|
||||
if parsed_movie:
|
||||
results.append(parsed_movie)
|
||||
|
||||
nr += 1
|
||||
if nr == limit:
|
||||
@@ -83,7 +84,7 @@ class TheMovieDb(MovieProvider):
|
||||
'id': identifier
|
||||
}, extended = extended)
|
||||
|
||||
return result
|
||||
return result or {}
|
||||
|
||||
def parseMovie(self, movie, extended = True):
|
||||
|
||||
@@ -91,6 +92,8 @@ class TheMovieDb(MovieProvider):
|
||||
movie = self.request('movie/%s' % movie.get('id'), {
|
||||
'append_to_response': 'alternative_titles' + (',images,casts' if extended else '')
|
||||
})
|
||||
if not movie:
|
||||
return
|
||||
|
||||
# Images
|
||||
poster = self.getImage(movie, type = 'poster', size = 'w154')
|
||||
@@ -192,8 +195,12 @@ class TheMovieDb(MovieProvider):
|
||||
params = dict((k, v) for k, v in params.items() if v)
|
||||
params = tryUrlencode(params)
|
||||
|
||||
url = 'http://api.themoviedb.org/3/%s?api_key=%s%s' % (call, self.conf('api_key'), '&%s' % params if params else '')
|
||||
data = self.getJsonData(url)
|
||||
try:
|
||||
url = 'http://api.themoviedb.org/3/%s?api_key=%s%s' % (call, self.conf('api_key'), '&%s' % params if params else '')
|
||||
data = self.getJsonData(url, show_error = False)
|
||||
except:
|
||||
log.debug('Movie not found: %s, %s', (call, params))
|
||||
data = None
|
||||
|
||||
if data and return_key and return_key in data:
|
||||
data = data.get(return_key)
|
||||
|
||||
@@ -13,7 +13,7 @@ class IPTorrents(MovieProvider, Base):
|
||||
([87], ['3d']),
|
||||
([48], ['720p', '1080p', 'bd50']),
|
||||
([72], ['cam', 'ts', 'tc', 'r5', 'scr']),
|
||||
([7,48], ['dvdrip', 'brrip']),
|
||||
([7, 48, 20], ['dvdrip', 'brrip']),
|
||||
([6], ['dvdr']),
|
||||
]
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
from couchpotato.core.helpers.encoding import tryUrlencode
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.media._base.providers.torrent.torrentleech import Base
|
||||
from couchpotato.core.media.movie.providers.base import MovieProvider
|
||||
|
||||
log = CPLog(__name__)
|
||||
|
||||
autoload = 'TorrentLeech'
|
||||
|
||||
|
||||
class TorrentLeech(MovieProvider, Base):
|
||||
|
||||
cat_ids = [
|
||||
([13], ['720p', '1080p', 'bd50']),
|
||||
([8], ['cam']),
|
||||
([9], ['ts', 'tc']),
|
||||
([10], ['r5', 'scr']),
|
||||
([11], ['dvdrip']),
|
||||
([14], ['brrip']),
|
||||
([12], ['dvdr']),
|
||||
]
|
||||
|
||||
def buildUrl(self, title, media, quality):
|
||||
return (
|
||||
tryUrlencode(title.replace(':', '')),
|
||||
self.getCatId(quality)[0]
|
||||
)
|
||||
@@ -203,13 +203,6 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
|
||||
quality['custom'] = quality_custom
|
||||
|
||||
results = fireEvent('searcher.search', search_protocols, movie, quality, single = True) or []
|
||||
results_count = len(results)
|
||||
total_result_count += results_count
|
||||
if results_count == 0:
|
||||
log.debug('Nothing found for %s in %s', (default_title, quality['label']))
|
||||
|
||||
# Keep track of releases found outside ETA window
|
||||
outside_eta_results += results_count if could_not_be_released else 0
|
||||
|
||||
# Check if movie isn't deleted while searching
|
||||
if not fireEvent('media.get', movie.get('_id'), single = True):
|
||||
@@ -217,11 +210,17 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
|
||||
|
||||
# Add them to this movie releases list
|
||||
found_releases += fireEvent('release.create_from_search', results, movie, quality, single = True)
|
||||
results_count = len(found_releases)
|
||||
total_result_count += results_count
|
||||
if results_count == 0:
|
||||
log.debug('Nothing found for %s in %s', (default_title, quality['label']))
|
||||
|
||||
# Keep track of releases found outside ETA window
|
||||
outside_eta_results += results_count if could_not_be_released else 0
|
||||
|
||||
# Don't trigger download, but notify user of available releases
|
||||
if could_not_be_released:
|
||||
if results_count > 0:
|
||||
log.debug('Found %s releases for "%s", but ETA isn\'t correct yet.', (results_count, default_title))
|
||||
if could_not_be_released and results_count > 0:
|
||||
log.debug('Found %s releases for "%s", but ETA isn\'t correct yet.', (results_count, default_title))
|
||||
|
||||
# Try find a valid result and download it
|
||||
if (force_download or not could_not_be_released or always_search) and fireEvent('release.try_download_result', results, movie, quality_custom, single = True):
|
||||
|
||||
@@ -441,7 +441,6 @@ class Release(Plugin):
|
||||
for rel in search_results:
|
||||
|
||||
rel_identifier = md5(rel['url'])
|
||||
found_releases.append(rel_identifier)
|
||||
|
||||
release = {
|
||||
'_t': 'release',
|
||||
@@ -482,6 +481,9 @@ class Release(Plugin):
|
||||
# Update release in search_results
|
||||
rel['status'] = rls.get('status')
|
||||
|
||||
if rel['status'] == 'available':
|
||||
found_releases.append(rel_identifier)
|
||||
|
||||
return found_releases
|
||||
except:
|
||||
log.error('Failed: %s', traceback.format_exc())
|
||||
|
||||
@@ -220,6 +220,10 @@ class Renamer(Plugin):
|
||||
nfo_name = self.conf('nfo_name')
|
||||
separator = self.conf('separator')
|
||||
|
||||
if len(file_name) == 0:
|
||||
log.error('Please fill in the filename option under renamer settings. Forcing it on <original>.<ext> to keep the same name as source file.')
|
||||
file_name = '<original>.<ext>'
|
||||
|
||||
cd_keys = ['<cd>','<cd_nr>', '<original>']
|
||||
if not any(x in folder_name for x in cd_keys) and not any(x in file_name for x in cd_keys):
|
||||
log.error('Missing `cd` or `cd_nr` in the renamer. This will cause multi-file releases of being renamed to the same file. '
|
||||
@@ -791,7 +795,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
|
||||
dest = sp(dest)
|
||||
try:
|
||||
|
||||
if os.path.exists(dest):
|
||||
if os.path.exists(dest) and os.path.isfile(dest):
|
||||
raise Exception('Destination "%s" already exists' % dest)
|
||||
|
||||
move_type = self.conf('file_action')
|
||||
|
||||
Reference in new issue
Block a user