Provider restructure

This commit is contained in:
Ruud
2014-03-11 18:45:50 +01:00
parent 28661ab11a
commit 471229216a
181 changed files with 1118 additions and 779 deletions

View File

@@ -24,9 +24,6 @@ class Loader(object):
'downloaders': (20, 'couchpotato.core.downloaders', os.path.join(core, 'downloaders')),
}
# Add providers to loader
self.addPath(root, ['couchpotato', 'core', 'providers'], 25, recursive = False)
# Add media to loader
self.addPath(root, ['couchpotato', 'core', 'media'], 25, recursive = True)
@@ -103,7 +100,7 @@ class Loader(object):
def loadSettings(self, module, name, save = True):
if not hasattr(module, 'config'):
log.debug('Skip loading settings for plugin %s as it has no config section' % module.__file__)
#log.debug('Skip loading settings for plugin %s as it has no config section' % module.__file__)
return False
try:

View File

@@ -1,21 +0,0 @@
config = [{
'name': 'automation_providers',
'groups': [
{
'label': 'Watchlists',
'description': 'Check watchlists for new movies',
'type': 'list',
'name': 'watchlist_providers',
'tab': 'automation',
'options': [],
},
{
'label': 'Automated',
'description': 'Uses minimal requirements',
'type': 'list',
'name': 'automation_providers',
'tab': 'automation',
'options': [],
},
],
}]

View File

@@ -1,96 +1,8 @@
from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.base import Provider
from couchpotato.environment import Env
from couchpotato.core.helpers.variable import splitString
import time
from couchpotato.core.media._base.providers.base import Provider
log = CPLog(__name__)
class Automation(Provider):
enabled_option = 'automation_enabled'
http_time_between_calls = 2
interval = 1800
last_checked = 0
def __init__(self):
addEvent('automation.get_movies', self._getMovies)
def _getMovies(self):
if self.isDisabled():
return
if not self.canCheck():
log.debug('Just checked, skipping %s', self.getName())
return []
self.last_checked = time.time()
return self.getIMDBids()
def search(self, name, year = None, imdb_only = False):
prop_name = 'automation.cached.%s.%s' % (name, year)
cached_imdb = Env.prop(prop_name, default = False)
if cached_imdb and imdb_only:
return cached_imdb
result = fireEvent('movie.search', q = '%s %s' % (name, year if year else ''), limit = 1, merge = True)
if len(result) > 0:
if imdb_only and result[0].get('imdb'):
Env.prop(prop_name, result[0].get('imdb'))
return result[0].get('imdb') if imdb_only else result[0]
else:
return None
def isMinimalMovie(self, movie):
if not movie.get('rating'):
log.info('ignoring %s as no rating is available for.', (movie['original_title']))
return False
if movie['rating'] and movie['rating'].get('imdb'):
movie['votes'] = movie['rating']['imdb'][1]
movie['rating'] = movie['rating']['imdb'][0]
for minimal_type in ['year', 'rating', 'votes']:
type_value = movie.get(minimal_type, 0)
type_min = self.getMinimal(minimal_type)
if type_value < type_min:
log.info('%s too low for %s, need %s has %s', (minimal_type, movie['original_title'], type_min, type_value))
return False
movie_genres = [genre.lower() for genre in movie['genres']]
required_genres = splitString(self.getMinimal('required_genres').lower())
ignored_genres = splitString(self.getMinimal('ignored_genres').lower())
req_match = 0
for req_set in required_genres:
req = splitString(req_set, '&')
req_match += len(list(set(movie_genres) & set(req))) == len(req)
if self.getMinimal('required_genres') and req_match == 0:
log.info2('Required genre(s) missing for %s', movie['original_title'])
return False
for ign_set in ignored_genres:
ign = splitString(ign_set, '&')
if len(list(set(movie_genres) & set(ign))) == len(ign):
log.info2('%s has blacklisted genre(s): %s', (movie['original_title'], ign))
return False
return True
def getMinimal(self, min_type):
return Env.setting(min_type, 'automation')
def getIMDBids(self):
return []
def canCheck(self):
return time.time() > self.last_checked + self.interval
class BaseAutomation(Provider):
pass

View File

@@ -14,7 +14,6 @@ import xml.etree.ElementTree as XMLTree
log = CPLog(__name__)
class MultiProvider(Plugin):
def __init__(self):
@@ -102,7 +101,6 @@ class Provider(Plugin):
class YarrProvider(Provider):
protocol = None # nzb, torrent, torrent_magnet
type = 'movie'
cat_ids = {}
cat_backup_id = None
@@ -180,7 +178,7 @@ class YarrProvider(Provider):
return 'try_next'
def search(self, movie, quality):
def search(self, media, quality):
if self.isDisabled():
return []
@@ -192,15 +190,17 @@ class YarrProvider(Provider):
# Create result container
imdb_results = hasattr(self, '_search')
results = ResultList(self, movie, quality, imdb_results = imdb_results)
results = ResultList(self, media, quality, imdb_results = imdb_results)
# Do search based on imdb id
if imdb_results:
self._search(movie, quality, results)
self._search(media, quality, results)
# Search possible titles
else:
for title in possibleTitles(getTitle(movie)):
self._searchOnTitle(title, movie, quality, results)
media_title = fireEvent('library.query', media['library'], single = True)
for title in possibleTitles(media_title):
self._searchOnTitle(title, media, quality, results)
return results
@@ -243,8 +243,7 @@ class YarrProvider(Provider):
def getCatId(self, identifier):
for cats in self.cat_ids:
ids, qualities = cats
for ids, qualities in self.cat_ids:
if identifier in qualities:
return ids

View File

@@ -1,5 +1,5 @@
from couchpotato.core.providers.base import Provider
from couchpotato.core.media._base.providers.base import Provider
class MovieProvider(Provider):
type = 'movie'
class BaseInfoProvider(Provider):
type = 'unknown'

View File

@@ -1,110 +1,8 @@
from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import sp
from couchpotato.core.helpers.variable import mergeDicts
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from couchpotato.environment import Env
import os
import shutil
import traceback
log = CPLog(__name__)
class MetaDataBase(Plugin):
enabled_option = 'meta_enabled'
def __init__(self):
addEvent('renamer.after', self.create)
def create(self, message = None, group = None):
if self.isDisabled(): return
if not group: group = {}
log.info('Creating %s metadata.', self.getName())
# Update library to get latest info
try:
group['media'] = fireEvent('movie.update_info', group['media'].get('_id'), identifier = group['media']['identifier'], extended = True, single = True)
except:
log.error('Failed to update movie, before creating metadata: %s', traceback.format_exc())
root_name = self.getRootName(group)
meta_name = os.path.basename(root_name)
root = os.path.dirname(root_name)
movie_info = group['media'].get('info')
for file_type in ['nfo', 'thumbnail', 'fanart']:
try:
# Get file path
name = getattr(self, 'get' + file_type.capitalize() + 'Name')(meta_name, root)
if name and (self.conf('meta_' + file_type) or self.conf('meta_' + file_type) is None):
# Get file content
content = getattr(self, 'get' + file_type.capitalize())(movie_info = movie_info, data = group)
if content:
log.debug('Creating %s file: %s', (file_type, name))
if os.path.isfile(content):
content = sp(content)
name = sp(name)
shutil.copy2(content, name)
shutil.copyfile(content, name)
# Try and copy stats seperately
try: shutil.copystat(content, name)
except: pass
else:
self.createFile(name, content)
group['renamed_files'].append(name)
try:
os.chmod(sp(name), Env.getPermission('file'))
except:
log.debug('Failed setting permissions for %s: %s', (name, traceback.format_exc()))
except:
log.error('Unable to create %s file: %s', (file_type, traceback.format_exc()))
def getRootName(self, data = None):
if not data: data = {}
return os.path.join(data['destination_dir'], data['filename'])
def getFanartName(self, name, root):
return
def getThumbnailName(self, name, root):
return
def getNfoName(self, name, root):
return
def getNfo(self, movie_info = None, data = None):
if not data: data = {}
if not movie_info: movie_info = {}
def getThumbnail(self, movie_info = None, data = None, wanted_file_type = 'poster_original'):
if not data: data = {}
if not movie_info: movie_info = {}
# See if it is in current files
files = data['media'].get('files')
if files.get('image_' + wanted_file_type):
if os.path.isfile(files['image_' + wanted_file_type][0]):
return files['image_' + wanted_file_type][0]
# Download using existing info
try:
images = movie_info['images'][wanted_file_type]
file_path = fireEvent('file.download', url = images[0], single = True)
return file_path
except:
pass
def getFanart(self, movie_info = None, data = None):
if not data: data = {}
if not movie_info: movie_info = {}
return self.getThumbnail(movie_info = movie_info, data = data, wanted_file_type = 'backdrop_original')
pass

View File

@@ -1,8 +0,0 @@
from couchpotato.core.providers.metadata.base import MetaDataBase
import os
class WindowsMediaCenter(MetaDataBase):
def getThumbnailName(self, name, root):
return os.path.join(root, 'folder.jpg')

View File

@@ -1,4 +1,4 @@
from couchpotato.core.providers.base import YarrProvider
from couchpotato.core.media._base.providers.base import YarrProvider
import time

View File

@@ -1,8 +1,3 @@
from .main import BinSearch
def start():
return BinSearch()
config = [{
'name': 'binsearch',

View File

@@ -1,16 +1,14 @@
from bs4 import BeautifulSoup
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.nzb.base import NZBProvider
from couchpotato.environment import Env
import re
import traceback
from couchpotato.core.media._base.providers.nzb.base import NZBProvider
log = CPLog(__name__)
class BinSearch(NZBProvider):
class Base(NZBProvider):
urls = {
'download': 'https://www.binsearch.info/fcgi/nzb.fcgi?q=%s',
@@ -18,23 +16,11 @@ class BinSearch(NZBProvider):
'search': 'https://www.binsearch.info/index.php?%s',
}
http_time_between_calls = 4 # Seconds
http_time_between_calls = 4 # Seconds
def _search(self, movie, quality, results):
def _search(self, media, quality, results):
arguments = tryUrlencode({
'q': movie['identifier'],
'm': 'n',
'max': 400,
'adv_age': Env.setting('retention', 'nzb'),
'adv_sort': 'date',
'adv_col': 'on',
'adv_nfo': 'on',
'minsize': quality.get('size_min'),
'maxsize': quality.get('size_max'),
})
data = self.getHTMLData(self.urls['search'] % arguments)
data = self.getHTMLData(self.urls['search'] % self.buildUrl(media, quality))
if data:
try:
@@ -101,4 +87,3 @@ class BinSearch(NZBProvider):
log.error('Failed getting nzb from %s: %s', (self.getName(), traceback.format_exc()))
return 'try_next'

View File

@@ -1,8 +1,3 @@
from .main import Newznab
def start():
return Newznab()
config = [{
'name': 'newznab',

View File

@@ -2,8 +2,7 @@ from couchpotato.core.helpers.encoding import tryUrlencode, toUnicode
from couchpotato.core.helpers.rss import RSS
from couchpotato.core.helpers.variable import cleanHost, splitString, tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.base import ResultList
from couchpotato.core.providers.nzb.base import NZBProvider
from couchpotato.core.media._base.providers.nzb.base import NZBProvider
from couchpotato.environment import Env
from dateutil.parser import parse
from urllib2 import HTTPError
@@ -15,39 +14,35 @@ import urllib2
log = CPLog(__name__)
class Newznab(NZBProvider, RSS):
class Base(NZBProvider, RSS):
urls = {
'download': 'get&id=%s',
'detail': 'details&id=%s',
'search': 'movie',
'download': 't=get&id=%s'
}
limits_reached = {}
http_time_between_calls = 1 # Seconds
def search(self, movie, quality):
def search(self, media, quality):
hosts = self.getHosts()
results = ResultList(self, movie, quality, imdb_results = True)
results = ResultList(self, media, quality, imdb_results = True)
for host in hosts:
if self.isDisabled(host):
continue
self._searchOnHost(host, movie, quality, results)
self._searchOnHost(host, media, quality, results)
return results
def _searchOnHost(self, host, movie, quality, results):
def _searchOnHost(self, host, media, quality, results):
arguments = tryUrlencode({
'imdbid': movie['identifier'].replace('tt', ''),
'apikey': host['api_key'],
'extended': 1
}) + ('&%s' % host['custom_tag'] if host.get('custom_tag') else '')
url = '%s&%s' % (self.getUrl(host['host'], self.urls['search']), arguments)
query = self.buildUrl(media, host['api_key'])
url = '%s&%s' % (self.getUrl(host['host']), query)
nzbs = self.getRSSData(url, cache_timeout = 1800, headers = {'User-Agent': Env.getIdentifier()})
@@ -136,11 +131,11 @@ class Newznab(NZBProvider, RSS):
if result:
return result
def getUrl(self, host, type):
def getUrl(self, host):
if '?page=newznabapi' in host:
return cleanHost(host)[:-1] + '&t=' + type
return cleanHost(host)[:-1] + '&'
return cleanHost(host) + 'api?t=' + type
return cleanHost(host) + 'api?'
def isDisabled(self, host = None):
return not self.isEnabled(host)

View File

@@ -1,8 +1,3 @@
from .main import NZBClub
def start():
return NZBClub()
config = [{
'name': 'nzbclub',

View File

@@ -1,40 +1,26 @@
from bs4 import BeautifulSoup
from couchpotato.core.helpers.encoding import toUnicode, tryUrlencode
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.rss import RSS
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.nzb.base import NZBProvider
from couchpotato.core.media._base.providers.nzb.base import NZBProvider
from dateutil.parser import parse
import time
log = CPLog(__name__)
class NZBClub(NZBProvider, RSS):
class Base(NZBProvider, RSS):
urls = {
'search': 'https://www.nzbclub.com/nzbfeeds.aspx?%s',
}
http_time_between_calls = 4 #seconds
http_time_between_calls = 4 #seconds
def _searchOnTitle(self, title, movie, quality, results):
def _search(self, media, quality, results):
q = '"%s %s"' % (title, movie['info']['year'])
q_param = tryUrlencode({
'q': q,
})
params = tryUrlencode({
'ig': 1,
'rpp': 200,
'st': 5,
'sp': 1,
'ns': 1,
})
nzbs = self.getRSSData(self.urls['search'] % ('%s&%s' % (q_param, params)))
nzbs = self.getRSSData(self.urls['search'] % self.buildUrl(media))
for nzb in nzbs:

View File

@@ -1,8 +1,3 @@
from .main import NzbIndex
def start():
return NzbIndex()
config = [{
'name': 'nzbindex',

View File

@@ -1,10 +1,10 @@
from bs4 import BeautifulSoup
from couchpotato.core.helpers.encoding import toUnicode, tryUrlencode
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.rss import RSS
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.nzb.base import NZBProvider
from couchpotato.environment import Env
from couchpotato.core.event import fireEvent
from couchpotato.core.media._base.providers.nzb.base import NZBProvider
from dateutil.parser import parse
import re
import time
@@ -12,7 +12,7 @@ import time
log = CPLog(__name__)
class NzbIndex(NZBProvider, RSS):
class Base(NZBProvider, RSS):
urls = {
'download': 'https://www.nzbindex.com/download/',
@@ -21,28 +21,44 @@ class NzbIndex(NZBProvider, RSS):
http_time_between_calls = 1 # Seconds
def _searchOnTitle(self, title, movie, quality, results):
def _search(self, media, quality, results):
q = '"%s %s" | "%s (%s)"' % (title, movie['info']['year'], title, movie['info']['year'])
arguments = tryUrlencode({
'q': q,
'age': Env.setting('retention', 'nzb'),
'sort': 'agedesc',
'minsize': quality.get('size_min'),
'maxsize': quality.get('size_max'),
'rating': 1,
'max': 250,
'more': 1,
'complete': 1,
})
nzbs = self.getRSSData(self.urls['search'] % arguments)
nzbs = self.getRSSData(self.urls['search'] % self.buildUrl(media, quality))
for nzb in nzbs:
enclosure = self.getElement(nzb, 'enclosure').attrib
nzbindex_id = int(self.getTextElement(nzb, "link").split('/')[4])
title = self.getTextElement(nzb, "title")
match = fireEvent('matcher.parse', title, parser='usenet', single = True)
if not match.chains:
log.info('Unable to parse release with title "%s"', title)
continue
# TODO should we consider other lower-weight chains here?
info = fireEvent('matcher.flatten_info', match.chains[0].info, single = True)
release_name = fireEvent('matcher.construct_from_raw', info.get('release_name'), single = True)
file_name = info.get('detail', {}).get('file_name')
file_name = file_name[0] if file_name else None
title = release_name or file_name
# Strip extension from parsed title (if one exists)
ext_pos = title.rfind('.')
# Assume extension if smaller than 4 characters
# TODO this should probably be done a better way
if len(title[ext_pos + 1:]) <= 4:
title = title[:ext_pos]
if not title:
log.info('Unable to find release name from match')
continue
try:
description = self.getTextElement(nzb, "description")
except:
@@ -57,7 +73,7 @@ class NzbIndex(NZBProvider, RSS):
results.append({
'id': nzbindex_id,
'name': self.getTextElement(nzb, "title"),
'name': title,
'age': self.calculateAge(int(time.mktime(parse(self.getTextElement(nzb, "pubDate")).timetuple()))),
'size': tryInt(enclosure['length']) / 1024 / 1024,
'url': enclosure['url'],
@@ -76,4 +92,3 @@ class NzbIndex(NZBProvider, RSS):
item['description'] = toUnicode(html.find('pre', attrs = {'id':'nfo0'}).text)
except:
pass

View File

@@ -1,8 +1,3 @@
from .main import OMGWTFNZBs
def start():
return OMGWTFNZBs()
config = [{
'name': 'omgwtfnzbs',

View File

@@ -3,7 +3,7 @@ from couchpotato.core.helpers.encoding import toUnicode, tryUrlencode
from couchpotato.core.helpers.rss import RSS
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.nzb.base import NZBProvider
from couchpotato.core.media._base.providers.nzb.base import NZBProvider
from dateutil.parser import parse
from urlparse import urlparse, parse_qs
import time
@@ -11,7 +11,7 @@ import time
log = CPLog(__name__)
class OMGWTFNZBs(NZBProvider, RSS):
class Base(NZBProvider, RSS):
urls = {
'search': 'https://rss.omgwtfnzbs.org/rss-search.php?%s',

View File

@@ -1,8 +1,3 @@
from .main import AwesomeHD
def start():
return AwesomeHD()
config = [{
'name': 'awesomehd',

View File

@@ -1,14 +1,14 @@
from bs4 import BeautifulSoup
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider
import re
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
log = CPLog(__name__)
class AwesomeHD(TorrentProvider):
class Base(TorrentProvider):
urls = {
'test': 'https://awesome-hd.net/',

View File

@@ -1,7 +1,6 @@
import traceback
from couchpotato.core.helpers.variable import getImdb, md5, cleanHost
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.base import YarrProvider
from couchpotato.core.media._base.providers.base import YarrProvider
from couchpotato.environment import Env
import time
@@ -15,6 +14,22 @@ class TorrentProvider(YarrProvider):
proxy_domain = None
proxy_list = []
def imdbMatch(self, url, imdbId):
if getImdb(url) == imdbId:
return True
if url[:4] == 'http':
try:
cache_key = md5(url)
data = self.getCache(cache_key, url)
except IOError:
log.error('Failed to open %s.', url)
return False
return getImdb(data) == imdbId
return False
def getDomain(self, url = ''):
forced_domain = self.conf('domain')

View File

@@ -1,8 +1,3 @@
from .main import BiTHDTV
def start():
return BiTHDTV()
config = [{
'name': 'bithdtv',

View File

@@ -1,14 +1,14 @@
from bs4 import BeautifulSoup
from couchpotato.core.helpers.encoding import tryUrlencode, toUnicode
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
log = CPLog(__name__)
class BiTHDTV(TorrentProvider):
class Base(TorrentProvider):
urls = {
'test': 'http://www.bit-hdtv.com/',
@@ -19,18 +19,13 @@ class BiTHDTV(TorrentProvider):
}
# Searches for movies only - BiT-HDTV's subcategory and resolution search filters appear to be broken
cat_id_movies = 7
http_time_between_calls = 1 #seconds
def _searchOnTitle(self, title, movie, quality, results):
def _search(self, media, quality, results):
arguments = tryUrlencode({
'search': '%s %s' % (title.replace(':', ''), movie['info']['year']),
'cat': self.cat_id_movies
})
query = self.buildUrl(media)
url = "%s&%s" % (self.urls['search'], arguments)
url = "%s&%s" % (self.urls['search'], query)
data = self.getHTMLData(url)

View File

@@ -1,8 +1,3 @@
from .main import Bitsoup
def start():
return Bitsoup()
config = [{
'name': 'bitsoup',

View File

@@ -2,13 +2,13 @@ from bs4 import BeautifulSoup
from couchpotato.core.helpers.encoding import simplifyString, tryUrlencode
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
log = CPLog(__name__)
class Bitsoup(TorrentProvider):
class Base(TorrentProvider):
urls = {
'test': 'https://www.bitsoup.me/',
@@ -28,6 +28,7 @@ class Bitsoup(TorrentProvider):
})
url = "%s&%s" % (self.urls['search'], arguments)
url = self.urls['search'] % self.buildUrl(media, quality)
data = self.getHTMLData(url)
if data:
@@ -84,4 +85,3 @@ class Bitsoup(TorrentProvider):
return 'logout.php' in output.lower()
loginCheckSuccess = loginSuccess

View File

@@ -1,8 +1,3 @@
from .main import HDBits
def start():
return HDBits()
config = [{
'name': 'hdbits',

View File

@@ -1,15 +1,15 @@
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider
import re
import json
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
log = CPLog(__name__)
class HDBits(TorrentProvider):
class Base(TorrentProvider):
urls = {
'test': 'https://hdbits.org/',

View File

@@ -1,8 +1,3 @@
from .main import ILoveTorrents
def start():
return ILoveTorrents()
config = [{
'name': 'ilovetorrents',

View File

@@ -2,14 +2,14 @@ from bs4 import BeautifulSoup
from couchpotato.core.helpers.encoding import toUnicode, tryUrlencode
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider
import re
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
log = CPLog(__name__)
class ILoveTorrents(TorrentProvider):
class Base(TorrentProvider):
urls = {
'download': 'https://www.ilovetorrents.me/%s',

View File

@@ -1,8 +1,3 @@
from .main import IPTorrents
def start():
return IPTorrents()
config = [{
'name': 'iptorrents',

View File

@@ -1,14 +1,15 @@
from bs4 import BeautifulSoup
from couchpotato.core.helpers.encoding import tryUrlencode, toSafeString
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
import six
log = CPLog(__name__)
class IPTorrents(TorrentProvider):
class Base(TorrentProvider):
urls = {
'test': 'https://www.iptorrents.com/',
@@ -18,26 +19,33 @@ class IPTorrents(TorrentProvider):
'search': 'https://www.iptorrents.com/torrents/?l%d=1%s&q=%s&qf=ti&p=%d',
}
cat_ids = [
([48], ['720p', '1080p', 'bd50']),
([72], ['cam', 'ts', 'tc', 'r5', 'scr']),
([7], ['dvdrip', 'brrip']),
([6], ['dvdr']),
]
http_time_between_calls = 1 #seconds
cat_backup_id = None
def _searchOnTitle(self, title, movie, quality, results):
def buildUrl(self, title, media, quality):
return self._buildUrl(title.replace(':', ''), quality['identifier'])
def _buildUrl(self, query, quality_identifier):
cat_ids = self.getCatId(quality_identifier)
if not cat_ids:
log.warning('Unable to find category ids for identifier "%s"', quality_identifier)
return None
return self.urls['search'] % ("&".join(("l%d=" % x) for x in cat_ids), tryUrlencode(query).replace('%', '%%'))
def _searchOnTitle(self, title, media, quality, results):
freeleech = '' if not self.conf('freeleech') else '&free=on'
base_url = self.buildUrl(title, media, quality)
if not base_url: return
pages = 1
current_page = 1
while current_page <= pages and not self.shuttingDown():
url = self.urls['search'] % (self.getCatId(quality['identifier'])[0], freeleech, tryUrlencode('%s %s' % (title.replace(':', ''), movie['info']['year'])), current_page)
data = self.getHTMLData(url)
data = self.getHTMLData(base_url % (freeleech, current_page))
if data:
html = BeautifulSoup(data)
@@ -57,27 +65,21 @@ class IPTorrents(TorrentProvider):
entries = result_table.find_all('tr')
columns = self.getColumns(entries)
if 'seeders' not in columns or 'leechers' not in columns:
log.warning('Unrecognized table format returned')
return
for result in entries[1:]:
cells = result.find_all('td')
if len(cells) <= 1:
torrent = result.find_all('td')
if len(torrent) <= 1:
break
torrent = cells[1].find('a')
torrent = torrent[1].find('a')
torrent_id = torrent['href'].replace('/details.php?id=', '')
torrent_name = unicode(torrent.string)
torrent_name = six.text_type(torrent.string)
torrent_download_url = self.urls['base_url'] + (result.find_all('td')[3].find('a'))['href'].replace(' ', '.')
torrent_details_url = self.urls['base_url'] + torrent['href']
torrent_size = self.parseSize(result.find_all('td')[5].string)
torrent_seeders = tryInt(cells[columns['seeders']].string)
torrent_leechers = tryInt(cells[columns['leechers']].string)
torrent_seeders = tryInt(result.find('td', attrs = {'class' : 'ac t_seeders'}).string)
torrent_leechers = tryInt(result.find('td', attrs = {'class' : 'ac t_leechers'}).string)
results.append({
'id': torrent_id,
@@ -95,20 +97,6 @@ class IPTorrents(TorrentProvider):
current_page += 1
def getColumns(self, entries):
result = {}
for x, col in enumerate(entries[0].find_all('th')):
name = col.text or col.find('img')['title']
key = toSafeString(name).strip().lower()
if not key:
continue
result[key] = x
return result
def getLoginParams(self):
return {
'username': self.conf('username'),

View File

@@ -1,8 +1,3 @@
from .main import KickAssTorrents
def start():
return KickAssTorrents()
config = [{
'name': 'kickasstorrents',

View File

@@ -1,14 +1,14 @@
from bs4 import BeautifulSoup
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentMagnetProvider
import re
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentMagnetProvider
log = CPLog(__name__)
class KickAssTorrents(TorrentMagnetProvider):
class Base(TorrentMagnetProvider):
urls = {
'detail': '%s/%s',
@@ -34,9 +34,9 @@ class KickAssTorrents(TorrentMagnetProvider):
'http://www.kickassproxy.info',
]
def _search(self, movie, quality, results):
def _search(self, media, quality, results):
data = self.getHTMLData(self.urls['search'] % (self.getDomain(), 'm', movie['identifier'].replace('tt', '')))
data = self.getHTMLData(self.urls['search'] % (self.getDomain(), 'm', media['identifier'].replace('tt', '')))
if data:

View File

@@ -1,8 +1,3 @@
from .main import PassThePopcorn
def start():
return PassThePopcorn()
config = [{
'name': 'passthepopcorn',

View File

@@ -1,7 +1,7 @@
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import getTitle, tryInt, mergeDicts
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
from dateutil.parser import parse
import htmlentitydefs
import json
@@ -13,56 +13,28 @@ import six
log = CPLog(__name__)
class PassThePopcorn(TorrentProvider):
class Base(TorrentProvider):
urls = {
'domain': 'https://tls.passthepopcorn.me',
'detail': 'https://tls.passthepopcorn.me/torrents.php?torrentid=%s',
'torrent': 'https://tls.passthepopcorn.me/torrents.php',
'login': 'https://tls.passthepopcorn.me/ajax.php?action=login',
'login_check': 'https://tls.passthepopcorn.me/ajax.php?action=login',
'search': 'https://tls.passthepopcorn.me/search/%s/0/7/%d'
'domain': 'https://tls.passthepopcorn.me',
'detail': 'https://tls.passthepopcorn.me/torrents.php?torrentid=%s',
'torrent': 'https://tls.passthepopcorn.me/torrents.php',
'login': 'https://tls.passthepopcorn.me/ajax.php?action=login',
'login_check': 'https://tls.passthepopcorn.me/ajax.php?action=login',
'search': 'https://tls.passthepopcorn.me/search/%s/0/7/%d'
}
http_time_between_calls = 2
quality_search_params = {
'bd50': {'media': 'Blu-ray', 'format': 'BD50'},
'1080p': {'resolution': '1080p'},
'720p': {'resolution': '720p'},
'brrip': {'media': 'Blu-ray'},
'dvdr': {'resolution': 'anysd'},
'dvdrip': {'media': 'DVD'},
'scr': {'media': 'DVD-Screener'},
'r5': {'media': 'R5'},
'tc': {'media': 'TC'},
'ts': {'media': 'TS'},
'cam': {'media': 'CAM'}
}
def _search(self, media, quality, results):
post_search_filters = {
'bd50': {'Codec': ['BD50']},
'1080p': {'Resolution': ['1080p']},
'720p': {'Resolution': ['720p']},
'brrip': {'Source': ['Blu-ray'], 'Quality': ['High Definition'], 'Container': ['!ISO']},
'dvdr': {'Codec': ['DVD5', 'DVD9']},
'dvdrip': {'Source': ['DVD'], 'Codec': ['!DVD5', '!DVD9']},
'scr': {'Source': ['DVD-Screener']},
'r5': {'Source': ['R5']},
'tc': {'Source': ['TC']},
'ts': {'Source': ['TS']},
'cam': {'Source': ['CAM']}
}
def _search(self, movie, quality, results):
movie_title = getTitle(movie)
movie_title = getTitle(media)
quality_id = quality['identifier']
params = mergeDicts(self.quality_search_params[quality_id].copy(), {
'order_by': 'relevance',
'order_way': 'descending',
'searchstr': movie['identifier']
'searchstr': media['identifier']
})
url = '%s?json=noredirect&%s' % (self.urls['torrent'], tryUrlencode(params))

View File

@@ -1,8 +1,3 @@
from .main import PublicHD
def start():
return PublicHD()
config = [{
'name': 'publichd',

View File

@@ -2,15 +2,16 @@ from bs4 import BeautifulSoup
from couchpotato.core.helpers.encoding import tryUrlencode, toUnicode
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentMagnetProvider
from urlparse import parse_qs
import re
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentMagnetProvider
import six
log = CPLog(__name__)
class PublicHD(TorrentMagnetProvider):
class Base(TorrentMagnetProvider):
urls = {
'test': 'https://publichd.se',
@@ -24,13 +25,15 @@ class PublicHD(TorrentMagnetProvider):
if not quality.get('hd', False):
return []
return super(PublicHD, self).search(movie, quality)
return super(Base, self).search(movie, quality)
def _searchOnTitle(self, title, movie, quality, results):
def _search(self, media, quality, results):
query = self.buildUrl(media)
params = tryUrlencode({
'page':'torrents',
'search': '%s %s' % (title, movie['info']['year']),
'search': query,
'active': 1,
})
@@ -54,7 +57,7 @@ class PublicHD(TorrentMagnetProvider):
results.append({
'id': url['id'][0],
'name': unicode(info_url.string),
'name': six.text_type(info_url.string),
'url': download['href'],
'detail_url': self.urls['detail'] % url['id'][0],
'size': self.parseSize(result.find_all('td')[7].string),

View File

@@ -1,8 +1,3 @@
from .main import SceneAccess
def start():
return SceneAccess()
config = [{
'name': 'sceneaccess',

View File

@@ -1,14 +1,14 @@
from bs4 import BeautifulSoup
from couchpotato.core.helpers.encoding import tryUrlencode, toUnicode
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
log = CPLog(__name__)
class SceneAccess(TorrentProvider):
class Base(TorrentProvider):
urls = {
'test': 'https://www.sceneaccess.eu/',
@@ -16,35 +16,15 @@ class SceneAccess(TorrentProvider):
'login_check': 'https://www.sceneaccess.eu/inbox',
'detail': 'https://www.sceneaccess.eu/details?id=%s',
'search': 'https://www.sceneaccess.eu/browse?c%d=%d',
'archive': 'https://www.sceneaccess.eu/archive?&c%d=%d',
'download': 'https://www.sceneaccess.eu/%s',
}
cat_ids = [
([22], ['720p', '1080p']),
([7], ['cam', 'ts', 'dvdrip', 'tc', 'r5', 'scr', 'brrip']),
([8], ['dvdr']),
]
http_time_between_calls = 1 #seconds
def _search(self, movie, quality, results):
cat = self.getCatId(quality['identifier'])
if not cat:
return
url = self.urls['search'] % (
cat[0],
cat[0]
)
arguments = tryUrlencode({
'search': movie['identifier'],
'method': 3,
})
url = "%s&%s" % (url, arguments)
http_time_between_calls = 1 #seconds
def _search(self, media, quality, results):
url = self.buildUrl(media, quality)
data = self.getHTMLData(url)
if data:
@@ -77,13 +57,6 @@ class SceneAccess(TorrentProvider):
except:
log.error('Failed getting results from %s: %s', (self.getName(), traceback.format_exc()))
def getLoginParams(self):
return {
'username': self.conf('username'),
'password': self.conf('password'),
'submit': 'come on in',
}
def getMoreInfo(self, item):
full_description = self.getCache('sceneaccess.%s' % item['id'], item['detail_url'], cache_timeout = 25920000)
html = BeautifulSoup(full_description)
@@ -93,6 +66,14 @@ class SceneAccess(TorrentProvider):
item['description'] = description
return item
# Login
def getLoginParams(self):
return {
'username': self.conf('username'),
'password': self.conf('password'),
'submit': 'come on in',
}
def loginSuccess(self, output):
return '/inbox' in output.lower()

View File

@@ -1,8 +1,3 @@
from .main import ThePirateBay
def start():
return ThePirateBay()
config = [{
'name': 'thepiratebay',

View File

@@ -1,29 +1,22 @@
from bs4 import BeautifulSoup
from couchpotato.core.helpers.encoding import toUnicode, tryUrlencode
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentMagnetProvider
import re
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentMagnetProvider
import six
log = CPLog(__name__)
class ThePirateBay(TorrentMagnetProvider):
class Base(TorrentMagnetProvider):
urls = {
'detail': '%s/torrent/%s',
'search': '%s/search/%s/%s/7/%s'
'detail': '%s/torrent/%s',
'search': '%s/search/%%s/%%s/7/%%s'
}
cat_ids = [
([207], ['720p', '1080p']),
([201], ['cam', 'ts', 'dvdrip', 'tc', 'r5', 'scr']),
([201, 207], ['brrip']),
([202], ['dvdr'])
]
cat_backup_id = 200
disable_provider = False
http_time_between_calls = 0
@@ -37,18 +30,21 @@ class ThePirateBay(TorrentMagnetProvider):
'http://nl.tpb.li',
'http://proxybay.eu',
'https://www.getpirate.com',
'http://piratebay.io',
'http://piratebay.io',
]
def _searchOnTitle(self, title, movie, quality, results):
def _search(self, media, quality, results):
page = 0
total_pages = 1
cats = self.getCatId(quality['identifier'])
search_url = self.urls['search'] % self.getDomain()
while page < total_pages:
search_url = self.urls['search'] % (self.getDomain(), tryUrlencode('"%s" %s' % (title, movie['info']['year'])), page, ','.join(str(x) for x in cats))
search_url = search_url % self.buildUrl(media, page, cats)
page += 1
data = self.getHTMLData(search_url)
@@ -88,7 +84,7 @@ class ThePirateBay(TorrentMagnetProvider):
results.append({
'id': re.search('/(?P<id>\d+)/', link['href']).group('id'),
'name': unicode(link.string),
'name': six.text_type(link.string),
'url': download['href'],
'detail_url': self.getDomain(link['href']),
'size': self.parseSize(size),
@@ -102,7 +98,7 @@ class ThePirateBay(TorrentMagnetProvider):
log.error('Failed getting results from %s: %s', (self.getName(), traceback.format_exc()))
def isEnabled(self):
return super(ThePirateBay, self).isEnabled() and self.getDomain()
return super(Base, self).isEnabled() and self.getDomain()
def correctProxy(self, data):
return 'title="Pirate Search"' in data
@@ -110,7 +106,7 @@ class ThePirateBay(TorrentMagnetProvider):
def getMoreInfo(self, item):
full_description = self.getCache('tpb.%s' % item['id'], item['detail_url'], cache_timeout = 25920000)
html = BeautifulSoup(full_description)
nfo_pre = html.find('div', attrs = {'class': 'nfo'})
nfo_pre = html.find('div', attrs = {'class':'nfo'})
description = toUnicode(nfo_pre.text) if nfo_pre else ''
item['description'] = description

View File

@@ -1,8 +1,3 @@
from .main import TorrentBytes
def start():
return TorrentBytes()
config = [{
'name': 'torrentbytes',

View File

@@ -2,13 +2,13 @@ from bs4 import BeautifulSoup
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
log = CPLog(__name__)
class TorrentBytes(TorrentProvider):
class Base(TorrentProvider):
urls = {
'test': 'https://www.torrentbytes.net/',

View File

@@ -1,8 +1,3 @@
from .main import TorrentDay
def start():
return TorrentDay()
config = [{
'name': 'torrentday',

View File

@@ -1,11 +1,11 @@
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
log = CPLog(__name__)
class TorrentDay(TorrentProvider):
class Base(TorrentProvider):
urls = {
'test': 'http://www.td.af/',
@@ -16,25 +16,18 @@ class TorrentDay(TorrentProvider):
'download': 'http://www.td.af/download.php/%s/%s',
}
cat_ids = [
([11], ['720p', '1080p']),
([1, 21, 25], ['cam', 'ts', 'dvdrip', 'tc', 'r5', 'scr', 'brrip']),
([3], ['dvdr']),
([5], ['bd50']),
]
http_time_between_calls = 1 #seconds
http_time_between_calls = 1 #seconds
def _search(self, media, quality, results):
def _searchOnTitle(self, title, movie, quality, results):
q = '"%s %s"' % (title, movie['info']['year'])
query = self.buildUrl(media)
data = {
'/browse.php?': None,
'cata': 'yes',
'jxt': 8,
'jxw': 'b',
'search': q,
'search': query,
}
data = self.getJsonData(self.urls['search'], data = data)

View File

@@ -1,8 +1,3 @@
from .main import TorrentLeech
def start():
return TorrentLeech()
config = [{
'name': 'torrentleech',

View File

@@ -1,15 +1,14 @@
from bs4 import BeautifulSoup
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
import six
log = CPLog(__name__)
class TorrentLeech(TorrentProvider):
class Base(TorrentProvider):
urls = {
'test': 'http://www.torrentleech.org/',
@@ -20,22 +19,13 @@ class TorrentLeech(TorrentProvider):
'download': 'http://www.torrentleech.org%s',
}
cat_ids = [
([13], ['720p', '1080p']),
([8], ['cam']),
([9], ['ts', 'tc']),
([10], ['r5', 'scr']),
([11], ['dvdrip']),
([14], ['brrip']),
([12], ['dvdr']),
]
http_time_between_calls = 1 #seconds
cat_backup_id = None
def _searchOnTitle(self, title, movie, quality, results):
def _search(self, media, quality, results):
url = self.urls['search'] % self.buildUrl(media, quality)
url = self.urls['search'] % (tryUrlencode('%s %s' % (title.replace(':', ''), movie['info']['year'])), self.getCatId(quality['identifier'])[0])
data = self.getHTMLData(url)
if data:
@@ -56,7 +46,7 @@ class TorrentLeech(TorrentProvider):
results.append({
'id': link['href'].replace('/torrent/', ''),
'name': unicode(link.string),
'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),

View File

@@ -1,8 +1,3 @@
from .main import TorrentPotato
def start():
return TorrentPotato()
config = [{
'name': 'torrentpotato',

View File

@@ -1,45 +1,37 @@
from couchpotato.core.helpers.encoding import tryUrlencode, toUnicode
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import splitString, tryInt, tryFloat
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.base import ResultList
from couchpotato.core.providers.torrent.base import TorrentProvider
from urlparse import urlparse
import re
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
log = CPLog(__name__)
class TorrentPotato(TorrentProvider):
class Base(TorrentProvider):
urls = {}
limits_reached = {}
http_time_between_calls = 1 # Seconds
def search(self, movie, quality):
def search(self, media, quality):
hosts = self.getHosts()
results = ResultList(self, movie, quality, imdb_results = True)
results = ResultList(self, media, quality, imdb_results = True)
for host in hosts:
if self.isDisabled(host):
continue
self._searchOnHost(host, movie, quality, results)
self._searchOnHost(host, media, quality, results)
return results
def _searchOnHost(self, host, movie, quality, results):
def _searchOnHost(self, host, media, quality, results):
arguments = tryUrlencode({
'user': host['name'],
'passkey': host['pass_key'],
'imdbid': movie['identifier']
})
url = '%s?%s' % (host['host'], arguments)
torrents = self.getJsonData(url, cache_timeout = 1800)
torrents = self.getJsonData(self.buildUrl(media, host), cache_timeout = 1800)
if torrents:
try:
@@ -110,7 +102,7 @@ class TorrentPotato(TorrentProvider):
hosts = self.getHosts()
for host in hosts:
result = super(TorrentPotato, self).belongsTo(url, host = host['host'], provider = provider)
result = super(Base, self).belongsTo(url, host = host['host'], provider = provider)
if result:
return result

View File

@@ -1,8 +1,3 @@
from .main import TorrentShack
def start():
return TorrentShack()
config = [{
'name': 'torrentshack',

View File

@@ -1,15 +1,14 @@
from bs4 import BeautifulSoup
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
import six
log = CPLog(__name__)
class TorrentShack(TorrentProvider):
class Base(TorrentProvider):
urls = {
'test': 'https://torrentshack.net/',
@@ -20,21 +19,11 @@ class TorrentShack(TorrentProvider):
'download': 'https://torrentshack.net/%s',
}
cat_ids = [
([970], ['bd50']),
([300], ['720p', '1080p']),
([350], ['dvdr']),
([400], ['brrip', 'dvdrip']),
]
http_time_between_calls = 1 #seconds
cat_backup_id = 400
def _searchOnTitle(self, title, movie, quality, results):
def _search(self, media, quality, results):
scene_only = '1' if self.conf('scene_only') else ''
url = self.urls['search'] % (tryUrlencode('%s %s' % (title.replace(':', ''), movie['info']['year'])), scene_only, self.getCatId(quality['identifier'])[0])
url = self.urls['search'] % self.buildUrl(media, quality)
data = self.getHTMLData(url)
if data:
@@ -77,3 +66,6 @@ class TorrentShack(TorrentProvider):
return 'logout.php' in output.lower()
loginCheckSuccess = loginSuccess
def getSceneOnly(self):
return '1' if self.conf('scene_only') else ''

View File

@@ -1,8 +1,3 @@
from .main import Yify
def start():
return Yify()
config = [{
'name': 'yify',

View File

@@ -1,12 +1,12 @@
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentMagnetProvider
import traceback
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
log = CPLog(__name__)
class Yify(TorrentMagnetProvider):
class Base(TorrentProvider):
urls = {
'test': '%s/api',

View File

@@ -1,6 +0,0 @@
from couchpotato.core.providers.userscript.base import UserscriptBase
class MoviesIO(UserscriptBase):
includes = ['*://movies.io/m/*']

View File

@@ -0,0 +1,21 @@
config = [{
'name': 'automation_providers',
'groups': [
{
'label': 'Watchlists',
'description': 'Check watchlists for new movies',
'type': 'list',
'name': 'watchlist_providers',
'tab': 'automation',
'options': [],
},
{
'label': 'Automated',
'description': 'Uses minimal requirements',
'type': 'list',
'name': 'automation_providers',
'tab': 'automation',
'options': [],
},
],
}]

View File

@@ -0,0 +1,96 @@
from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.automation.base import BaseAutomation
from couchpotato.environment import Env
from couchpotato.core.helpers.variable import splitString
import time
log = CPLog(__name__)
class Automation(BaseAutomation):
enabled_option = 'automation_enabled'
http_time_between_calls = 2
interval = 1800
last_checked = 0
def __init__(self):
addEvent('automation.get_movies', self._getMovies)
def _getMovies(self):
if self.isDisabled():
return
if not self.canCheck():
log.debug('Just checked, skipping %s', self.getName())
return []
self.last_checked = time.time()
return self.getIMDBids()
def search(self, name, year = None, imdb_only = False):
prop_name = 'automation.cached.%s.%s' % (name, year)
cached_imdb = Env.prop(prop_name, default = False)
if cached_imdb and imdb_only:
return cached_imdb
result = fireEvent('movie.search', q = '%s %s' % (name, year if year else ''), limit = 1, merge = True)
if len(result) > 0:
if imdb_only and result[0].get('imdb'):
Env.prop(prop_name, result[0].get('imdb'))
return result[0].get('imdb') if imdb_only else result[0]
else:
return None
def isMinimalMovie(self, movie):
if not movie.get('rating'):
log.info('ignoring %s as no rating is available for.', (movie['original_title']))
return False
if movie['rating'] and movie['rating'].get('imdb'):
movie['votes'] = movie['rating']['imdb'][1]
movie['rating'] = movie['rating']['imdb'][0]
for minimal_type in ['year', 'rating', 'votes']:
type_value = movie.get(minimal_type, 0)
type_min = self.getMinimal(minimal_type)
if type_value < type_min:
log.info('%s too low for %s, need %s has %s', (minimal_type, movie['original_title'], type_min, type_value))
return False
movie_genres = [genre.lower() for genre in movie['genres']]
required_genres = splitString(self.getMinimal('required_genres').lower())
ignored_genres = splitString(self.getMinimal('ignored_genres').lower())
req_match = 0
for req_set in required_genres:
req = splitString(req_set, '&')
req_match += len(list(set(movie_genres) & set(req))) == len(req)
if self.getMinimal('required_genres') and req_match == 0:
log.info2('Required genre(s) missing for %s', movie['original_title'])
return False
for ign_set in ignored_genres:
ign = splitString(ign_set, '&')
if len(list(set(movie_genres) & set(ign))) == len(ign):
log.info2('%s has blacklisted genre(s): %s', (movie['original_title'], ign))
return False
return True
def getMinimal(self, min_type):
return Env.setting(min_type, 'automation')
def getIMDBids(self):
return []
def canCheck(self):
return time.time() > self.last_checked + self.interval

View File

@@ -2,7 +2,7 @@ from bs4 import BeautifulSoup
from couchpotato.core.helpers.rss import RSS
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.automation.base import Automation
from couchpotato.core.media.movie.providers.automation.base import Automation
log = CPLog(__name__)

View File

@@ -1,6 +1,6 @@
from couchpotato.core.helpers.variable import tryInt, splitString
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.automation.base import Automation
from couchpotato.core.media.movie.providers.automation.base import Automation
log = CPLog(__name__)

View File

@@ -1,6 +1,6 @@
from bs4 import BeautifulSoup
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.automation.base import Automation
from couchpotato.core.media.movie.providers.automation.base import Automation
log = CPLog(__name__)

View File

@@ -7,9 +7,8 @@ from couchpotato.core.helpers.rss import RSS
from couchpotato.core.helpers.variable import getImdb, splitString, tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.automation.base import Automation
from couchpotato.core.providers.base import MultiProvider
from couchpotato.core.media._base.providers.base import MultiProvider
from couchpotato.core.media.movie.providers.automation.base import Automation
log = CPLog(__name__)

View File

@@ -1,7 +1,7 @@
from couchpotato.core.helpers.rss import RSS
from couchpotato.core.helpers.variable import md5, splitString, tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.automation.base import Automation
from couchpotato.core.media.movie.providers.automation.base import Automation
from xml.etree.ElementTree import QName
import datetime
import traceback

View File

@@ -1,6 +1,6 @@
from couchpotato.core.helpers.rss import RSS
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.automation.base import Automation
from couchpotato.core.media.movie.providers.automation.base import Automation
import datetime
log = CPLog(__name__)

View File

@@ -1,7 +1,7 @@
from bs4 import BeautifulSoup
from couchpotato.core.helpers.variable import tryInt, splitString, removeEmpty
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.automation.base import Automation
from couchpotato.core.media.movie.providers.automation.base import Automation
import re
log = CPLog(__name__)

View File

@@ -1,7 +1,7 @@
from couchpotato.core.event import fireEvent
from couchpotato.core.helpers.rss import RSS
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.automation.base import Automation
from couchpotato.core.media.movie.providers.automation.base import Automation
log = CPLog(__name__)

View File

@@ -2,7 +2,7 @@ from couchpotato.core.event import fireEvent
from couchpotato.core.helpers.rss import RSS
from couchpotato.core.helpers.variable import tryInt, splitString
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.automation.base import Automation
from couchpotato.core.media.movie.providers.automation.base import Automation
log = CPLog(__name__)

View File

@@ -1,7 +1,7 @@
from couchpotato.core.helpers.rss import RSS
from couchpotato.core.helpers.variable import tryInt, splitString
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.automation.base import Automation
from couchpotato.core.media.movie.providers.automation.base import Automation
from xml.etree.ElementTree import QName
import datetime
import re

View File

@@ -1,7 +1,7 @@
from couchpotato.core.event import addEvent
from couchpotato.core.helpers.variable import sha1
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.automation.base import Automation
from couchpotato.core.media.movie.providers.automation.base import Automation
import base64
log = CPLog(__name__)

View File

@@ -0,0 +1,5 @@
from couchpotato.core.media._base.providers.info.base import BaseInfoProvider
class MovieProvider(BaseInfoProvider):
type = 'movie'

View File

@@ -1,7 +1,7 @@
from .main import MovieResultModifier
def start():
return MovieResultModifier()
config = []

View File

@@ -1,10 +1,12 @@
import base64
import time
from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.info.base import MovieProvider
from couchpotato.core.media.movie.providers.base import MovieProvider
from couchpotato.environment import Env
import base64
import time
log = CPLog(__name__)

View File

@@ -1,11 +1,13 @@
import json
import re
import traceback
from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import tryInt, tryFloat, splitString
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.info.base import MovieProvider
import json
import re
import traceback
from couchpotato.core.media.movie.providers.base import MovieProvider
log = CPLog(__name__)

View File

@@ -1,10 +1,12 @@
import traceback
from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import simplifyString, toUnicode, ss
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.info.base import MovieProvider
from couchpotato.core.media.movie.providers.base import MovieProvider
import tmdb3
import traceback
log = CPLog(__name__)

View File

@@ -0,0 +1,109 @@
from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import sp
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.metadata.base import MetaDataBase
from couchpotato.environment import Env
import os
import shutil
import traceback
log = CPLog(__name__)
class MovieMetaData(MetaDataBase):
enabled_option = 'meta_enabled'
def __init__(self):
addEvent('renamer.after', self.create)
def create(self, message = None, group = None):
if self.isDisabled(): return
if not group: group = {}
log.info('Creating %s metadata.', self.getName())
# Update library to get latest info
try:
group['media'] = fireEvent('movie.update_info', group['media'].get('_id'), identifier = group['media']['identifier'], extended = True, single = True)
except:
log.error('Failed to update movie, before creating metadata: %s', traceback.format_exc())
root_name = self.getRootName(group)
meta_name = os.path.basename(root_name)
root = os.path.dirname(root_name)
movie_info = group['media'].get('info')
for file_type in ['nfo', 'thumbnail', 'fanart']:
try:
# Get file path
name = getattr(self, 'get' + file_type.capitalize() + 'Name')(meta_name, root)
if name and (self.conf('meta_' + file_type) or self.conf('meta_' + file_type) is None):
# Get file content
content = getattr(self, 'get' + file_type.capitalize())(movie_info = movie_info, data = group)
if content:
log.debug('Creating %s file: %s', (file_type, name))
if os.path.isfile(content):
content = sp(content)
name = sp(name)
shutil.copy2(content, name)
shutil.copyfile(content, name)
# Try and copy stats seperately
try: shutil.copystat(content, name)
except: pass
else:
self.createFile(name, content)
group['renamed_files'].append(name)
try:
os.chmod(sp(name), Env.getPermission('file'))
except:
log.debug('Failed setting permissions for %s: %s', (name, traceback.format_exc()))
except:
log.error('Unable to create %s file: %s', (file_type, traceback.format_exc()))
def getRootName(self, data = None):
if not data: data = {}
return os.path.join(data['destination_dir'], data['filename'])
def getFanartName(self, name, root):
return
def getThumbnailName(self, name, root):
return
def getNfoName(self, name, root):
return
def getNfo(self, movie_info = None, data = None):
if not data: data = {}
if not movie_info: movie_info = {}
def getThumbnail(self, movie_info = None, data = None, wanted_file_type = 'poster_original'):
if not data: data = {}
if not movie_info: movie_info = {}
# See if it is in current files
files = data['media'].get('files')
if files.get('image_' + wanted_file_type):
if os.path.isfile(files['image_' + wanted_file_type][0]):
return files['image_' + wanted_file_type][0]
# Download using existing info
try:
images = movie_info['images'][wanted_file_type]
file_path = fireEvent('file.download', url = images[0], single = True)
return file_path
except:
pass
def getFanart(self, movie_info = None, data = None):
if not data: data = {}
if not movie_info: movie_info = {}
return self.getThumbnail(movie_info = movie_info, data = data, wanted_file_type = 'backdrop_original')

View File

@@ -0,0 +1,8 @@
from couchpotato.core.media.movie.providers.metadata.base import MovieMetaData
import os
class WindowsMediaCenter(MovieMetaData):
def getThumbnailName(self, name, root):
return os.path.join(root, 'folder.jpg')

View File

@@ -1,7 +1,7 @@
from couchpotato.core.media.movie.providers.metadata.base import MovieMetaData
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import getTitle
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.metadata.base import MetaDataBase
from xml.etree.ElementTree import Element, SubElement, tostring
import os
import re
@@ -10,7 +10,7 @@ import xml.dom.minidom
log = CPLog(__name__)
class XBMC(MetaDataBase):
class XBMC(MovieMetaData):
def getFanartName(self, name, root):
return self.createMetaName(self.conf('meta_fanart_name'), name, root)

View File

@@ -0,0 +1,14 @@
config = [{
'name': 'nzb_providers',
'groups': [
{
'label': 'Usenet Providers',
'description': 'Providers searching usenet for new releases',
'wizard': True,
'type': 'list',
'name': 'nzb_providers',
'tab': 'searcher',
'options': [],
},
],
}]

View File

@@ -0,0 +1,7 @@
from .main import BinSearch
def start():
return BinSearch()
config = []

View File

@@ -0,0 +1,24 @@
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.nzb.binsearch.main import Base
from couchpotato.core.media.movie.providers.base import MovieProvider
from couchpotato.environment import Env
log = CPLog(__name__)
class BinSearch(MovieProvider, Base):
def buildUrl(self, media, quality):
query = tryUrlencode({
'q': media['identifier'],
'm': 'n',
'max': 400,
'adv_age': Env.setting('retention', 'nzb'),
'adv_sort': 'date',
'adv_col': 'on',
'adv_nfo': 'on',
'minsize': quality.get('size_min'),
'maxsize': quality.get('size_max'),
})
return query

View File

@@ -0,0 +1,7 @@
from .main import Newznab
def start():
return Newznab()
config = []

Some files were not shown because too many files have changed in this diff Show More